2
votes

Im currently learning to build my own bootloader. I was able to setup a gdt and get into protected mode. But when i tried to move 0x18 (third segment in gdt) into ds most of my registers are destroyed and eip gets something random

Code that causes error: (im already in protected 32-bit mode)

mov eax, 0x18
mov ds, eax  <--- After this instruction registers are destroyed
mov eax, [0x0000]

My gdt entries:

; GDT null segment                                                                                   
  8 gdt_null:
  9     dq 0
 10 
 11 ; GDT code segment (4GB)
 12 gdt_code:
 13     dw 0xFFFF
 14     dw 0x00
 15     db 0x00
 16     db 10011010b
 17     db 11001111b
 18     db 0x00
 19 
 20 ; GDT data segment (4GB)
 21 gdt_data:
 22     dw 0xFFFF
 23     dw 0x00
 24     db 0x00
 25     db 10010010b
 26     db 11001111b
 27     db 0x00
 28 
 29 ; GDT video segment
 30 gdt_video:
 31     dw 0xFFFF
 32     dw 0x00
 33     dw 0x00
 34     dw 10010010b
 35     db 11001111b
 36     db 0x00

gdb before the instruction:

─── Output/messages ─────────────────────────────────────────────────────────────────────────────────────
─── Assembly ────────────────────────────────────────────────────────────────────────────────────────────
0x00007cf4 ? mov    ds,eax
0x00007cf6 ? mov    eax,ds:0x0
0x00007cfb ? hlt    
0x00007cfc ? or     BYTE PTR [eax+0x65],0x6c
0x00007d00 ? ins    BYTE PTR es:[edi],dx
0x00007d01 ? outs   dx,DWORD PTR ds:[esi]
0x00007d02 ? and    BYTE PTR [edi+0x6f],dl
─── Expressions ─────────────────────────────────────────────────────────────────────────────────────────
─── History ─────────────────────────────────────────────────────────────────────────────────────────────
─── Memory ──────────────────────────────────────────────────────────────────────────────────────────────
─── Registers ───────────────────────────────────────────────────────────────────────────────────────────
   eax 0x00000018       ecx 0x00000002       edx 0x00000080       ebx 0x00000000       esp 0x00002000   
   ebp 0x00000000       esi 0x00000000       edi 0x00000000       eip 0x00007cf4    eflags [ PF ]       
    cs 0x00000008        ss 0x000007e0        ds 0x00000010        es 0x000009e0        fs 0x00000000   

gdb after instruction:

─── Output/messages ─────────────────────────────────────────────────────────────────────────────────────
─── Assembly ────────────────────────────────────────────────────────────────────────────────────────────
0x0000e05b ? add    BYTE PTR [eax],al
0x0000e05d ? add    BYTE PTR [eax],al
0x0000e05f ? add    BYTE PTR [eax],al
0x0000e061 ? add    BYTE PTR [eax],al
0x0000e063 ? add    BYTE PTR [eax],al
0x0000e065 ? add    BYTE PTR [eax],al
0x0000e067 ? add    BYTE PTR [eax],al
─── Expressions ─────────────────────────────────────────────────────────────────────────────────────────
─── History ─────────────────────────────────────────────────────────────────────────────────────────────
─── Memory ──────────────────────────────────────────────────────────────────────────────────────────────
─── Registers ───────────────────────────────────────────────────────────────────────────────────────────
   eax 0x00000000       ecx 0x00000000       edx 0x00000663       ebx 0x00000000       esp 0x00000000   
   ebp 0x00000000       esi 0x00000000       edi 0x00000000       eip 0x0000e05b    eflags [ ]          
    cs 0x0000f000        ss 0x00000000        ds 0x00000000        es 0x00000000        fs 0x00000000   
    gs 0x00000000   

as you see most of the registers are destroyed, eip is somewhere else it should be and there is not really code at that location. Some instruction before i move 0x10 in ds and it works without any problems. Is this a bug of qemu? I do not want to try this on my real pc, cause who know what happens? Anyone have an idea?

1
That's not a minimal reproducible example. Anyway, you probably set up your GDT wrong (e.g. wrong limit) and you got an exception the handler for which is also broken. I recommend you use bochs as that provides better debugging.Jester

1 Answers

3
votes

The reason the registers are trashed is because your system triple faulted and entered back into real mode. CS:IP afterwards is 0xf000:e05b which is in the BIOS ROM. GDB doesn't properly deal with real mode and is displaying the instructions at 0x0000:0xe05b because it doesn't understand that the segment register 0xf000 also makes up part of the address and disassembled the instructions from the wrong memory location. That memory appears to have been filled with zeroes. BOCHS is a better debugger when debugging this kind of problem early on in OS development. BOCHs has an info gdt command that will show you the currently loaded GDT. If an entry is corrupt you'd more easily be able to see it.

As it appears you have managed to set CS selector register (before the triple fault) I assume part of your GDT is valid. My first observation is that your gdt_video descriptor in the GDT is laid out incorrectly. You have:

; GDT video segment
gdt_video:
    dw 0xFFFF
    dw 0x00
    dw 0x00             ; <------ This needs to be a byte
    dw 10010010b        ; <------ This needs to be a byte
    db 11001111b
    db 0x00

It should have been:

; GDT video segment
gdt_video:
    dw 0xFFFF
    dw 0x00
    db 0x00
    db 10010010b
    db 11001111b
    db 0x00

You may have other issues, but based on the information given this is the only thing I can observe being incorrect.


Other Observations

  • It is unclear why you have created the gdt_video descriptor. You've made it a flat 4GB data descriptor just like the gdt_data descriptor. Both descriptors as you have shown here are identical. You could have loaded DS selector with 0x10.
  • You don't show all your code but I noticed that before the triple fault the debugger said:

    ss 0x000007e0        ds 0x00000010        es 0x000009e0        fs 0x00000000
    

    I hope that you intend to set SS (and ESP), ES, FS, and GS at some point. SS:ESP should be set before you use any instructions that interact with the stack (ie: push, pop, call, ret etc.)