Home > Blockchain >  Switch to 32-bit Protected Mode causes QEMU to restart in a loop
Switch to 32-bit Protected Mode causes QEMU to restart in a loop

Time:10-16

boot.asm:

[org 0x7c00]
[BITS 16]
boot:
    mov bp, 0x9000 ; set the stack
    mov sp, bp

    mov bx, MSG_REAL_MODE
    call print_string

    call switch_to_pm

    jmp $

%include "print/print.asm"
%include "gdt.asm"
%include "print_32.asm"
%include "switch_to_pm.asm"

[BITS 32]

; We're in 32-bit Protected Mode
BEGIN_PM:
    mov ebx, MSG_PROT_MODE
    call print_string_pm

    jmp $

MSG_REAL_MODE:
    db "Started in 16-bit Real Mode", 0

MSG_PROT_MODE:
    db "Sucessfully landed in 32-bit Protected Mode", 0

; Bootsector padding
times 510-($-$$) db 0
dw 0xAA55

gdt.asm:

[BITS 16]
align 4

gdtr:
    dw gdt_end-gdt_start-1
    dd gdt_start
; GDT
gdt_start:
    dd 0x0 ; 'dd' means define double word (4 bytes)
    dd 0x0

gdt_code: ; the code segment descriptor
    ; base=0x0, limit=0 xfffff,
    ; 1st flags: (present)1 (privilege)00 (descriptor type)1 -> 1001b
    ; type flags: (code)1 (conforming)0 (readable)1 (accessed)0 -> 1010b
    ; 2nd flags: (granularity)1 (32 - bit default)1 (64 - bit seg)0 (AVL)0 -> 1100b
    dw 0xffff ; Limit (bits 0-15)
    dw 0x0 ; base (bits 0-15)
    db 0x0 ; base (bits 16-23)
    db 0x9A ; 1st flags, type flags
    db 11001111b ; 2nd flags, linit (bits 16-19)
    db 0x0 ; base (bits 24-31)

gdt_data: ; the data segment descriptor
    ; same as code segment execpt for the type flags:
    ; type flags: (code)0 (expand down)0 (writable)1 (accessed)0 = 0010b
    dw 0xffff ; Limit (bits 0-15)
    dw 0x0 ; base (bits 0-15)
    db 0x0 ; base (bits 16-23)
    db 0x92 ; 1st flags, type flags
    db 11001111b ; 2nd flags, linit (bits 16-19)
    db 0x0 ; base (bits 24-31)

gdt_end: ; the reason for putting a label at the end of the
         ; GDT is so we can have the assembly calculate
         ; the size of the GDT for the GDT descriptor (below)

; GDT descriptor
gdt_descriptor:
    dw gdt_end - gdt_start - 1 ; size of the GDT, always less one
                               ; of the true size

    dd gdt_start ; start address of the GDT

    ; define some handy constants for the GDT segment descriptor offsets, which
    ; are what segment registers must contain when in protected mode
    ; (0x0 = NULL; 0x08 = CODE; 0x10 = DATA)
    CODE_SEG equ gdt_code - gdt_start
    DATA_SEG equ gdt_data - gdt_start

print_32.asm:

[BITS 32]
; Define some constants
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f

; prints a null-terminated string pointed to by edx
print_string_pm:
    pusha
    mov ah, WHITE_ON_BLACK ; Set edx to the start of video memory

print_string_pm_loop:
    mov al, [ebx] ; store the char at ebx in al
    mov al, WHITE_ON_BLACK ; store the attributes in ah

    cmp al, 0 ; if (al == 0), at end of string, so
    je print_string_pm_done; jump to print_string_pm_done

    mov [edx], ax ; store char and attributes at current character cell

    add ebx, 1 ; increment ebx to the next char in the string
    add edx, 2 ; move to next character cell in video memory

    jmp print_string_pm_loop

print_string_pm_done:
    popa
    ret ; return from the function

The only reason I know of that would cause QEMU to just restart in a loop is a triple fault, but I have no idea where that's coming from.

I've tried logging the QEMU interrupts with -d int but I have no idea what it means whatsoever. Here's the output log file:

