Qemu infinite restart after giving control to the kernel
Posted: Mon Dec 20, 2021 7:22 pm
Hi,
I'm facing a problem where Qemu keeps restarting because of (I guess) an invalid address.. I've successfully managed to get into protected mode and my gdt is loaded correctly.
Here is my bootloader:
Notice where it crashes :
Also, here is where I switch to protected mode :
My linker script for the bootloader is this one (nothing too complicated) :
My kernel entry which calls the main function in another file :
and it's linker script with .text at 0x10000
Now, I don't really understand why this shouldn't work as my kernek is loader at 0X10000 and in my bootloader I call this address. Also worth to note, in order to link my bootloader and my kenrel, I'm just using cat.
Thanks in advance !
I'm facing a problem where Qemu keeps restarting because of (I guess) an invalid address.. I've successfully managed to get into protected mode and my gdt is loaded correctly.
Here is my bootloader:
Code: Select all
.intel_syntax noprefix
.code16 # use 16 bits
.global _start
.global _init
.text
_start:
.space 80, 0 # Some BIOSes need a BPB, therefore we fill up space for a fake one
jmp 0x0000, _init # in case BIOS set cs to 0x7c00. We work with cs:ip
_init:
cld
mov bp, 0x9000
mov sp, bp
xor ax, ax
mov ds, ax
mov ss, ax
mov es, ax
movb [BOOT_DRIVE], dl
mov bx, offset flat:start_16_str
call print
mov bx, offset flat:read_disk_str
call print
mov dh, 0x1
mov bx, 0x7e00 # memory location to load disk to
call load_disk
mov bx, offset flat:read_disk_success_str
call print
ljmp 0x0000:0x7e00
.include "print_16.S"
.include "read_disk.S"
start_16_str:
.asciz "Starting in 16-bit mode"
read_disk_str:
.asciz "Loading disk into memory"
read_disk_success_str:
.asciz "Loaded disk successfully !"
.set BOOT_DRIVE, 0
.space 510-(.-_start), 0 # add zeroes to make it 510 bytes long
.word 0xaa55 # magic bytes that tell BIOS that this is bootable
secondstage:
call .check_CPUID
mov bx, offset flat:enable_a20_gate_str
call print
mov ax, 0x2401
int 0x15
call switch_to_protected_mode
.check_CPUID:
pusha
pushfd
pop eax
mov ecx, eax
xor eax, (1 << 21)
push eax
popfd
pushfd
pop eax
push ecx
popfd
xor eax, ecx
jz .no_CPUID
movb [cpuid_support], 1
mov bx, offset flat:cpuid_success_str
call print
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .lm_error
jmp .check_lm
.check_lm:
mov eax, 0x80000001 #check if CPU supports Long Mode, abort if not
cpuid
test edx, (1 << 29)
jz .lm_error
movb [long_mode_support], 1
mov ebx, offset flat:lm_success_str
call print
jmp lm_end
.no_CPUID:
movb [cpuid_support], 0
mov ebx, offset flat:cpuid_error_str
call print
jmp lm_end
.lm_error:
movb [long_mode_support], 0
mov ebx, offset flat:lm_error_str
call print
jmp lm_end
lm_end:
popa
ret
lm_error_str:
.asciz "ERROR: CPU does not support Long Mode"
lm_success_str:
.asciz "CHECK: CPU support Long mode "
cpuid_error_str:
.asciz "ERROR: CPU does not support CPUID"
cpuid_success_str:
.asciz "CHECK: CPU support CPUID"
enable_a20_gate_str:
.asciz "WARNING: Enabling A20 gate"
.include "gdt.S"
.include "32bit_switch.S"
.include "32bit-print.S"
.code32
BEGIN_PM:
mov ebx, offset flat:MSG_PROT_MODE
call print_string_pm
call 0x10000 # Here is where it fails
jmp .
MSG_PROT_MODE:
.asciz "[SUCCESS] Giving control to the Kernel !"
.set cpuid_support, 0
.set long_mode_support, 0
Code: Select all
.code32
BEGIN_PM:
mov ebx, offset flat:MSG_PROT_MODE
call print_string_pm
call 0x10000
jmp .
Code: Select all
.intel_syntax noprefix
.code16 # use 16 bits
switch_to_protected_mode:
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
ljmp CODE_SEG:init_pm
.code32
init_pm:
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x9000
mov esp, ebp
call BEGIN_PM
Code: Select all
ENTRY(_start)
SECTIONS
{
. = 0x7C00;
.text : {
*(.text*)
}
.rodata : {
*(.rodata*)
}
.data : {
*(.data*)
}
.bss : {
*(.bss*)
}
}
Code: Select all
.code32
.extern main
call main
jmp .
Code: Select all
ENTRY(main)
SECTIONS
{
. = 0x10000;
.text : {
KEEP(*(.text*))
}
}
Thanks in advance !