[BOOT] Multiboot compliant kernel which runs 64 bit code
This commit is contained in:
122
kernel/boot/boot.S
Normal file
122
kernel/boot/boot.S
Normal file
@@ -0,0 +1,122 @@
|
||||
.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 .
|
||||
54
kernel/boot/boot_structures.S
Normal file
54
kernel/boot/boot_structures.S
Normal file
@@ -0,0 +1,54 @@
|
||||
.intel_syntax noprefix
|
||||
#include <mem.h>
|
||||
#include <gdt.h>
|
||||
|
||||
|
||||
// Hardcode the initial page mapping
|
||||
// Identity map the first GiB of memory
|
||||
// Also map the same memory at KERNEL_OFFSET
|
||||
.section .data
|
||||
.align 0x1000
|
||||
.global BootP4
|
||||
BootP4:
|
||||
.quad V2P(BootP3) + (PAGE_PRESENT | PAGE_WRITE)
|
||||
.rept P4_OFFSET(KERNEL_OFFSET)-1
|
||||
.quad 0x0
|
||||
.endr
|
||||
.quad V2P(BootP3) + (PAGE_PRESENT | PAGE_WRITE)
|
||||
.rept 510 - P4_OFFSET(KERNEL_OFFSET) + 1
|
||||
.quad 0x0
|
||||
.endr
|
||||
BootP3:
|
||||
.quad V2P(BootP2) + (PAGE_PRESENT | PAGE_WRITE)
|
||||
.rept 511
|
||||
.quad 0x0
|
||||
.endr
|
||||
BootP2:
|
||||
.set i, 0
|
||||
.rept 512
|
||||
.quad (i << 21) + (PAGE_PRESENT | PAGE_WRITE | PAGE_HUGE)
|
||||
.set i, (i+1)
|
||||
.endr
|
||||
|
||||
|
||||
// Hardcode initial GDT segments
|
||||
// Only kernel code (0x8) and data (0x10) for now
|
||||
.section .rodata
|
||||
.align 0x1000
|
||||
.global BootGDT
|
||||
.global BootGDTp
|
||||
BootGDT:
|
||||
.quad 0
|
||||
.quad (GDT_PRESENT | GDT_CODEDATA | GDT_WRITE | GDT_EXECUTE | GDT_64BIT)
|
||||
.quad (GDT_PRESENT | GDT_CODEDATA | GDT_WRITE)
|
||||
BootGDTp: // We can't put the gdt pointer in the gdt, it's too big
|
||||
.short 3*8-1
|
||||
.quad V2P(BootGDT)
|
||||
|
||||
|
||||
// Reserved space for the stack
|
||||
.section .bss
|
||||
.global BootStack
|
||||
.align 0x1000
|
||||
.skip 0x1000
|
||||
BootStack:
|
||||
34
kernel/boot/kmain.c
Normal file
34
kernel/boot/kmain.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <mem.h>
|
||||
|
||||
#define VGA_MEMORY 0xb8000
|
||||
#define VGA_ROWS 24
|
||||
#define VGA_COLS 80
|
||||
|
||||
void clear_screen()
|
||||
{
|
||||
// Clear the video memory
|
||||
unsigned char *m = (void *)P2V(VGA_MEMORY);
|
||||
for(int i = 0; i < VGA_ROWS*VGA_COLS*2; i++)
|
||||
{
|
||||
*m++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void prints(const char *s, unsigned int row, unsigned int col)
|
||||
{
|
||||
// Very simple pure ascii string printing
|
||||
unsigned char *m = (void *)P2V(VGA_MEMORY);
|
||||
m += 2*VGA_COLS*row+2*col;
|
||||
while(*s)
|
||||
{
|
||||
*m++ = *s++;
|
||||
*m++ = 0x7;
|
||||
}
|
||||
}
|
||||
|
||||
int kmain(void)
|
||||
{
|
||||
clear_screen();
|
||||
prints("Hello, world!", 0, 0);
|
||||
for(;;)asm("hlt");
|
||||
}
|
||||
23
kernel/boot/multiboot_header.S
Normal file
23
kernel/boot/multiboot_header.S
Normal file
@@ -0,0 +1,23 @@
|
||||
.section .multiboot
|
||||
#include <multiboot.h>
|
||||
|
||||
|
||||
.align 0x1000
|
||||
MultiBootHeader1:
|
||||
.long MBOOT1_MAGIC
|
||||
.long MBOOT1_HEADER_FLAGS
|
||||
.long MBOOT1_HEADER_CHECKSUM
|
||||
|
||||
|
||||
.align 0x1000
|
||||
MultiBootHeader:
|
||||
.long MBOOT2_MAGIC
|
||||
.long MBOOT2_ARCH
|
||||
.long MBOOT2_LENGTH
|
||||
.long MBOOT2_CHECKSUM
|
||||
// Multiboot tags
|
||||
// End tag
|
||||
.short 0
|
||||
.short 0
|
||||
.long 8
|
||||
MultiBootHeaderEnd:
|
||||
Reference in New Issue
Block a user