After much debate with myself, I have finally decided to move my OS to Protected Mode. However, I am having a few issues executing Protected Mode code. The first step on the OSDev wiki was to enable the A20 line, something I had little trouble with because of the fast gate. The second part was loading the Global Descriptor Table. I followed the BrokenThorn Entertainment tutorial and used it as a rough base for my GDT, and translated some of the long binary values to nice and short hex values. Finally, I set the lowest bit of the cr0 register to 1 to enter protected mode. I then made the far jump to 0x08:start32. Upon executing my code, however, and monitoring the registers using qemu's monitor -stdio flag, I see unexpected results. My main protected mode routine, start32, is simple. It moves the value 0xDEADBABA into the eax register. This however does not seem to take effect, as on QEMU, the value is shown to be 00000100. The cr0 register is 00000010, which seems to be correct, but once again makes me skeptical as it is not the lowest bit that is one. The worst one by far is the GDT register, which is equal to precisely 00000000 00000000. What is the problem here? I have provided code for both my bootsector and my part of the kernel that switches to Protected Mode below.
P.S: The bootsector clears the screen and loads the kernel. That is its only purpose.
start.asm (bootsector) - https://gist.github.com/safsom/54a9c653 ... 8f8a12b62b
kernel.asm (problematic file) - https://gist.github.com/safsom/bc887816 ... 05de670d1c
Any help would be greatly appreciated.
Trouble jumping to 32-bit code once in Protected Mode
-
- Member
- Posts: 799
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Trouble jumping to 32-bit code once in Protected Mode
This was resolved on SO in the comment area. But the main problem is that he's using real mode segments that aren't zero (ie: 0x7c0, 0x2000 eyc) base on BrokenThorne tutorial. Unfortunately this meant that the base in the GDT was a real mode offset and had to be converted to a linear address. The FAR JMP into protected mode also suffered the same kind of issue. Once in protected mode the offsets the code were running at were not relative to linear address 0x00000. I suggested a simplification of the code to have the jump to protected mode and the GDT in the first 64k and using a segment of 0x0000. This means a 16-bit offset in real mode in the first 64kb is the same as the offset in protected mode. No monkeying around by doing real mode offset to linear address conversions in protected mode. The drive number was hard coded to 0 instead of the one passed in by the BIOS (via DL register) when doing a disk read. A quick fix was to simplify the code he posted to something like the code below. start.asm:
kernel.asm:
Code: Select all
org 0x7c00
bits 16
start:
xor ax, ax ; Set DS to 0. xor register to itselfzeroes register
mov ds, ax
mov ss, ax ; Stack just below bootloader SS:SP=0x0000:0x7c00
mov sp, 0x7c00
mov ah, 0x00
mov al, 0x03
int 0x10
load_kernel:
mov ah, 0x02 ; call function 0x02 of int 13h (read sectors)
mov al, 0x01 ; read one sector (512 bytes)
mov ch, 0x00 ; track 0
mov cl, 0x02 ; sector 2
mov dh, 0x00 ; head 0
; mov dl, 0x00 ; drive 0, floppy 1. Comment out DL passed to bootloader
xor bx, bx ; segment 0x0000
mov es, bx ; segments must be loaded from non immediate data
mov bx, 0x7E00 ; load the kernel right after the bootloader in memory
.readsector:
int 13h ; call int 13h
jc .readsector ; error? try again
jmp 0x0000:0x7E00 ; jump to the kernel at 0x0000:0x7e00
times 510-($-$$) db 0
dw 0xAA55
Code: Select all
org 0x7e00 ; Offset of this code is 0x7e00
; as we loaded it into memory at 0x0000:0x7e00
bits 16
section .text
start:
cli
in al, 0x92
or al, 2
out 0x92, al
lgdt[toc]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:start32 ; The FAR JMP is simplified since our segment is 0
section .rodata
gdt32:
dd 0
dd 0
dw 0x0FFFF
dw 0
db 0
db 0x9A
db 0xCF
db 0
dw 0x0FFFF
dw 0
db 0
db 0x92
db 0xCF
db 0
gdt_end:
toc:
dw gdt_end - gdt32 - 1
dd gdt32 ; The GDT base is simplified since our segment is now 0
bits 32
section .text
start32:
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
mov esp, 0x9c000 ; Set the stack to grow down from area under BDA/Video memory
mov dword [0xB8000], 0x2f4b2f4f
jmp $