OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 6:49 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: (Another Post) Problems doing far jump after switch to PM
PostPosted: Tue Mar 12, 2019 6:48 am 
Offline

Joined: Tue Mar 12, 2019 6:39 am
Posts: 6
Hello,

Working on my bootloader and all seems to be going along nicely, I had it printing characters to the screen and what not. Now comes the time to switch to 32-bit Protected Mode.

From what I can tell, I seem to load the GDT correctly and set the Protected Mode flag in cr0. However, as soon as I attempt to do the far jump afterwards in order to flush the 16-bit commands in the pipeline I have issues. Qemu sits in a reboot loop and VirtualBox crashes out. Presumably, I'm not jumping to the location I expect to be jumping to either due to a misunderstanding of how CS/DS is used in a far jump, or my GDT table is incorrect. As a result, meaningless instructions are being executed and causing an exception of some variety causing the VM to crash.

Below is the full copy of my bootloader code, stripped down to the minimum code required to reproduce the issue. Presumably, I'm doing something dumb and should be a simple fix.

Code:
BITS 16

ORG 0x7C00

entry:
    xor ax, ax
    mov ds, ax
    mov ss, ax
    mov sp, 0x7C00

; Enable A20 Gate (TODO: Check if A20 is already enabled)
enable_a20:
    in al, 0x92
    or al, 2
    out 0x92, al

begin_protected_mode_switch:
    cli

load_gdt:
    lgdt [gdt_desc]

enable_protected_mode:
    ; Switch to 32-bit Protected Mode
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    mov ax, 0x5574
    ; Temporary to examine registers in Qemu
    jmp hang
    jmp 0x0008:flush

hang:
    jmp hang

BITS 32
flush:
    ; Data Selectors set to the gdt_data offset (16 bytes into GDT)
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    ; TODO: Switch to C code from here
loop:
    jmp loop

; GDT Table
gdt:
; Null Descriptor
gdt_null:
    dq 0

; Code GDT Entry
gdt_code:
    dw 0xFFFF
    dw 0
    db 0
    db 0x9A
    db 11001111b
    db 0

; Data GDT Entry
gdt_data:
    dw 0xFFFF
    dw 0
    db 0
    db 0x92
    db 11001111b
    db 0
gdt_end:

; GDT Descriptor
gdt_desc:
    dw gdt_end - gdt - 1
    dd gdt

; Magic Bytes to Make Bootable
    times 510-($-$$) db 0
    db 0x55
    db 0xAA


Code:
    mov ax, 0x5574
    ; Temporary to examine registers in Qemu
    jmp hang

The above code is to force the VM to be at a specific point I want. The code in this state doesn't reset Qemu. And I can do "info registers" to view the various registers (see below)

Code:
EAX=00005574 EBX=00000000 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00007c00
EIP=00007c29 EFL=00000006 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
CS =0000 00000000 0000ffff 00009b00 DPL=0 CS16 [-RA]
SS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
DS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-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=     00007c3b 00000017
IDT=     00000000 000003ff
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000


I can see the value 0x5574 is loaded into EAX. The EIP value seems sane, as does the value in GDT.

However, if I remove the "jmp hang" and allow it to execute the far jump, Qemu then gets stuck in it's reboot loop and doing "info registers" provides meaningless data depending on where I manage to execute it during the reboot.

I have attempted to use GDB to step through the instructions but GDB seems to refuse to load my executable and therefore doesn't play nicely for me.

Can anyone see anything obvious I've done wrong?


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:18 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
I see nothing wrong in this code (whether you use `jmp hang` or not). When it doesn't work are you sure the code you are assembling is what you are showing here?


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:20 am 
Offline

Joined: Tue Mar 12, 2019 6:39 am
Posts: 6
Amusingly I went away for a meeting with a client, came back, had an idea, and now it seems to work.

Immediately prior to my jump I now do this:

Code:
    mov eax, 0
    mov ds, eax
    jmp 0x0008:flush


