I have always struggled with the GDT (and IDT). My current understanding:
GRUB boots into 32-bit protected mode, and the documentation seems to imply that interrupts aren't enabled. Just to be safe, I disable them before doing anything with the GDT or IDT.
The GDT describes where certain things are. For my purposes right now, it holds a null record, a kernel code record, a kernel data record, a user code record, and a user data record. All code and data records start at 0x00000000u and are sized 0xFFFFFFFFu, so they are a flat memory model. For now, no IDT is used.
The exact format of the access byte for each GDT entry is problematic, specifically bit 3 (fourth). At here and here the bit is described so that 1 is code/data selector, 0 is system (TSS, LDT, or Gate). However, elsewhere on that second page and also on this one, the bit is said to be 1 for code selector, 0 for data selector. These are contradictory. For my code, I assumed that the 1=code/data, 0=system information is correct. It would be great if someone could clarify.
Since GDT entries are a pain, I made a C++ class that handles it. See here. The five entries are set up and loaded by:
Code: Select all
static EntryGDT gdt_entries[5];
void load_gdt(void) {
uint32_t base = (uint32_t)(&gdt_entries); //The linear address of the first gdt_entry_t struct.
uint16_t limit = sizeof(EntryGDT)*5 - 1; //The upper 16 bits of all selector limits. Size of table minus 1. sizeof(EntryGDT) is 8 (I checked)
EntryGDT::construct(gdt_entries, 0x00000000u, 0u, EntryGDT::Access::AccessByte:: get_null()); //Null segment
EntryGDT::construct(gdt_entries+1, 0x00000000u,0xFFFFFFFFu, EntryGDT::Access::AccessByte::get_selector_datacode(0)); //Kernel code segment
EntryGDT::construct(gdt_entries+2, 0x00000000u,0xFFFFFFFFu, EntryGDT::Access::AccessByte::get_selector_datacode(0)); //Kernel data segment
EntryGDT::construct(gdt_entries+3, 0x00000000u,0xFFFFFFFFu, EntryGDT::Access::AccessByte::get_selector_datacode(3)); //User code segment
EntryGDT::construct(gdt_entries+4, 0x00000000u,0xFFFFFFFFu, EntryGDT::Access::AccessByte::get_selector_datacode(3)); //User data segment
gdt_lgdt(base,limit);
}
Code: Select all
[GLOBAL gdt_lgdt]
gdt_ptr:
DW 0 ;For limit storage
DD 0 ;For base storage
gdt_lgdt:
mov eax, [esp + 4]
mov [gdt_ptr + 2], eax
mov ax, [esp + 8]
mov [gdt_ptr], ax
lgdt [gdt_ptr]
ret
Code: Select all
[GLOBAL reload_segments]
;See http://wiki.osdev.org/Segmentation
;The 0x08 is the offset of the kernel code selector in the GDT (the second 8-byte entry, following the null-entry)
;The 0x10 is the offset of the kernel data selector in the GDT (the third 8-byte entry, following the code selector at 0x08)
reload_segments:
; Reload CS register containing code selector:
jmp 0x08:reload_CS
reload_CS:
; Reload data segment registers:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
ret
I don't know what the "branch_far64" line means, but I find the interrupt lines immediately after bizarre, since interrupts weren't enabled! What's going on? What are the problems with my understanding?00018064222i[BIOS ] Booting from 07c0:0000
00018072558i[MEM0 ] allocate_block: block=0x1 used 0x3 of 0x20
00034919314i[MEM0 ] allocate_block: block=0x1e used 0x4 of 0x20
00055800305e[CPU0 ] branch_far64: RIP > limit
00055800305e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00055800305e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00055800305i[CPU0 ] CPU is in protected mode (active)
00055800305i[CPU0 ] CS.mode = 32 bit
00055800305i[CPU0 ] SS.mode = 32 bit
00055800305i[CPU0 ] EFER = 0x00000000
00055800305i[CPU0 ] | EAX=00000000 EBX=00184120 ECX=00000002 EDX=00000003
00055800305i[CPU0 ] | ESP=0018410c EBP=00000000 ESI=00010000 EDI=00000000
00055800305i[CPU0 ] | IOPL=0 ID vip vif ac vm RF nt of df if tf sf zf AF pf cf
00055800305i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00055800305i[CPU0 ] | CS:0010( 0002| 0| 0) 00000000 ffffffff 1 1
00055800305i[CPU0 ] | DS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00055800305i[CPU0 ] | SS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00055800305i[CPU0 ] | ES:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00055800305i[CPU0 ] | FS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00055800305i[CPU0 ] | GS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00055800305i[CPU0 ] | EIP=001005a4 (001005a4)
00055800305i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00055800305i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00055800305i[CPU0 ] 0x00000000001005a4>> jmp far 0008:001005ab : EAAB0510000800
00055800305e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00055800305i[SYS ] bx_pc_system_c::Reset(HARDWARE) called
00055800305i[CPU0 ] cpu hardware reset
Thanks,