In order to see what is happening with various implementations, I have been trying to use GDB with QEMU (running on Windows XP).
I am using a basic bootloader (from the Reactos code) called "isoboot.asm". This routine loads a file called "setupldr.sys" to address 0x8000. This works fine.
I have created a "setupldr.sys" file based on code bits from other experimental operating systems. The objective is the following:
1. Enable A20
2. Load Flat-model GDT
2. Switch to PMode
3. Setup registers
4. Load a Kernel from the ISO file (where my bootloader and setupldr.sys came from)
My test "setupldr.sys" code is as follows:
Code: Select all
[BITS 16]
start:
; enable A20
cli
mov al, 0d1h ; AT
out 64h, al
mov al, 3
out 60h, al
mov al, 2 ; PS/2
out 92h, al
; switch to protected mode
lgdt [cs:GDTvalue] ; load protected mode GDT
mov eax, cr0 ; read current cr0 settings
or al, 1 ; set protected mode flag
mov cr0, eax ; store modified cr0 settings
jmp os_code:SetRegs ; jump to 32 bit code
GDTvalue: dw GDT_l - GDT - 1 ; size of GDT - 1
dd GDT ; base of GDT
GDT: dd 0
dd 0
os_code_l: dw 0ffffh, 0
db 0, 10011011b, 11001111b, 0
os_data_l: dw 0ffffh, 0
db 0, 10010011b, 11001111b, 0
GDT_l:
os_code equ os_code_l - GDT ; Pointer to 2nd 8-byte selector in the GDT
[BITS 32] ; 32 bit protected mode code
; Setup the registers to make use of the newly created GDT
SetRegs:
xor ebx, ebx
mov ds, ebx
mov es, ebx
mov fs, ebx
mov gs, ebx
mov ss, ebx
; Print Kernel Loading message
mov si, msgLoading
call Print
hlt
;************************************************;
; Prints a string
; DS=>SI: 0 terminated string
;************************************************;
Print:
lodsb ; load next byte from string from SI to AL
or al, al ; Does AL=0?
jz PrintDone ; Yep, null terminator found-bail out
mov ah, 0eh ; Nope-Print the character
int 10h
jmp Print ; Repeat until null terminator found
PrintDone:
ret ; we are done, so return
msgLoading db 0x0D, 0x0A, "Loading Kernel... ", 0x0D, 0x0A, 0x00
GDB is all I have, as the builtin debugging capabilities of Qemu are inadequate (or at least as far as I can tell by perusing the Qemu docs). For example, there appears to be no way to step through code.
GDB appears to show me what I would expect until I reach the instruction "jmp os_code:SetRegs".
In this case, GDB shows me it's disassembly of the instruction as follows:
jmp 0x17:0x8003e
First off I would have thought it should have shown 0x8 (instead of 0x17) as my understanding is that 8 references the 2nd 8-byte section of the GDT which happens to be my Code Segment selector. My code should produce a 0x8. Even if I replace the "os_code" with 8, it still shows up as 0x17.
0x17 happens to be the first word of the GDTR, but it makes no sense that the "jmp" instruction should be using that value. Why doesn't it use the value I have told it to use (0x8)?
Secondly, the 0x8003e makes no sense because I know the code is at 0x803e.
Given these "jmp" values it is no wonder it crashes. The problem is I don't understand how it is arriving at such odd values. So, is GDB showing me false information? Or, is there something else that I need to be doing in my code?
If GDB is the problem, what do others use as an alternative?
I would rather be using Olly Debugger as it is a MUCH better debugger, but I don't know how to make it connect to QEMU as does GDB. I suppose I could attach directly to the QEMU process, but then finding the address where my code starts becomes a significant issue.