Page 1 of 2
GDT Misconfigured?
Posted: Mon May 05, 2014 8:34 pm
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
Re: GDT Misconfigured?
Posted: Mon May 05, 2014 9:11 pm
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.
Re: GDT Misconfigured?
Posted: Mon May 05, 2014 9:28 pm
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?
Re: GDT Misconfigured?
Posted: Mon May 05, 2014 10:02 pm
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
Re: GDT Misconfigured?
Posted: Tue May 06, 2014 6:30 am
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
Re: GDT Misconfigured?
Posted: Tue May 06, 2014 7:01 am
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.
Re: GDT Misconfigured?
Posted: Tue May 06, 2014 10:19 am
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
Re: GDT Misconfigured?
Posted: Tue May 06, 2014 4:41 pm
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?
Re: GDT Misconfigured?
Posted: Wed May 07, 2014 12:21 am
by Combuster
Bochs wrote:limit (0)
Learn to read?
Re: GDT Misconfigured?
Posted: Wed May 07, 2014 8:51 pm
by n0ax
Ok, but why is the limit set to 0?
Re: GDT Misconfigured?
Posted: Thu May 08, 2014 7:07 am
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
Re: GDT Misconfigured?
Posted: Thu May 08, 2014 7:17 pm
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.
Re: GDT Misconfigured?
Posted: Fri May 09, 2014 4:04 pm
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)
Re: GDT Misconfigured?
Posted: Fri May 09, 2014 7:47 pm
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.
Re: GDT Misconfigured?
Posted: Fri May 09, 2014 9:15 pm
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.