我想在 x86_64 操作系统中启用 GDT。我编写了以下代码来启用 GDT。
struct gdt_entry
{// 128 Bit
uint16_t limit_low; // Lower 16 bits of the segment limit
uint16_t base_low; // Lower 16 bits of the base address
uint8_t base_middle; // Next 8 bits of the base address
uint8_t access; // Access byte
uint8_t granularity; // Flags and upper limit
uint8_t base_high; // Next 8 bits of the base address
uint32_t base_upper; // Upper 32 bits of the base address
uint32_t reserved; // Reserved (must be zero)
} __attribute__((packed));
typedef struct gdt_entry gdt_entry_t;
// Structure for GDTR
struct gdtr {
uint16_t limit;
uint64_t base; // Use uint64_t for 64-bit systems
} __attribute__((packed));
typedef struct gdtr gdtr_t;
extern void gdt_flush(gdtr_t *gdtr_instance);
extern void reloadSegments();
gdt_entry_t gdt_entries[5];
gdtr_t gdtr_instance;
void gdt_setup( uint8_t idx, uint64_t base, uint32_t limit, uint8_t access, uint8_t granularity){
gdt_entries[idx].limit_low = limit & 0xFFFF; // 16 bit
gdt_entries[idx].base_low = base & 0xFFFF; // 16 bit
gdt_entries[idx].base_middle = (base >> 16) & 0xFF; // 8 bit
gdt_entries[idx].access = access;
gdt_entries[idx].granularity = (limit >> 16) & 0x0F; // Set limit : lower 4 bit
gdt_entries[idx].granularity |= granularity & 0xF0; // Set Flags : upper 4 bit
gdt_entries[idx].base_high = (base >> 24) & 0xFF; // 8 bit
gdt_entries[idx].base_upper = (base >> 32) & 0xFFFFFFFF; // 32 bit
gdt_entries[idx].reserved = 0; // 32 bit
}
void init_gdt(){
// index = 0, base = 0, limit = 0, access = 0, granularity = 0
gdt_setup(0, 0, 0x0, 0x0, 0x0); // null descriptor selector : 0x0
// index = 1, base = 0, limit = 0xFFFFFFFF, access = 0x9A = 154, granularity = 0xA0 = 160
gdt_setup(1, 0, 0xFFFFF, 0x9A, 0xA0); // kernel mode code segment, selector : 0x8
// index = 2, base = 0, limit = 0xFFFFFFFF, access = 0x92 = 146, granularity = 0xA0 = 160
gdt_setup(2, 0, 0xFFFFF, 0x92, 0xA0); // kernel mode data segment, selector : 0x10
// index = 3, base = 0, limit = 0xFFFFFFFF, access = 0xFA = 250, granularity = 0xA0 = 160
gdt_setup(3, 0, 0xFFFFF, 0xFA, 0xA0); // user mode code segment, selector : 0x18
// index = 4, base = 0, limit = 0xFFFFFFFF, access = 0xF2 = 242, granularity = 0xA0 = 160
gdt_setup(4, 0, 0xFFFFF, 0xF2, 0xA0); // user mode data segment, selector : 0x20
// Calculate the GDT limit and base address
gdtr_instance.limit = (uint16_t) (sizeof(gdt_entry_t) * 5 - 1);
gdtr_instance.base = (uint64_t) &gdt_entries;
gdt_flush((gdtr_t *) &gdtr_instance);
reloadSegments();
}
将GDT加载到GDTR寄存器中
section .text
global gdt_flush
gdt_flush:
MOV RAX, [RDI] ;Getting gdtr_instance pointer from externel gdt.c
LGDT [RAX]
RET
global reloadSegments
reloadSegments:
; Reload CS register:
PUSH 0x08 ; Push code segment to stack, 0x08 is a stand-in for your code segment
LEA RAX, [rel reload_CS] ; Load address of reload_CS into RAX, LEA (Load Effective Address),
PUSH RAX ; Push this value to the stack
LRETQ ; Perform a far return, RETFQ or LRETQ depending on syntax
reload_CS:
; Reload data segment registers
MOV AX, 0x10 ; 0x10 is a stand-in for your data segment
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
RET
完整代码在这里。
reloadSegments 函数导致系统崩溃。我还检查了 GDB,我看到虽然我在
gdt_setup(4, 0, 0xFFFFF, 0xF2, 0xA0);
函数中输入了 init_gdt()
,但没有第 4 个条目,而且我也看到了不必要的第 255 个条目,尽管我使用了 gdtr_instance.limit = (uint16_t) (sizeof(gdt_entry_t) * 5 - 1);
。
我看到了以下 GDB 输出:
gdt_setup(idx=0 '\000', base=0, limit=0, access=0 '\000', granularity=0 '\000') at src/x86_64/gdt.c :19
gdt_setup(idx=255 '\377', base=18446603339441663968, limit=2147491364, access=255 '\377', granularity=119 'w') at src/x86_64/gdt.c :30
gdt_setup(idx=1 '\001', base=0, limit=4294967295, access=154 '\232', granularity=160 '\240') at src/x86_64/gdt.c :41
gdt_setup(idx=255 '\377', base=18446603339441663968, limit=2147491364, access=255 '\377', granularity=181 '\265') at src/x86_64/gdt.c :44
gdt_setup(idx=2 '\002', base=0, limit=4294967295, access=146 '\222', granularity=160 '\240') at src/x86_64/gdt.c :19
gdt_setup(idx=3 '\003', base=0, limit=4294967295, access=250 '\372', granularity=160 '\240') at src/x86_64/gdt.c :19
gdt_setup(idx=255 '\377', base=18446603339441663968, limit=2147491364, access=255 '\377', granularity=243 '\363') at src/x86_64/gdt.c :32
Qemu 日志显示
Triple fault
。
Qemu 日志:
CPU Reset (CPU 0)
RAX=ffffffff80000010 RBX=0000000000000000 RCX=00000000000000c0 RDX=0000000000000000
RSI=0000000000000000 RDI=ffffffff80006990 RBP=ffff8000bff36fe0 RSP=ffff8000bff36fc8
R8 =00000000000000c0 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=ffffffff80003445 RFL=00000082 [--S----] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0030 0000000000000000 00000000 00009300 DPL=0 DS [-WA]
CS =0028 0000000000000000 00000000 00209b00 DPL=0 CS64 [-RA]
SS =0030 0000000000000000 00000000 00009300 DPL=0 DS [-WA]
DS =0030 0000000000000000 00000000 00009300 DPL=0 DS [-WA]
FS =0030 0000000000000000 00000000 00009300 DPL=0 DS [-WA]
GS =0030 0000000000000000 00000000 00009300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 00000000 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 0000000000000000 00000000
IDT= 0000000000000000 00000000
CR0=80010011 CR2=0000000000000000 CR3=00000000bff26000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=ffffffff8000694c CCD=ffffffff8000698c CCO=ADDQ
EFER=0000000000000d00
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=0000000000000000 0000000000000000 XMM01=0000000000000000 0000000000000000
XMM02=0000000000000000 0000000000000000 XMM03=0000000000000000 0000000000000000
XMM04=0000000000000000 0000000000000000 XMM05=0000000000000000 0000000000000000
XMM06=0000000000000000 0000000000000000 XMM07=0000000000000000 0000000000000000
XMM08=0000000000000000 0000000000000000 XMM09=0000000000000000 0000000000000000
XMM10=0000000000000000 0000000000000000 XMM11=0000000000000000 0000000000000000
XMM12=0000000000000000 0000000000000000 XMM13=0000000000000000 0000000000000000
XMM14=0000000000000000 0000000000000000 XMM15=0000000000000000 0000000000000000
7: v=03 e=0000 i=1 cpl=0 IP=0008:00000000000efb0a pc=00000000000efb0a SP=0010:0000000000000fc8 env->regs[R_EAX]=00000000000f6106
EAX=000f6106 EBX=000f3e0a ECX=00000000 EDX=00000cf9
ESI=00000000 EDI=00100000 EBP=00000000 ESP=00000fc8
EIP=000efb0a EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 000f6180 00000037
IDT= 000f61be 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000f61c8 CCD=00009e34 CCO=SUBL
EFER=0000000000000000
check_exception old: 0xffffffff new 0xd
8: v=0d e=001a i=0 cpl=0 IP=0008:00000000000efb0a pc=00000000000efb0a SP=0010:0000000000000fc8 env->regs[R_EAX]=00000000000f6106
EAX=000f6106 EBX=000f3e0a ECX=00000000 EDX=00000cf9
ESI=00000000 EDI=00100000 EBP=00000000 ESP=00000fc8
EIP=000efb0a EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 000f6180 00000037
IDT= 000f61be 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000f61c8 CCD=00009e34 CCO=SUBL
EFER=0000000000000000
check_exception old: 0xd new 0xd
9: v=08 e=0000 i=0 cpl=0 IP=0008:00000000000efb0a pc=00000000000efb0a SP=0010:0000000000000fc8 env->regs[R_EAX]=00000000000f6106
EAX=000f6106 EBX=000f3e0a ECX=00000000 EDX=00000cf9
ESI=00000000 EDI=00100000 EBP=00000000 ESP=00000fc8
EIP=000efb0a EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
CS =0008 00000000 ffffffff 00cf9b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT= 000f6180 00000037
IDT= 000f61be 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=000f61c8 CCD=00009e34 CCO=SUBL
EFER=0000000000000000
check_exception old: 0x8 new 0xd
Triple fault
我从
here创建
gdt_entry
结构。我不明白是什么导致了问题?
我不需要 gdt_entry_t 结构中的
uint32_t base_upper;
和 uint32_t reserved;
部分吗?是什么导致了问题,因为它仍然为零。
我需要帮助来解决问题。
因此,根据上面的评论,以下更改将起作用
struct gdt_entry
{// 64-Bit not 128 Bit
uint16_t limit_low; // Lower 16 bits of the segment limit
uint16_t base_low; // Lower 16 bits of the base address
uint8_t base_middle; // Next 8 bits of the base address
uint8_t access; // Access byte
uint8_t granularity; // Flags and upper limit
uint8_t base_high; // Next 8 bits of the base address
} __attribute__((packed));
typedef struct gdt_entry gdt_entry_t;