123 lines
2.1 KiB
ArmAsm

.intel_syntax noprefix
#include <mem.h>
// Some info from here: http://os.phil-opp.com/multiboot-kernel.html
.section .text
.global _start
.code32 // GRUB leaves us in 32 bit mode
_start:
cli
// Check if long mode is available
// Otherwise, there's no point in continuing
call check_longmode
// Enable long mode through process described in
// AMD64 manual vol. 2 ch. 14
// Enable Physical Address Extension
mov eax, cr4
or eax, 1<<5
mov cr4, eax
// Load page directory into cr3
mov eax, offset V2P(BootP4)
mov cr3, eax
// Enable long mode
mov ecx, 0xC0000080
rdmsr
or eax, 1<<8
wrmsr
// Enable paging
mov eax, cr0
or eax, 1<<31
mov cr0, eax
// We are now in 32 bit long mode
// Go to 64 bit mode by loading a GDT
// and perforing a far jump
lgdt [V2P(BootGDTp)]
mov eax, 0x10
mov ss, eax
mov ds, eax
mov es, eax
.extern long_mode_start
jmp 0x8:V2P(long_mode_start)
.code64
long_mode_start:
// We are now in 64 bit long mode
// but we are still running code in the identity mapped low memory kernel mirror
// Next we jump to code in high memory (> 32 bits)
movabs rax, offset .upper_memory
jmp rax
.upper_memory:
// We are now in high memory
// Set up a stack and set up a fake return address to stop backtracing
movabs rsp, offset BootStack
push 0
mov rbp, rsp
// Remove identity mapping
mov rax, 0x0
mov [V2P(BootP4)], rax
// Call c kernel code
.extern kmain
call kmain
hlt
.code32
// Check if CPUID is available
// Method described in AMD64 manual vol. 3
check_cpuid:
pushfd
pushfd
xor dword ptr[esp], 0x00200000
popfd
pushfd
pop eax
xor eax, [esp]
popfd
and eax, 1<<21
jz error
ret
// Check if long mode is available using cpuid
// AMD manual vol. 3 Appendix E
check_longmode:
call check_cpuid
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb error
mov eax, 0x80000001
cpuid
test edx, 1<<29
jz error
ret
// Jump here if something went wrong
error:
// Print ERR! to screen
mov [0xb8000], dword ptr 0x4f524f45
mov [0xb8004], dword ptr 0x4f214f52
jmp .