214 lines
4.6 KiB
ArmAsm
214 lines
4.6 KiB
ArmAsm
.set ALIGN, 1 << 0
|
|
.set MEMINFO, 1 << 1
|
|
.set VIDMODE, 1 << 2
|
|
.set FLAGS, ALIGN | MEMINFO
|
|
.set MAGIC, 0x1BADB002
|
|
.set CHECKSUM, -(MAGIC + FLAGS)
|
|
|
|
/* the amount of memory to allocate for bootstrap page directories. */
|
|
#define BOOTSTRAP_PDIR_SIZE 0x1000
|
|
|
|
.extern start_64 # defined in start_64.S
|
|
|
|
.code32
|
|
|
|
.section .boot.rodata, "a", @progbits
|
|
no_long_mode_err:
|
|
.asciz "This system is not 64-bit. Press any key to reboot."
|
|
|
|
unsupported_cpu_err:
|
|
.asciz "Your CPU is not supported by Magenta. Press any key to reboot."
|
|
|
|
.section .boot.bss, "aw", @nobits
|
|
bootstrap_pml4t: # a single PML4T
|
|
.skip 0x1000
|
|
bootstrap_pdpt: # a single PDPT
|
|
.skip 0x1000
|
|
bootstrap_pdir_buf: # a buffer of page directories. each pdir entry can be used to map 2MB of virtual memory.
|
|
.skip BOOTSTRAP_PDIR_SIZE
|
|
bootstrap_stack_bottom:
|
|
.skip 0x1000
|
|
bootstrap_stack_top:
|
|
|
|
.section .boot.text, "ax", @progbits
|
|
.align 4
|
|
.long MAGIC
|
|
.long FLAGS
|
|
.long CHECKSUM
|
|
|
|
# Print an error message and wait for RETURN if the system's CPU doesn't support long mode.
|
|
no_long_mode:
|
|
# print error message
|
|
mov $no_long_mode_err, %esi
|
|
|
|
mov $0xb8000, %edi
|
|
1:
|
|
movsb
|
|
movb $12, (%edi)
|
|
incl %edi
|
|
cmpb $0, (%esi)
|
|
jne 1b
|
|
|
|
2:
|
|
inb $0x64, %al
|
|
test $0x01, %al
|
|
jz 3f
|
|
inb $0x60, %al
|
|
jmp 2b
|
|
|
|
3:
|
|
inb $0x64, %al
|
|
test $0x01, %al
|
|
jz 3b
|
|
|
|
int $0xff
|
|
cli
|
|
hlt
|
|
|
|
# Print an error message and wait for RETURN if the system's CPU isn't supported.
|
|
unsupported_cpu:
|
|
# print error message
|
|
mov $unsupported_cpu_err, %esi
|
|
|
|
mov $0xb8000, %edi
|
|
1:
|
|
movsb
|
|
movb $12, (%edi)
|
|
incl %edi
|
|
cmpb $0, (%esi)
|
|
jne 1b
|
|
|
|
2:
|
|
inb $0x64, %al
|
|
test $0x01, %al
|
|
jz 3f
|
|
inb $0x60, %al
|
|
jmp 2b
|
|
|
|
3:
|
|
inb $0x64, %al
|
|
test $0x01, %al
|
|
jz 3b
|
|
|
|
int $0xff
|
|
cli
|
|
hlt
|
|
|
|
init_page_tables:
|
|
/* STEP 1: add an entry in the PML4T pointing to the PDPT.
|
|
NOTE that we actually add two entries in the PML4T that both point to the same PDPT.
|
|
This allows us to map the kernel at both vaddr 0x0 AND vaddr 0xffffffff80000000 using the same PDPT */
|
|
|
|
mov $bootstrap_pml4t, %edi
|
|
mov $bootstrap_pdpt, %esi
|
|
|
|
# in %ESI, build a PML4T entry containing the base address of the PDPT
|
|
xor $0xFFF, %esi
|
|
or $0x3, %esi
|
|
|
|
# add the PML4T entries at PML4T[0] and PML4T[511]
|
|
mov %esi, (%edi)
|
|
add $0xFF8, %edi
|
|
mov %esi, (%edi)
|
|
|
|
/* STEP 2: initialise the PDPT.
|
|
We need to create an entry in the PDPT for every page directory we intend to use. */
|
|
|
|
# BOOTSTRAP_PDIR_SIZE contains the total size of the page directory buffer.
|
|
# use it to calculate the number of page directories we're using.
|
|
mov $0, %edx
|
|
mov $BOOTSTRAP_PDIR_SIZE, %eax
|
|
mov $0x1000, %ebx
|
|
idiv %ebx
|
|
|
|
mov $bootstrap_pdpt, %edi
|
|
mov $bootstrap_pdir_buf, %esi
|
|
/* %ESI is a pointer into the pagedir buffer.
|
|
%EDI is a pointer into the PDPT.
|
|
%EAX is the total number of page directories.
|
|
%EBX is where we build the PDPT entry. */
|
|
1:
|
|
mov %esi, %ebx
|
|
xor $0xFFF, %ebx
|
|
or $0x3, %ebx
|
|
|
|
# skip the first 4 bytes of the 8-byte entry, leaving them zero.
|
|
add $0x4, %edi
|
|
mov %ebx, (%edi)
|
|
|
|
add $0x1000, %esi
|
|
add $0x4, %edi
|
|
sub $0x1, %eax
|
|
|
|
cmp $0x0, %eax
|
|
jne 1b
|
|
|
|
/* STEP 3: initialise the page directories.
|
|
Each page directory can be used to map 2MiB of virtual memory.
|
|
The exact number of page directories in use is determined by BOOTSTRAP_PDIR_SIZE */
|
|
|
|
/* the total number of page directory entries is stored in %EAX */
|
|
mov $0, %edx
|
|
mov $BOOTSTRAP_PDIR_SIZE, %eax
|
|
mov $0x8, %ebx
|
|
idiv %ebx
|
|
|
|
mov $0x0, %esi
|
|
mov $bootstrap_pdir_buf, %edi
|
|
/* %EDI is a pointer into the pagedir buffer.
|
|
%ESI is the physical address being mapped. must be a multiple of 2MiB.
|
|
%EAX is the total number of page directories.
|
|
%EBX is where we build the pagedir entry. */
|
|
|
|
2:
|
|
mov %esi, %ebx
|
|
xor $0xFFF, %ebx
|
|
or $0x3, %ebx
|
|
|
|
# skip the first 4 bytes of the 8-byte entry, leaving them zero.
|
|
add $0x4, %edi
|
|
mov %ebx, (%edi)
|
|
|
|
add $0x200000, %esi
|
|
add $0x4, %edi
|
|
dec %eax
|
|
jnz 2b
|
|
|
|
ret
|
|
|
|
long_mode_switch:
|
|
ret
|
|
|
|
.global _start
|
|
.type _start, @function
|
|
|
|
_start:
|
|
mov $bootstrap_stack_top, %esp
|
|
|
|
push %ebx # store the pointer to the multiboot info block.
|
|
|
|
# check if long mode is supported
|
|
movl $0x80000000, %eax # Extended-function 80000000h.
|
|
cpuid # Is largest extended function
|
|
cmpl $0x80000000, %eax # any function > 80000000h?
|
|
jbe no_long_mode # If not, no long mode.
|
|
movl $0x80000001, %eax # Extended-function 80000001h.
|
|
cpuid # Now EDX = extended-features flags.
|
|
btl $29, %edx # Test if long mode is supported.
|
|
jnc no_long_mode # Exit if not supported.
|
|
|
|
movl $1, %eax
|
|
cpuid
|
|
btl $3, %edx
|
|
|
|
mov $0xb8000, %eax
|
|
movb $76, (%eax)
|
|
inc %eax
|
|
movb $0xF, (%eax)
|
|
|
|
call init_page_tables
|
|
call long_mode_switch # calls start_64, does not return
|
|
|
|
cli
|
|
hlt
|