160 lines
3.1 KiB
ArmAsm

.intel_syntax noprefix
#include <mem.h>
#include <cpuid.h>
.section .data
// Some room to store the bootloader return values
MultiBootMagic:
.quad 0x0
MultiBootData:
.quad 0x0
// 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
// Save eax and ebx in memory
mov V2P(MultiBootMagic), eax
mov V2P(MultiBootData), ebx
// 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
// CPUID
#define CPUID(function) mov rax, (function); cpuid;
#define STORE(reg, variable) movabs r8, offset (variable); mov dword ptr [r8], (reg);
// Store max CPUID function numbers
CPUID(CPUID_FUNCTION_VENDOR)
STORE(eax, cpuid_max)
CPUID(CPUID_FUNCTIONX_VENDOR)
STORE(eax, cpuid_maxx)
// Store CPUID features
CPUID(CPUID_FUNCTION_FEATURES)
STORE(eax, cpuid_signature)
STORE(ebx, cpuid_features_b)
STORE(ecx, cpuid_features_c)
STORE(edx, cpuid_features_d)
// ...and extended features
CPUID(CPUID_FUNCTIONX_FEATURES)
STORE(ebx, cpuid_featuresx_b)
STORE(ecx, cpuid_featuresx_c)
STORE(edx, cpuid_featuresx_d)
// Get the saved bootloader data and pass to kmain
movabs rax, MultiBootMagic
mov rdi, rax
movabs rax, MultiBootData
mov rsi, 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 .