So I decided to move the kernel up to the 3GB mark (ala Windows and Linux) which will better allow me to layout memory later on when multitasking comes into play. The kernel is linked against a virtual address of
0xC0001000 (physical address of
0x00101000). When grub passes control over to us I create a .setup section which is mapped virtual = physical. This setup section initializes basic paging and maps the kernel into its correct virtual address. Grub sets up a Global Descriptor Table with a code and data segment of base
0x00000000 so segmentation does not effect the address translation from logical to linear.
If we
'>objdump-elf -h kernel.bin' to view the sections we get:
kernel.bin: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .setup 00001000 00100000 00100000 00001000 2**2
CONTENTS, ALLOC, LOAD, CODE
1 .kernel 00002000 c0001000 00101000 00002000 2**2
CONTENTS, ALLOC, LOAD, CODE
2 .data 00001000 c0003000 00103000 00004000 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .bss 00003000 c0004000 00104000 00005000 2**2
ALLOC
4 .comment 000000c8 c0007000 c0007000 00005000 2**2
CONTENTS
The code to setup paging and jump into the kernel is quite short and simple:
KERNEL_VMA equ 0xC0001000
PAGE_DIRCTORY equ 0x9C000
PAGE_TABLE_1 equ 0x9D000
PAGE_TABLE_2 equ 0x9E000
PRIV equ 3
_setup:
; store the pointer to the Grub multi boot header for later
push ebx
; create a page table that identity maps the first 4MB of mem
mov eax, PAGE_TABLE_1
mov ebx, 0x00000000 | PRIV
call map
; create a page table that will map the kernel into the 3GB mark
mov eax, PAGE_TABLE_2
mov ebx, 0x00100000 | PRIV
call map
; store the first page table into the page directory
mov dword [PAGE_DIRCTORY], PAGE_TABLE_1 | PRIV
; store the second page table into the page directory entry 768 (3GB mark)
mov dword [PAGE_DIRCTORY + 768*4], PAGE_TABLE_2 | PRIV
; enable paging
mov eax, PAGE_DIRCTORY
mov cr3, eax
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
; restore ebx with the pointer to the multi boot header
pop ebx
; jump into the kenel at it virtual memory address
jmp 0x08:KERNEL_VMA
map:
; loop 1024 times (number of entry's in a page table)
mov ecx, 1024
lmap:
; move next entry (ebx) into the page table (eax)
mov dword [eax], ebx
; move forward to next entry in table
add eax, 4
; move address forward by a page size
add ebx, 4096
; go again untill ecx == 0
loop lmap
ret