aboutsummaryrefslogtreecommitdiff
path: root/src/boot.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/boot.S')
-rw-r--r--src/boot.S89
1 files changed, 81 insertions, 8 deletions
diff --git a/src/boot.S b/src/boot.S
index b17aea3..635b38f 100644
--- a/src/boot.S
+++ b/src/boot.S
@@ -36,17 +36,95 @@ stack_bottom:
.skip 16 * 1024
stack_top:
+.section .pages, "aw", @nobits
+.align 4096
+boot_page_directory:
+ .skip 4096
+boot_page_table1:
+ .skip 4096
+
+
/*
The linker script specifies _start as the entry point to the kernel and the
bootloader will jump to this position once the kernel has been loaded.
*/
.section .multiboot.text, "ax"
-.extern kernel_constructors
-.extern kernel_main
.global _start
.type _start, @function
_start:
- mov $stack_bottom, %ebp
+ # Physical address of boot_page_table1.
+ movl $(boot_page_table1 - 0xC0000000), %edi
+ # First address to map is address 0.
+ # TODO: Start at the first kernel page instead. Alternatively map the first
+ # 1 MiB as it can be generally useful, and there's no need to
+ # specially map the VGA buffer.
+ movl $0, %esi
+ # Map 1023 pages. The 1024th will be the VGA text buffer.
+ movl $1023, %ecx
+
+1:
+ # Only map the kernel.
+ cmpl $_kernel_start, %esi
+ jl 2f
+ cmpl $(_kernel_end - 0xC0000000), %esi
+ jge 3f
+
+ # Map physical address as "present, writable". Note that this maps
+ # .text and .rodata as writable. Mind security and map them as non-writable.
+ movl %esi, %edx
+ orl $0x003, %edx
+ movl %edx, (%edi)
+
+2:
+ # Size of page is 4096 bytes.
+ addl $4096, %esi
+ # Size of entries in boot_page_table1 is 4 bytes.
+ addl $4, %edi
+ # Loop to the next entry if we haven't finished.
+ loop 1b
+
+3:
+ # Map VGA video memory to 0xC03FF000 as "present, writable".
+ movl $(0x000B8000 | 0x003), boot_page_table1 - 0xC0000000 + 1023 * 4
+
+ # The page table is used at both page directory entry 0 (virtually from 0x0
+ # to 0x3FFFFF) (thus identity mapping the kernel) and page directory entry
+ # 768 (virtually from 0xC0000000 to 0xC03FFFFF) (thus mapping it in the
+ # higher half). The kernel is identity mapped because enabling paging does
+ # not change the next instruction, which continues to be physical. The CPU
+ # would instead page fault if there was no identity mapping.
+
+ # Map the page table to both virtual addresses 0x00000000 and 0xC0000000.
+ movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 0
+ movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 768 * 4
+
+ # Set cr3 to the address of the boot_page_directory.
+ movl $(boot_page_directory - 0xC0000000), %ecx
+ movl %ecx, %cr3
+
+ # Enable paging and the write-protect bit.
+ movl %cr0, %ecx
+ orl $0x80010000, %ecx
+ movl %ecx, %cr0
+
+ # Jump to higher half with an absolute jump.
+ lea (kinit), %ecx
+ jmp *%ecx
+
+.section .text
+.extern kernel_constructors
+.extern kernel_main
+kinit:
+ # At this point, paging is fully set up and enabled.
+
+ # Unmap the identity mapping as it is now unnecessary.
+ movl $0, boot_page_directory + 0
+
+ # Reload crc3 to force a TLB flush so the changes to take effect.
+ movl %cr3, %ecx
+ movl %ecx, %cr3
+
+ #mov $stack_bottom, %ebp
mov $stack_top, %esp # point the stack pointer to the stack
/*
@@ -90,8 +168,3 @@ _start:
hang: hlt
jmp hang
-/*
-Set the size of the _start symbol to the current location '.' minus its start.
-This is useful when debugging or when you implement call tracing.
-*/
-.size _start, . - _start