2

Running my code with qemu, right after calling switch_to_32_pm, Qemu starts going crazy and constantly clearing the screen & displaying 'Booting from hard disk'. (I must add that I can't run with -curses for some reason (-curses: curses or iconv support is disabled) (i should really switch to linux...).

This is the relevant code:

boot.asm

[org 0x7c00]
[bits 16]
    ; initialise stack
    mov bp, 0x9000
    mov sp, bp

    call switch_to_32_pm

    jmp $

%include "gdt.asm"
%include "switch_to_pm.asm"

[bits 32]
    BEGIN_PM:

        jmp $

; bootsector padding
times 510-($-$$) db 0
dw 0xaa55

gdt.asm

gdt_start:
    gdt_null: ; null descriptor
        dd 0x0
        dd 0x0

    gdt_code: ; code segment descriptor
        dw 0xffff ; limit (bits 0-15)
        dw 0x0 ; base (bits 0-15)
        db 0x0 ; base (bits 16 -23)
        db 10011010b ; 1st flags, type flags
        db 11001111b ; 2nd flags, Limit (bits 16-19)
        db 0x0 ; base (bits 24 - 31)

    gdt_data: ; data segment descriptor
        dw 0xffff ; limit (bits 0-15)
        dw 0x0 ; base (bits 0-15)
        db 0x0 ; base (bits 16 -23)
        db 10010010b ; 1st flags, type flags
        db 11001111b ; 2nd flags, Limit (bits 16-19)
        db 0x0 ; base (bits 24 - 31)

    gdt_end:
        gdt_descriptor:
            dw gdt_end - gdt_start - 1 ; size of the gdt
            dd gdt_start ; gdt start address

            ; some handy constants
            CODE_SEG equ gdt_code - gdt_start
            DATA_SEG equ gdt_data - gdt_start

switch_to_pm.asm

[bits 16]

; switch to 32bit protected mode
switch_to_32_pm:
    ; disable interrupts
    cli

    ; switch to 32bit protected mode
    lgdt [gdt_descriptor]

    mov eax, cr0 ; move cr0 to eax
    or eax, 0x1 ; set the first bit of eax
    mov cr0 , eax ; update cr0

    jmp CODE_SEG:init_32_pm ; make a far jump
                            ; this forces the cpu to flush it's cache
                            ; of pre fetched instructions

[bits 32]
; We're now in 32bit mode! 4gb hip hip hooray!
; init stack
init_32_pm:
    mov ax, DATA_SEG ; point all segment regs to our data sector in gdt 
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ebp, 0x90000 ; set the stack at the top of free space
    mov esp, ebp

    call BEGIN_PM
  • 1
    Are you sure the code you are showing here is what you are using. Among other things `STR` isn't defined. You don't properly set up the segment registers when the bootloade rfirst starts. Not sure about yuor version of QEMU but possibly that is a problem - but usually QEMU sets the segment registers to zero before reaching your bootloader. Real hardware is often not that forgiving though and it should be fixed. – Michael Petch Oct 15 '20 at 07:04
  • 1
    yeah, i forgot to include STR in the code I posted here. It's defined in my actual code. About setting up the segment registers, I don't know how to do that. Could you provide me any pointers? – salt shaker Oct 15 '20 at 07:07
  • 1
    Seems your code is relying on SS & DS to be zero. You should set SS & DS at the beginning of your bootloader. I don't think this is your problem though. Are you sure the code you are using isn't doing something else after entering protected mode? The constant cycling in QEMU suggests you are experiencing a triple fault but the code you are showing seems to be ok (except for the one thing I have noted). Can you post the exact code that is failing for you. As well what command line do you use to launch QEMU with. What OS is your dev environment? What is the NASM command line you use to assemble? – Michael Petch Oct 15 '20 at 07:12
  • nasm: `nasm boot.asm -f bin -o boot.bin` qemu: `qemu-system-x86_64 boot.bin` i'm on windows – salt shaker Oct 15 '20 at 07:28
  • sorry, this is exactly what I am using – salt shaker Oct 15 '20 at 07:37
  • I somehow erased STR from the code I posted. It's defined in my code. Anyways, I removed it. Still nothing. I updated my code – salt shaker Oct 15 '20 at 07:41
  • 1
    Did you attempt to correct the problem of this code not setting up SS and DS to zero at the start of the bootloader (as in add `xor ax, ax` `mov ds, ax` `mov ss, ax` at the very start before doing anything else). The reality is if you make that change this code should work and sit at the boot screen doing nothing. – Michael Petch Oct 15 '20 at 07:44
  • Oh my god I'm such an idiot that worked. Thanks Michael :) Could you just tell me why it worked? – salt shaker Oct 15 '20 at 07:46
  • 1
    If that change worked it means that when the BIOS transferred control to the code in your boot sector it didn't set the segment registers to zero. You can't assume any of the registers (except DL) have any specific values in them. You have to ensure they are set properly. Since the stack pointer is SS:SP and you reference DS when accessing memory with the LGDT instruction) they have to be set to 0x0000 if you are using 0x7c00 as an origin point. – Michael Petch Oct 15 '20 at 07:48
  • I have a SO answer with a bunch of Bootloader tips that cover these kinds of problems: https://stackoverflow.com/a/32705076/3857942 – Michael Petch Oct 15 '20 at 07:49

0 Answers0