Difficultly with Long Mode
Posted: Thu Apr 08, 2010 5:54 am
So I've been toying with my 32-bit OS for quite some time and am trying to get into 64-bit development. But I am having a bit of difficulty getting into long mode on all my tests. Currently, what I have works in bochs, but gives a stack fault in vmware and stalls qemu. I am booting with grub, the intention is to have a higher half kernel, but currently I am just 1:1 mapping the first 6 MEG (physical load address is 2MB). Here is the code:
If anyone has any clues as to what could be going wrong, please let me know.
Code: Select all
#define ASM
#include "multiboot.h"
#define KERNEL_VMA 0xffffffff80000000
.code32
.align 4
multiboot_header:
.long MULTIBOOT_HEADER_MAGIC /* magic */
.long MULTIBOOT_HEADER_FLAGS /* flags */
.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) /* checksum */
.long (multiboot_header - KERNEL_VMA) /* header_addr */
.long (_start - KERNEL_VMA) /* load_addr */
.long (_edata - KERNEL_VMA) /* load_end_addr */
.long (_end - KERNEL_VMA) /* bss_end_addr */
.long (bootstrap - KERNEL_VMA) /* entry_addr */
.globl bootstrap
bootstrap:
/* make sure interrupts are off */
cli
/* load the GDT */
lgdt (GDT64_PTR - KERNEL_VMA)
/* this may not be necessary if since I use grub, just trying to be sure */
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
/* give ourselfs a functional stack */
movl $(init_stack_end - KERNEL_VMA), %esp
/* once again, trying to find the issue, I don't think this is necessary */
ljmp $0x08, $(boot32 - KERNEL_VMA)
boot32:
/* ensure that paging is off */
movl %cr0, %eax
btr $31, %eax
movl %eax, %cr0
/* reset EFLAGS. */
pushl $2
popf
/* load a level4 PD */
movl $(pml4 - KERNEL_VMA), %eax
mov %eax, %cr3
/* enable CR4.PAE */
movl %cr4, %eax
bts $5, %eax
movl %eax, %cr4
/* set IA32_EFER.LME */
movl $0xc0000080, %ecx
rdmsr
orl $0x00000101, %eax
wrmsr
/* **** DOESN'T GET HERE IN VMWARE , Stack Fault Error! *** */
/* enable paging */
movl %cr0, %eax
bts $31, %eax
movl %eax, %cr0
/* at this point we should be in IA-32e mode, let's go all the way to long mode :-) */
ljmp $0x18, $(boot64 - KERNEL_VMA)
GDT64:
.quad 0x0000000000000000 // 0x00 NULL
.quad 0x00cf9a000000ffff // 0x08 CODE32
.quad 0x00cf92000000ffff // 0x10 DATA32
.quad 0x002098000000ffff // 0x18 CODE64
.quad 0x000090000000ffff // 0x20 DATA64
.align 16
GDT64_PTR:
.word . - GDT64 - 1
.quad GDT64 - KERNEL_VMA
.align 0x1000
pml4:
.quad pdp - KERNEL_VMA + 3
.fill 511,8,0
pdp:
.quad pd - KERNEL_VMA + 3
.fill 511,8,0
pd:
/* ident map of first 6 megs */
.quad 0x0000000000000083
.quad 0x0000000000200083
.quad 0x0000000000400083
.fill 509,8,0
.align 0x1000
init_stack:
.fill 1024,1,0
init_stack_end:
.code64
boot64:
/* Hurray, we made it, a simple clear the screen with blue code */
mov $0xb8000, %rdi
mov $0x1f201f201f201f20, %rax
mov $500, %rcx
cls:
mov %rax, (%rdi)
add $8, %rdi
loop cls
hlt