Problem setting up GDT

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
f2

Problem setting up GDT

Post by f2 »

I set up the GDT (I hope correctly, but apparently not) and switched to PMode. I coded this, but it's not working. When I booted off of my OS's disk to try it out and see if it works, my computer restarted when, I guess, it reached the GDT and/or PMode part.

Why would my computer restart? What would cause it (having to do with GDT and/or PMode problems)? Would you like to see my code? Thanks!
jedld

Re:Problem setting up GDT

Post by jedld »

Based on my experience the computer would
reboot for the following reasons, I suggest that you check this out:

1. The GDT has not bee properly set up.
-This is the number one reason I could think of,
if your program goes into protected mode and
your CS selector points to an invalid
entry------>REBOOT :)

2.After entering protected mode you used a segment
register that has an invalid selector value. Remeber that upon entering pmode only CS has a valid value. If
the segment has an invalid value a simple
PUSH SS,PUSH Sx,POP Sx,POP ES, POP SS..... would
make your computer reboot. Assigning a segment
register with an invalid selector value will also make your computer reboot: For example if AX has a value of 9 and your GDT has a limit of 5 entries, MOV ES,AX will make your computer reboot.

3.I also had problems when writing a protected mode routine in the bootsector, but I'm still checking the problem out.

The reason why the computer reboots is because the errors above generate exceptions, and if the exception is not handled (which I assume you have not) the computer will indeed reboot.
Hope I help you out.
K.J.

Re:Problem setting up GDT

Post by K.J. »

Please post your code or give a link to it.

K.J.
f2

Re:Problem setting up GDT

Post by f2 »

Here is my code:

[bits 16]
[org 0x00]

jmp start

GDTR:
   dw   0xFFFF      ;GDT Segment Limit
   dd   0x00000000   ;GDT Segment Base Address

IDTR:
   dw   0x07FF      ;IDT Segment Limit
   dd   0x00010000   ;IDT Segment Base Address

GDT:
   db   0x00      ;--0x0000 Null Descriptor-- Bits 07-00 of Limit
   db   0x00      ;Bits 15-08 of Limit
   db   0x00      ;Bits 07-00 of Base
   db   0x00      ;Bits 15-08 of Base
   db   0x00      ;Bits 23-16 of Base
   db   0xF0      ;Access Byte
   db   0x00      ;Flags and Bits 19-16 of Limit
   db   0x00      ;Bits 32-24 of Base

   db   0xFF      ;--0x0008 Kernel Code Segment Descriptor--
   db   0x00
   db   0x00
   db   0x00
   db   0x10
   db   0x98
   db   0xC0
   db   0x00

   db   0xFF      ;--0x0010 Kernel Data Segment Descriptor--
   db   0x00
   db   0x00
   db   0x00
   db   0x10
   db   0x92
   db   0xC0
   db   0x00

   db   0x8F      ;--0x0018 Stack Segment Descriptor--
   db   0xFF
   db   0xFF
   db   0xFF
   db   0x09
   db   0x96
   db   0xCF
   db   0x00

   db   0xFF      ;--0x0020 Video RAM Segment Descriptor--
   db   0xFF
   db   0x00
   db   0x00
   db   0x0A
   db   0x92
   db   0x41
   db   0x00

   db   0xFF      ;--0x0028 Bootstrap Code Segment Descriptor--
   db   0xFF
   db   0x00
   db   0x00
   db   0x02
   db   0x98
   db   0x00
   db   0x00

   db   0xFF      ;--0x0030 Bootstrap Data Segment Descriptor--
   db   0xFF
   db   0x00
   db   0x00
   db   0x02
   db   0x92
   db   0x00
   db   0x00
EGDT:

;TASK TABLE strings
TaskTableTop: db '==TASK TABLE============================================'
,13,10,0
BsLoadMsg: db '= Load Bootstrap ... SUCCESSFUL =',13,10,0
OpenA20Msg: db '= Open A20 Gate ... SUCCESSFUL =',13,10,0
TaskTableBot: db '=================================================
=======',13,10,0

start:
mov si,TaskTableTop
call PrintMsg
mov si,BsLoadMsg
call PrintMsg ;message to print out success

call OpenA20 ;open A20 gate for more than 1M
mov si,OpenA20Msg
call PrintMsg

mov si,TaskTableBot ;print out the organization table of tasks
call PrintMsg

;HERE STARTS GDT AND PMODE CODE...****************
mov      ax,0x2000
mov      ds,ax

xor      ax,ax      ;--Write the GDT-- Write it to segment zero
mov      es,ax      ;zero out to put in ES
mov      si,GDT      ;si points to GDT
xor      di,di      ;zero out DI to offset zero
mov      cx,EGDT-GDT   ;the size of the GDT
rep      movsb