SMM: enter
EAX=00000001 EBX=0000000b ECX=02000000 EDX=02000628
ESI=00000000 EDI=02000000 EBP=07fa84c0 ESP=00006c80
EIP=000ebad0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00007113 CCD=00000001 CCO=LOGICB  
EFER=0000000000000000
SMM: after RSM
EAX=00000001 EBX=0000000b ECX=02000000 EDX=02000628
ESI=00000000 EDI=02000000 EBP=07fa84c0 ESP=00006c80
EIP=000ebad0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=00000000 CCO=EFLAGS  
EFER=0000000000000000
SMM: enter
EAX=000000b5 EBX=000f7cd9 ECX=00001234 EDX=0000db80
ESI=07fbdb3b EDI=00006c40 EBP=00006c00 ESP=00006c00
EIP=00007cd8 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =db80 000db800 ffffffff 008f9300
CS =f000 000f0000 ffffffff 008f9b00
SS =0000 00000000 ffffffff 008f9300
DS =0000 00000000 ffffffff 008f9300
FS =0000 00000000 ffffffff 008f9300
GS =0000 00000000 ffffffff 008f9300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00006c00 CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=000f7cd9 ECX=00001234 EDX=0000db80
ESI=07fbdb3b EDI=00006c40 EBP=00006c00 ESP=00006c00
EIP=000f7cd9 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=00000000 CCO=EFLAGS  
EFER=0000000000000000
SMM: enter
EAX=000000b5 EBX=00007cf3 ECX=00005678 EDX=000eac40
ESI=07fbdb3b EDI=000eac40 EBP=00006c00 ESP=00006c00
EIP=000f7cf2 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=00006bec CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=00007cf3 ECX=00005678 EDX=000eac40
ESI=07fbdb3b EDI=000eac40 EBP=00006c00 ESP=00006c00
EIP=00007cf3 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =db80 000db800 ffffffff 00809300
CS =f000 000f0000 ffffffff 00809b00
SS =0000 00000000 ffffffff 00809300
DS =0000 00000000 ffffffff 00809300
FS =0000 00000000 ffffffff 00809300
GS =0000 00000000 ffffffff 00809300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000001 CCO=EFLAGS  
EFER=0000000000000000
SMM: enter
EAX=000000b5 EBX=000f7cd9 ECX=00001234 EDX=0000db80
ESI=07fbdb3b EDI=0000692e EBP=000068ee ESP=000068ee
EIP=00007cd8 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =db80 000db800 ffffffff 008f9300
CS =f000 000f0000 ffffffff 008f9b00
SS =0000 00000000 ffffffff 008f9300
DS =0000 00000000 ffffffff 008f9300
FS =0000 00000000 ffffffff 008f9300
GS =ca00 000ca000 ffffffff 008f9300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=000068ee CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=000f7cd9 ECX=00001234 EDX=0000db80
ESI=07fbdb3b EDI=0000692e EBP=000068ee ESP=000068ee
EIP=000f7cd9 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=00000000 CCO=EFLAGS  
EFER=0000000000000000
SMM: enter
EAX=000000b5 EBX=00007cf3 ECX=00005678 EDX=00000005
ESI=07fbdb3b EDI=00000000 EBP=000068ee ESP=000068ee
EIP=000f7cf2 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f6070 00000037
IDT=     000f60ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000000 CCD=000068da CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=00007cf3 ECX=00005678 EDX=00000005
ESI=07fbdb3b EDI=00000000 EBP=000068ee ESP=000068ee
EIP=00007cf3 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =db80 000db800 ffffffff 00809300
CS =f000 000f0000 ffffffff 00809b00
SS =0000 00000000 ffffffff 00809300
DS =0000 00000000 ffffffff 00809300
FS =0000 00000000 ffffffff 00809300
GS =ca00 000ca000 ffffffff 00809300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000001 CCO=EFLAGS  
EFER=0000000000000000

No idea what's wrong. The log file just repeats that block of text over and over (which makes sense, as it was restarting in a loop)

CodePudding user response:

The print_string_pm has multiple issues!

mov ah, WHITE_ON_BLACK ; Set edx to the start of video memory

The code does not setup the video output address in EDX. Depending on the pre-existing value in EDX, you might be destroying something important!


mov al, WHITE_ON_BLACK ; store the attributes in ah
cmp al, 0 ; if (al == 0), at end of string, so
je  print_string_pm_done

To make matters worse, these lines will make the loop never end (WHITE_ON_BLACK is non-zero). So the above mentioned destroying is guaranteed to happen (I believe).

Try next code:

VIDEO_MEMORY equ 0xB8000
WHITE_ON_BLACK equ 0x0F

; prints a null-terminated string pointed to by EBX
print_string_pm:
    pusha
    mov   edx, VIDEO_MEMORY
    mov   ah, WHITE_ON_BLACK
print_string_pm_loop:
    mov   al, [ebx]
    cmp   al, 0
    je    print_string_pm_done
    mov   [edx], ax
    add   ebx, 1
    add   edx, 2
    jmp print_string_pm_loop
print_string_pm_done:
    popa
    ret

CodePudding user response:

I've just fixed it. After applying the fix @SepRoland gave me in his answer, I realized on line 17 of switch_to_pm.asm, I put init_pm instead of CODE_SEG:init_pm, so instead of preforming a far jump, I accidentally preformed a short jump. My code now works, thanks everyone.

  • Related