Assembly code crashes in QEMU but runs fine in Bochs

74 views Asked by At

I'm currently learning some OS development and wrote a very basic bootloader.

It just takes some sectors of a floppy disk image and loads it into the RAM at address 0x10000. Then it switches to 32-bit protected mode and jumps into 0x10000. That works pretty fine.

At that address, there is just some code that displays "Hello, World!" by writing to the BIOS video buffer. Then, it jumps back into 16-Bit real mode and just halts in an infinite loop.

Here's the code that is loaded ad 0x10000:

; file is loaded at address 0x10000
org 0x10000

; Entry point is here
; 32-bit protected mode

bits 32
pm32:
    ; print "Hello World!" using the BIOS video buffer
    VideoBuffer equ 0xb8200

    ; Set up data segments so we can access the "Hello World!" string
    mov ax, 10h
    mov ds, ax
    mov ss, ax

    sti

    mov edi, VideoBuffer
    mov esi, msg

    print:
        lodsb

        ; check if we reached the null char
        test al, al
        jz print_done

        ; print text and move destination pointer
        mov [edi], al
        inc edi
        inc edi

        jmp print

    print_done:
        ; jump to "pmdone" in 16-bit protected mode
        jmp 18h:pmdone

bits 16
pmdone:
    ; switch to real mode
    mov eax, cr0
    xor al, 1
    mov cr0, eax

halt:
    ; halt the CPU using an infinite loop
    ; (gotta use 1000h: segment because the address of halt is cut to 16 bits)
    jmp 1000h:halt

msg: db "Hello World!", 0

My GDT looks like this: 0x8: 32-bit code 0x10: 32-bit data 0x18: 16-bit code 0x20: 16-bit data

I'm using QEMU to execute the code and Bochs to debug it. However, when I run my code in Bochs and just enter c for continue, it works fine. It displays the hello world message and then just gets stuck in the loop.

But when I run it in QEMU, it keeps crashing and restarting. I set down the speed a bit and saw that it only sometimes displays the "Hello World" message, but not always.

Is there a reason why it doesn't work in QEMU? Am I doing something wrong with the addressing or the jumping? Because I'm not feeling very sure there.

Is that best the way how you would exit 32-bit mode to halt your CPU, or should I do it in another way?

Thanks for answers

(EDIT): This is the last interrupt QEMU logs. Not sure if that's helpful

     2: v=08 e=0000 i=0 cpl=0 IP=0018:0000002b pc=0000002b SP=0010:00000000 env->regs[R_EAX]=00000011
EAX=00000011 EBX=00000000 ECX=00000002 EDX=00000000
ESI=0001003f EDI=000b8218 EBP=00000000 ESP=00000000
EIP=0000002b EFL=00000293 [--S-A-C] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =1000 00010000 0000ffff 00009300 DPL=0 DS16 [-WA]
CS =0018 00000000 000fffff 000f9a00 DPL=0 CS16 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
GS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007c7a 00000027
IDT=     00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=000000d4 CCD=ffffff3d CCO=SUBW
EFER=0000000000000000
check_exception old: 0x8 new 0xd
0

There are 0 answers