lgdt   [GDTR]
lidt   [IDTR]

mov      eax,cr0      ;read from control register (CR) 0
or      al,0x01      ;Set bit 0 (PE)
mov      cr0,eax      ;put the value back to enable PMode
jmp      0x28:$+5   ;set CS to new PMode value
;END OF GDT AND PMODE CODE****************

;------------------------------------------------
jmp $
;------------------------------------------------

;----------------PRINTMSG---------------------------------------
;Function to print a message to the screen at
;memory location in [si]
PrintMsg:
mov ah,0x0E ;teletype mode
mov bh,0x00 ;page
char_loop:
lodsb ;mov [si] into al and inc si
or al,al ;set zero flag if al = 0
jz break ;if al = 0, break from function
int 0x10 ;print out character with BIOS function
jmp char_loop ;next character
break:
ret

;----------------CLEARSCR---------------------------------------
;Function to clear the screen for new output
ClearScr:
mov ah,0x02 ;specify int 10,2
mov bh,0x00 ;page number 0
mov dh,0x00 ;row 0
mov dl,0x00 ;column 0
int 0x10 ;call BIOS function to set cursor position at top

mov bx,0B800h ;beginning of video memory for char output
mov es,bx ;move it to extra segment (es)
mov bx,0 ;put bx back to 0 for later use
clear_loop:
mov byte [es:bx],0 ;char ' ' to be printed (clear screen)
inc bx ;increment bx for next instruction in offset bx
mov byte [es:bx],7 ;code 7 prints out what's in previous byte
inc bx ;increment bx for next instruction in offset bx
cmp bx,4000 ;compare to see if 2000 squares were cleared
jne clear_loop ;next clear char call
ret ;fall through and return

;----------------OPENA20----------------------------------------
;Function to open the A20 gate to allow
;more than 1M of memory to be used in PMode
OpenA20:
in al,0x92
or al,0x02
out 0x92,al
ret

This is my WHOLE bootstrap code, but where I labeled ";HERE STARTS GDT AND PMODE CODE" is where the code for the GDT and PMode begins (just so you don't have to search the whole thing to find the general area of the problem). Also, the variables and the descriptors are defined at the top (the labels, GDTR and GDT and EGDT is the ending of from GDT - EGDT).

So, I still can't seem to find the problem. Can you? Thanks!
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Problem setting up GDT

Post by Pype.Clicker »

According to what i see from the sourcecode, your GDTR register isn't initialised before you start : you have GDT.base = 0x00000000, (the address of the realmode interrupt table).

There should be

mov eax, GDT ; or offset GDT, depending on you're using nasm/tasm
xor ebx,ebx
mov bx, ds ; assuming GDT is ds-based
shl ebx,4
add eax,ebx
mov [GDTR+2],eax

somewhere :-)
f2

Re:Problem setting up GDT

Post by f2 »

I figured it out (I forgot to clear the interrupts flag with CLI before I loaded the IDT into memory). But, what exactly are you saying? I don't understand your reasoning...
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Problem setting up GDT

Post by Pype.Clicker »

reasonning:
you are obviously moving your GDT to physical address 0x0000000 where the IVT (real mode interrupts) usually stands. This means
1) never come back to real mode
2) won't be able to use any V86 services (interrupts table is lost forever: all the job done by the BIOS is definitively unusable)

This is not really a trouble if you don't plan to use any of the BIOS services once you're in PMODE, but i used to think it's a good think to have an 'escape route' in your kernel that can bring you back to real mode for debugging, respawning, etc rather than letting the CPU reboot at the first problem, so my approach would be
1) to adjust the BASE field of GDTR to your actual GDT location (or at least to copy it somewhere else than in a well-known reserved area) , or
2) if your setup code for pmode is likely to be erased by something else, move it to a definitive location that you know to be *free* and *document* it (nothing in your code tells where your GDT is! ASM code should have 1 line of comments for 2 lines of code :)
f2

Re:Problem setting up GDT

Post by f2 »

I guess I'm still having problems with the code. When it starts up, it just reboots the computer again. The CLI didn't help. So, what is causing this? Is the problem that my GDT is at memory location 0x00000000? If not, what IS the problem with my code?
DynatOS

Re:Problem setting up GDT

Post by DynatOS »

If your GDT is setup in real mode, as I have been told to do so many a'time, writting your GDT at 0000:0000 overwrites the IVT (real mode version of the IDT) which extends from 0000:0000 to 0000:03FF and provides interrupt access (Video/HD/etc...) in real mode. I suggest you build your GDT initially at 0000:0400 with only 3 entries (1 null, 1 ring-0 code, 1 ring-0 data) and then when you make the switch over to protected and only then you can write to the beginning of memory.

As for the initialization code... are you loading the GDTR via LGDT from a variable location in C or an offset in Assembly... if so do you have the proper origin (code base offset) defined? Do you have an short jump followed by a far-jump to a memory location/label/pointer immediately after changing the PE bit? The thing that stuck me for a whole week was the "origin" issue in NASM, I needed to define the appropriate code offset base of that the current code is intending to run on. Considering that your logical boot sector can be loaded to different parts of memory by different MBRs, I suggest you load the memory offset and limit of the GDT into memory itself and use that memory address for the LGDT instrruction.

Here is what my code looks like immediately following the the LGDT command (assembly)...
mov eax,cr0
or al,0x01
mov cr0,eax
;NO CODE CAN BE BETWEEN THESE TWO INSTRUCTIONS
jmp CLEAR
CLEAR:
DW 0xEA66 ;Far-jump operand w/32-bit override
DD 0x00002000 ;32-bit offset to jump to
DW 0x0008 ;16-bit GDT segment selector (0x0008 is the 2nd descriptor)

You can replace the "DD 0x00002000" with a label like this...
DD 32BIT
DW 0x0008

32BIT:

ONLY IF THE CODE HAS BEEN ASSEMBLED/COMPILED PROPERLY AND IS AT THE SPECIFIED ORIGIN/BASE THAT HAS BEEN PREDEFINED!!! This is one of the biggest fubars that get most people in the beginning.

Lastly, I urge you to follow specifications for the MBR and LBR. The MBR should be impartial, it should load a specfied partition offset sector (LBR) into memory and transfer execution to it. The LBR should assume no knowledge of its current location and work from there.

Hope any of that helps ;)
Tim

Re:Problem setting up GDT

Post by Tim »

DynatOS wrote: I suggest you build your GDT initially at 0000:0400 with only 3 entries (1 null, 1 ring-0 code, 1 ring-0 data) and then when you make the switch over to protected and only then you can write to the beginning of memory.
No, don't put it at 0000:0400; that is the same as 0040:0000, which is the start of the BDA.

Put your GDT somewhere just after your code.
Here is what my code looks like immediately following the the LGDT command (assembly)...
mov eax,cr0
or al,0x01
mov cr0,eax
;NO CODE CAN BE BETWEEN THESE TWO INSTRUCTIONS
jmp CLEAR
CLEAR:
DW 0xEA66 ;Far-jump operand w/32-bit override
DD 0x00002000 ;32-bit offset to jump to
DW 0x0008 ;16-bit GDT segment selector (0x0008 is the 2nd descriptor)
Why do you need the 32-bit override? 0x2000 fits within 16 bits. Even if you did need to use a 32-bit offset, why would you need to write it as machine code? Any worthwhile assembler would assemble this correctly:

a32 jmp 8:2000h
Lastly, I urge you to follow specifications for the MBR and LBR. The MBR should be impartial, it should load a specfied partition offset sector (LBR) into memory and transfer execution to it. The LBR should assume no knowledge of its current location and work from there.
What's an LBR? A boot sector on a partition?

You could probably ignore the MBR and use the normal DOS one (assuming your OS boots from the primary partition). If not, use GRUB, and forget all about boot sectors and switching to protected mode.
DynatOS

Re:Problem setting up GDT

Post by DynatOS »

1. I'm not too keen on real mode addressing, I suppose NASM translates that 32-bit offset to a segment:offset format.

2. I don't assume anything, I don't assume that NASM is going to treat the instruction exactly like I want it to (which it hasn't in the past)... writing the instruction out manually is just the way I do it, even if it is 24 bits too big.

3. Yes, by LBR (Logical Boot Record) I mean the boot sector on a partition.
Tim

Re:Problem setting up GDT

Post by Tim »

NASM is designed not to mess with your assembly code and will only output exactly what you write. If you've found a place where it changes its output, you've found a bug.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Problem setting up GDT

Post by Pype.Clicker »

Guys, why are you re-inventing the screw-drawer for your re-invented wheel ? there are pmode initializers that are known to work and writing your own is as tricky as going to moon & back with nothing but your feet !
Pick up TRAN start32 or DJGPP pmode switcher or anything else that you can test (there is one in Intel docs and you have a BIOS function that does a real/protected/real switch for memory copying), but there are *many*many*many* things to think about when switching to PMODE and even code i've read in some books was wrong.

So just admit it's complex, and try to understand *how* someone else's code works *before* asking why your code don't :)
f2

Re:Problem setting up GDT

Post by f2 »

I think I've finally gotten my PMode switch and GDT code working. But, I still have the IDT which will come at a later time. For now, I have to write my own function to print out a string because I'm in PMode and I can't do BIOS interrupts in PMode.
Post Reply