I am doing a hobby 32bit kernel and few days ago I've encountered different behaviour when running my kernel with `-accel` parameter.
The kernel is working OK when run with:
Code: Select all
qemu-system-x86_64 -drive file=release/disk.img,format=raw,index=1,media=disk
Code: Select all
qemu-system-x86_64 -drive file=release/disk.img,format=raw,index=1,media=disk -accel hvf
I've found out that problem is in code after setting up paging, specifically when jumping to higher half kernel entry point.
I am attaching my code and I would be very happy if someone could tell me what is wrong and why is the program acting differently when running accelerated or not.
I can provide more information if needed.
Thank you very much.
Ondrej
Code: Select all
[bits 32]
STACKSIZE equ 0x4000
global _loader
extern kmain
KERNEL_VIRTUAL_BASE equ 0xc0000000 ; 3GB
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; Page directory index of kernel's 4MB PTE.
FRAMEBUFFER_VIRTUAL_BASE equ 0xff400000
FRAMEBUFFER_PAGE_NUMBER equ (FRAMEBUFFER_VIRTUAL_BASE >> 22) ; Page directory index of framebuffer's 4MB PTE.
section .data
align 0x1000
boot_page_directory:
; This page directory entry identity-maps the first 4MB of the 32-bit physical address space.
; This entry must be here -- otherwise the kernel will crash immediately after paging is
; enabled because it can't fetch the next instruction! It's ok to unmap this page later.
dd 0x00000083
times (KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages before kernel space.
; This page directory entry defines a 4MB page containing the kernel.
dd 0x00000083
times (FRAMEBUFFER_PAGE_NUMBER - KERNEL_PAGE_NUMBER - 1) dd 0
; Two page directory entries define a 8MB space for framebuffer.
dd 0xfd000083
dd 0xfd400083
times (1024 - FRAMEBUFFER_PAGE_NUMBER - 2) dd 0 ; Pages after the framebuffer space.
; setting up entry point for linker
loader equ (_loader - 0xc0000000)
global loader
_loader:
cli
; NOTE: Until paging is set up, the code must be position-independent and use physical addresses, not virtual ones!
mov edx, (boot_page_directory - KERNEL_VIRTUAL_BASE)
mov cr3, edx ; Load Page Directory Base Register.
mov edx, cr4
or edx, 0x00000010 ; Set PSE bit in CR4 to enable 4MB pages.
mov cr4, edx
mov edx, cr0
or edx, 0x80000000 ; Set PG bit in CR0 to enable paging.
mov cr0, edx
; Start fetching instructions in kernel space.
; Since eip at this point holds the physical address of this command (approximately 0x00100000)
; we need to do a long jump to the correct virtual address of start_in_higher_half which is approximately 0xc0100000.
lea edx, [start_in_higher_half]
jmp edx ; ===================> HERE, after this jump program crashes and qemu keeps resetting
start_in_higher_half:
mov esp, stack + STACKSIZE
call kmain ; call kernel
hlt
section .bss
align 32
stack:
resb STACKSIZE ; reserve 16k stack