Created
June 13, 2018 05:07
-
-
Save nebrelbug/5a0042d4de32f942bb72e71fe282bdd2 to your computer and use it in GitHub Desktop.
The bootcode of my toy kernel following Phil-Opp's OS tutorials
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;Based on the tutorials by Phil Opperman | |
global start | |
extern long_mode_start | |
section .text | |
bits 32 | |
start: | |
mov esp, stack_top ;ESP is the stack pointer register, so (I think?) telling computer where stack is | |
mov edi, ebx ; Move Multiboot info pointer to edi | |
call check_multiboot | |
call check_cpuid | |
call check_long_mode | |
call setup_page_tables | |
call enable_paging | |
call get_vesa_info | |
; load the 64-bit GDT | |
lgdt [gdt64.pointer] | |
jmp gdt64.code:long_mode_start | |
hlt | |
setup_page_tables: | |
mov eax, p4_table | |
or eax, 0b11 ; present + writable | |
mov [p4_table + 511 * 8], eax | |
; map first P4 entry to P3 table | |
mov eax, p3_table | |
or eax, 0b11 ; present + writable | |
mov [p4_table], eax | |
; map first P3 entry to P2 table | |
mov eax, p2_table | |
or eax, 0b11 ; present + writable | |
mov [p3_table], eax | |
mov ecx, 0 | |
.map_p2_table: | |
; map ecx-th P2 entry to a huge page that starts at address 2MiB*ecx | |
mov eax, 0x200000 ; 2MiB | |
mul ecx ; start address of ecx-th page | |
or eax, 0b10000011 ; present + writable + huge | |
mov [p2_table + ecx * 8], eax ; map ecx-th entry | |
inc ecx ; increase counter | |
cmp ecx, 512 ; if counter == 512, the whole P2 table is mapped | |
jne .map_p2_table ; else map the next entry | |
ret | |
enable_paging: | |
; load P4 to cr3 register (cpu uses this to access the P4 table) | |
mov eax, p4_table | |
mov cr3, eax | |
; enable PAE-flag in cr4 (Physical Address Extension) | |
mov eax, cr4 | |
or eax, 1 << 5 | |
mov cr4, eax | |
; set the long mode bit in the EFER MSR (model specific register) | |
mov ecx, 0xC0000080 | |
rdmsr | |
or eax, 1 << 8 | |
wrmsr | |
; enable paging in the cr0 register | |
mov eax, cr0 | |
or eax, 1 << 31 | |
mov cr0, eax | |
ret | |
section .rodata | |
gdt64: | |
dq 0 ; zero entry | |
.code: equ $ - gdt64 ; new | |
dq (1<<43) | (1<<44) | (1<<47) | (1<<53) ; code segment | |
.pointer: | |
dw $ - gdt64 - 1 | |
dq gdt64 | |
; Prints `ERR: ` and the given error code to screen and hangs. | |
; parameter: error code (in ascii) in al | |
error: | |
mov dword [0xb8000], 0x4f524f45 | |
mov dword [0xb8004], 0x4f3a4f52 | |
mov dword [0xb8008], 0x4f204f20 | |
mov byte [0xb800a], al | |
hlt | |
; Throw error 0 if eax doesn't contain the Multiboot 2 magic value (0x36d76289). | |
check_multiboot: | |
cmp eax, 0x36d76289 | |
jne .no_multiboot | |
ret | |
.no_multiboot: | |
mov al, "0" | |
jmp error | |
; Throw error 1 if the CPU doesn't support the CPUID command. | |
check_cpuid: | |
pushfd ; Store the FLAGS-register. | |
pop eax ; Restore the A-register. | |
mov ecx, eax ; Set the C-register to the A-register. | |
xor eax, 1 << 21 ; Flip the ID-bit, which is bit 21. | |
push eax ; Store the A-register. | |
popfd ; Restore the FLAGS-register. | |
pushfd ; Store the FLAGS-register. | |
pop eax ; Restore the A-register. | |
push ecx ; Store the C-register. | |
popfd ; Restore the FLAGS-register. | |
xor eax, ecx ; Do a XOR-operation on the A-register and the C-register. | |
jz .no_cpuid ; The zero flag is set, no CPUID. | |
ret ; CPUID is available for use. | |
.no_cpuid: | |
mov al, "1" | |
jmp error | |
; Throw error 2 if the CPU doesn't support Long Mode. | |
check_long_mode: | |
mov eax, 0x80000000 ; Set the A-register to 0x80000000. | |
cpuid ; CPU identification. | |
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001. | |
jb .no_long_mode ; It is less, there is no long mode. | |
mov eax, 0x80000000 ; Set the A-register to 0x80000000. | |
cpuid ; CPU identification. | |
cmp eax, 0x80000001 ; Compare the A-register with 0x80000001. | |
jb .no_long_mode ; It is less, there is no long mode. | |
ret | |
.no_long_mode: | |
mov al, "2" | |
jmp error | |
; Hopefully VBE Stuff | |
get_vesa_info: | |
mov ax, 0x4f00 | |
mov [es:di], vbe_info_structure | |
int 0x10 | |
ret | |
section.data: | |
vbe_info_structure: | |
.signature db "VBE2" ; indicate support for VBE 2.0+ | |
.table_data: resb 512-4 ; reserve space for the table below | |
section .bss | |
align 4096 | |
p4_table: | |
resb 4096 | |
p3_table: | |
resb 4096 | |
p2_table: | |
resb 4096 | |
stack_bottom: | |
resb 4096*4 | |
stack_top: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment