GDT Misconfigured?

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.
n0ax
Posts: 10
Joined: Thu May 01, 2014 11:43 pm

GDT Misconfigured?

Post by n0ax »

I am currently developing my own boot loader, and continue to get the error "(unk. ctxt) jmp far 000a:0058" in bochs, when I attempt to relocate using the "descriptor:offset" memory model. my GDT looks like this and I am able to successfully enter protected mode. The jump code is "jmp gdt_code_descriptor_table:late_init"

Code: Select all

gdt_code_descriptor_table:	
	dw 0xFFFF		;[lowest byte of mem]
	dw 0x0			;[lowest next byte(base)]
	db 0x0			;[lowest base addres(middle, base)]
	db 10011010b		;[segment permissions look at sec,2]
	db 11001111b 		;[granuality]"alighment" data at sec,3]
	db 0			;[high base]
gdt_data_descriptor_table:
	dw 0xFFFF		;Same!
	dw 0x0			;Same!
	db 0x0			;Same!
	db 10010010b		;only type bit different
	db 11001111b		;Same!
	db 0			;Same!
If anyone could shed light on this issue? perhaps this issue is quite common or I am just being an idiot.
-N0aX
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: GDT Misconfigured?

Post by neon »

The jump code is "jmp gdt_code_descriptor_table:late_init
I think you misunderstood selector:offset addressing. The selector is an offset in the GDT; you cannot obtain that from gdt_code_descriptor_table. For example, if the code descriptor is at byte offset 8 as is most cases (right after the mandatory null descriptor - I assume you already have this), you should be using jmp 8:late_init instead. Similarly the data segments should be set to the data selector 8 bytes after code selector; probably 0x10.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
n0ax
Posts: 10
Joined: Thu May 01, 2014 11:43 pm

Re: GDT Misconfigured?

Post by n0ax »

Oh that clears allot up, thanks
but now i get "check_cs(0x0008): not a valid code segment !", accompanied by a tripple fault. Is it still adressing in the "segment:offset" mode or am i loading the gdt incorrectly so the code segment described in the gdt is somewhere else in the gdt or just invalid?
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: GDT Misconfigured?

Post by neon »

Hello,

Can you post the complete GDT structure and the code to jump into protected mode being used? I have to assume the provided GDT is not the entire GDT do to it being invalid; missing the null descriptor. If the provided GDT is indeed the entire GDT; then that would indeed be the problem.

That is, your complete GDT and GDTR register structure should be,

Code: Select all

;
; global descriptor table
;
gdt_start:
   ;
   ; null descriptor
   ;
   dd 0
   dd 0
   ;
   ; code descriptor - offset 8
   ;
   dw 0xFFFF      ;[lowest byte of mem]
   dw 0x0         ;[lowest next byte(base)]
   db 0x0         ;[lowest base addres(middle, base)]
   db 10011010b      ;[segment permissions look at sec,2]
   db 11001111b       ;[granuality]"alighment" data at sec,3]
   db 0         ;[high base]
   ;
   ; data descriptor offset 0x10
   ;
   dw 0xFFFF      ;Same!
   dw 0x0         ;Same!
   db 0x0         ;Same!
   db 10010010b      ;only type bit different
   db 11001111b      ;Same!
   db 0         ;Same!
gdt_end :
;
; load into gdtr with ldgt [gdtr_descr] later
;
gdtr_descr :
  dw gdt_end - gdt_start - 1
  dd gdt_start
Then you can enter protected mode like so,

Code: Select all

cli
lgdt [gdtr_descr]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 8:pmode_entry

bits 32

pmode_entry :
  ; 32 bit protected mode code here
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
n0ax
Posts: 10
Joined: Thu May 01, 2014 11:43 pm

Re: GDT Misconfigured?

Post by n0ax »

Here's my whole GDT. and I am indicated by Bochs to be in protected mode, also the a20 gate is also indicated to be enabled.

Code: Select all

gdt_stub_begin:			;used to get size (requires double null padding)
	dd 0
	dd 0
        ;;gdt_code_descriptor_table:
	dw 0xFFFF		;[lowest byte of mem]
	dw 0x0			;[lowest next byte(base)]
	db 0x0			;[lowest base address(middle, base)]
	db 10011010b		;[segment permissions look at sec,2]
	db 11001111b 		;[granularity]" alignment" data at sec,3]
	db 0			;[high base]
	;;gdt_data_descriptor_table
	;; 0x10
	dw 0xFFFF		;Same!
	dw 0x0			;Same!
	db 0x0			;Same!
	db 10010010b		;only type bit different
	db 11001111b		;Same!
	db 0			;Same!
	;; (sec,2) the access byte is divided into 8 bits (obviously), each describing access and restrictions of the segment. these can be encoded using binary, also remember little endian so its read "left-right
	;; (0)-limit address (8 bytes), the highest accessible address
	;; (1)-base address (8 bytes), lowest possible address
	;; (2)-middle address (1/2/4/8 bytes), middle address splits
	;; (3)-access restrictions, restricts segment setting up permissions, which are broken into (bit,0)=Access bit for virtual memory, (bit,1)=isread/write/execute allowed?, (bit,2)=expansion direction  (bit,3)=code or data descriptor (0/1), (bit 4)=system or code/data, (bit,5-6) protection ring, (2 bits) binary (0=0, 0011=3 etc, (0=kernel), (bit,7)(is-in-mem), for virtual memory
gdt_stub_end:	
gdt_point_desc:
	dw gdt_stub_end - gdt_stub_begin - 1 ;this is preprocessed
	dd gdt_stub_begin
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: GDT Misconfigured?

Post by Bender »

What offset is the above code loaded? If you haven't inserted an ORG or told the asssembler that the code needs to be loaded at a specific offset, It'll assume it's 0, if you load it at any offset other than 0, all the internal label references will be messed up.
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
n0ax
Posts: 10
Joined: Thu May 01, 2014 11:43 pm

Re: GDT Misconfigured?

Post by n0ax »

We'll the code is loaded to 0x2000, this is after 1bl has loaded it from the floppy using bios interrupts. I haven't thought about inserting an org for alignment, I'll try this when I get home
n0ax
Posts: 10
Joined: Thu May 01, 2014 11:43 pm

Re: GDT Misconfigured?

Post by n0ax »

Ok the org definitely worked and I am now aligned correctly, but now bochs throws a new error at me "fetch_raw_descriptor: GDT: index (f) 1 > limit (0)", is my gdt not alligned correctly?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GDT Misconfigured?

Post by Combuster »

Bochs wrote:limit (0)
Learn to read?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
n0ax
Posts: 10
Joined: Thu May 01, 2014 11:43 pm

Re: GDT Misconfigured?

Post by n0ax »

Ok, but why is the limit set to 0?
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: GDT Misconfigured?

Post by JAAman »

either:
1) you set the limit to 0
2) wrong GDTR is being loaded (passing the wrong address to LGDT)
3) you haven't loaded the GDT yet (trying to load the segments before your LGDT)


number 3 is unlikely, since the GDTR will likely still contain values from the BIOS GDT, which shouldn't have a 0 limit
number 1 should be easy to check
leaving #2 as the only possibility: check the manuals carefully to ensure you are passing the address correctly
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: GDT Misconfigured?

Post by neon »

Hello,

Unfortunately the cause can be the result of a number of different things; you would greatly benefit with the use of a debugger (particularly Bochs debugger) to validate the state of the in memory GDT (info gdt command) after installing it as well as what happens right after the far jump to protected mode code. If you are using the provided GDT correctly (see my example above), and keep hardware interrupts disabled right before setting protected mode (do not use STI in the protected mode code at this time) and you use bits 32 properly, then the problem might be (1) alignment or (2) assembler output, or (3) environment problem (build system; invalid or incomplete in memory state [i.e. boot record not loading the image in full], etc.)

It might also be a good idea to align the 32 bit code segment to a dword boundary as well as the GDT and GDTR structure itself. These should not be necessary but are recommended for performance reasons.

In short, you might need to use your debugger here and keep a close watch on the GDT and what happens after the far jump to long mode. My guess is that it is jumping into garbage land. Only way to verify is with your debugger.

Feel free to provide more code if you are not sure; particularly your ORG directives, how your segment registers are set up during initialization and how you use them with respect to ORG directive, how you currently define and install the GDT, how you enter protected mode and what the protected mode code currently does.

As of current, the provided code is perfectly fine so the actual problem lies elsewhere.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
n0ax
Posts: 10
Joined: Thu May 01, 2014 11:43 pm

Re: GDT Misconfigured?

Post by n0ax »

Here is my full Bochs debug output, the fault occurs when I attempt to jump to the 32 bit code. I am using an [ORG 0x1000] and the data segment is set to 0. I am guessing this fault is due to alignment, also the gdt is alligned to 4 bytes

Code: Select all

00014040328i[BIOS ] Booting from 0000:7c00
00014215477i[FDD  ] partial read() on floppy image returns 115/512
00014260276e[CPU0 ] fetch_raw_descriptor: GDT: index (17) 2 > limit (0)
00014260276e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00014260276e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00014260276i[CPU0 ] CPU is in protected mode (active)
00014260276i[CPU0 ] CS.mode = 16 bit
00014260276i[CPU0 ] SS.mode = 16 bit
00014260276i[CPU0 ] EFER   = 0x00000000
00014260276i[CPU0 ] | EAX=60000010  EBX=00000000  ECX=00090000  EDX=00000000
00014260276i[CPU0 ] | ESP=0000ffc6  EBP=00000000  ESI=000e0025  EDI=0000ffac
00014260276i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00014260276i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00014260276i[CPU0 ] |  CS:1000( 0004| 0|  0) 00010000 0000ffff 0 0
00014260276i[CPU0 ] |  DS:1000( 0005| 0|  0) 00010000 0000ffff 0 0
00014260276i[CPU0 ] |  SS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00014260276i[CPU0 ] |  ES:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00014260276i[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00014260276i[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00014260276i[CPU0 ] | EIP=0000004f (0000004f)
00014260276i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00014260276i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
(0).[14260276] [0x00000001004f] 1000:000000000000004f (unk. ctxt): mov ds, ax                ; 8ed8
00014260276e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00014260276i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00014260276i[CPU0 ] cpu hardware reset
00014260276i[APIC0] allocate APIC id=0 (MMIO enabled) to 0x0000fee00000
00014260276i[CPU0 ] CPUID[0x00000000]: 00000005 756e6547 6c65746e 49656e69
00014260276i[CPU0 ] CPUID[0x00000001]: 00000633 00010800 00002008 1fcbfbff
00014260276i[CPU0 ] CPUID[0x00000002]: 00410601 00000000 00000000 00000000
00014260276i[CPU0 ] CPUID[0x00000003]: 00000000 00000000 00000000 00000000
00014260276i[CPU0 ] CPUID[0x00000004]: 00000000 00000000 00000000 00000000
00014260276i[CPU0 ] CPUID[0x00000005]: 00000040 00000040 00000003 00000020
00014260276i[CPU0 ] CPUID[0x80000000]: 80000008 00000000 00000000 00000000
00014260276i[CPU0 ] CPUID[0x80000001]: 00000000 00000000 00000101 2a100000
00014260276i[CPU0 ] CPUID[0x80000002]: 20202020 20202020 20202020 6e492020
00014260276i[CPU0 ] CPUID[0x80000003]: 286c6574 50202952 69746e65 52286d75
00014260276i[CPU0 ] CPUID[0x80000004]: 20342029 20555043 20202020 00202020
00014260276i[CPU0 ] CPUID[0x80000005]: 01ff01ff 01ff01ff 40020140 40020140
00014260276i[CPU0 ] CPUID[0x80000006]: 00000000 42004200 02008140 00000000
00014260276i[CPU0 ] CPUID[0x80000007]: 00000000 00000000 00000000 00000000
00014260276i[CPU0 ] CPUID[0x80000008]: 00003028 00000000 00000000 00000000
2BL.s (Beginning when jumped too)

Code: Select all

[bits 16]                                                                                                      
[org 0x1000]                                                                                                   
mov ax, 0                                                                                              
mov ds, ax                                                                                                     
mov es, ax                                                                                                     
jmp init_aa_2bl                                                                                                
align 4     
1BL.s

Code: Select all

jmp 0x1000:0x0          ;jmp to 0x1000 and pass execution   
(if you need more code, just ask)
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: GDT Misconfigured?

Post by neon »

Hello,

Your jmp 0x1000:0x0 instruction in the boot record (1BL.s) implies that the program is running at 64k linear. Thus using org 0x1000 would be lying to the assembler; org just tells the assembler to base local labels from a common origin. If you really want to use it, it should be org 0x10000 but see below first.

I advise using org 0 and setting the segment registers to 0x1000 for consistency and to avoid any additional misuse; org should be avoided anyways.

Code: Select all

bits 16
org 0

cli
mov ax, 0x1000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
;; allocate stack space and set ss:sp -> stack
sti
jmp init_aa_2bl                                                                                                
align 4 
Also, please take note,

Code: Select all

jmp 0x1000:0x0          ;jmp to 0x1000 and pass execution
This actually jumps to 0x1000:0 which is 0x10000 linear not 0x1000. 0x1000 is the segment number, where each segment is aligned on 16 bytes. That is, you can convert it using segment:offset = segment*16+offset => 0x1000:0x0 = 0x1000*16+0= 0x10000 linear. This is why your org 0x1000 is lying to the assembler and resulting in errors. I'd advise doing the above and just use org 0 to avoid any farther problems.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Octocontrabass
Member
Member
Posts: 5604
Joined: Mon Mar 25, 2013 7:01 pm

Re: GDT Misconfigured?

Post by Octocontrabass »

neon wrote:Your jmp 0x1000:0x0 instruction in the boot record (1BL.s) implies that the program is running at 64k linear. Thus using org 0x1000 would be lying to the assembler; org just tells the assembler to base local labels from a common origin. If you really want to use it, it should be org 0x10000 but see below first.
This is wrong. If you use jmp 0x1000:0x0 to jump to the next section of code, that code should start with org 0. The assembler does not care about the linear address, just the offset within the segment.

There is no reason to avoid org, so long as you know how to use it correctly.
Post Reply