Setting the DS register to 0 seems to have allowed the jmp to execute the address I actually wanted it to do.

Code:
flush:
    ; Data Selectors set to the gdt_data offset (16 bytes into GDT)
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    ; TODO: Switch to C code from here
    mov eax, 0x34567890
loop:
    jmp loop


Doing 'info registers' in Qemu now shows me that EAX is equal to 0x34567890 and there is no reboot loop.....


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:27 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
There is no reason to do this:
Code:
mov eax, 0
mov ds, eax
Are you sure if you remove those lines it fails?


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:33 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
Using this exact file does it crash or not?
Code:
BITS 16

ORG 0x7C00

entry:
    xor ax, ax
    mov ds, ax
    mov ss, ax
    mov sp, 0x7C00

; Enable A20 Gate (TODO: Check if A20 is already enabled)
enable_a20:
    in al, 0x92
    or al, 2
    out 0x92, al

begin_protected_mode_switch:
    cli

load_gdt:
    lgdt [gdt_desc]

enable_protected_mode:
    ; Switch to 32-bit Protected Mode
    mov eax, cr0
    or eax, 1
    mov cr0, eax
    ; Remove all instruction between turning on PE flag and the JMP
    jmp 0x0008:flush


BITS 32
flush:
    ; Data Selectors set to the gdt_data offset (16 bytes into GDT)
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    ; TODO: Switch to C code from here
loop:
    jmp loop

; GDT Table
gdt:
; Null Descriptor
gdt_null:
    dq 0

; Code GDT Entry
gdt_code:
    dw 0xFFFF
    dw 0
    db 0
    db 0x9A
    db 11001111b
    db 0

; Data GDT Entry
gdt_data:
    dw 0xFFFF
    dw 0
    db 0
    db 0x92
    db 11001111b
    db 0
gdt_end:

; GDT Descriptor
gdt_desc:
    dw gdt_end - gdt - 1
    dd gdt

; Magic Bytes to Make Bootable
    times 510-($-$$) db 0
    db 0x55
    db 0xAA
TO assemble and run this in QEMU use:
Code:
nasm -f bin boot.asm -o boot.bin
qemu-system-i386 -fda boot.bin


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:42 am 
Offline

Joined: Tue Mar 12, 2019 6:39 am
Posts: 6
Nope you're absolutely right, removing the bits I added means it's not crashing.

Building and running the code snippet you provided, results in no crashing....

I'm so confused....


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:43 am 
Offline

Joined: Tue Mar 12, 2019 6:39 am
Posts: 6
Is it purely because I had something between setting the Protected Mode bit in cr0 and the jump?


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:47 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
If I didn't know any better and I had heard this story the first thing I would have asked is "When it fails, is it failing on real hardware and are you booting with USB Floppy Disk Emulation". I'm going to straight up ask... The failures you are seeing are strictly in QEMU and not on real hardware?


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:49 am 
Offline

Joined: Tue Mar 12, 2019 6:39 am
Posts: 6
It was crashing in both Qemu and VirtualBox VMs - I don't have an easy way to test on real hardware.


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:50 am 
Offline

Joined: Tue Mar 12, 2019 6:39 am
Posts: 6
Thank you for your assistance though. It has allowed me to get past this roadblock and can hopefully leave much of this ASM world behind soon and get back into a language I'm much more familiar with (C).


Top
 Profile  
 
 Post subject: Re: (Another Post) Problems doing far jump after switch to P
PostPosted: Tue Mar 12, 2019 8:51 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 692
The idea of using the JMP 0x0008:flush right after turning on the PE bit in CR0 is to ensure that the instruction prefetch queue is cleared (to ensure the instructions following are decoded properly) and that a 32-bit CS selector is set. To be honest the code you did have shouldn't have caused a problem. Maybe you weren't testing the code you thought you were in QEMU? (wrote one set of code, ran another by accident)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 87 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group