为什么 GDT 在 x86_64 系统中不起作用?

问题描述 投票:0回答:1

我想在 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

enter image description here

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;
部分吗?是什么导致了问题,因为它仍然为零。

我需要帮助来解决问题。

编辑:forum.osdev.org

assembly gcc x86-64 osdev gdt
1个回答
0
投票

因此,根据上面的评论,以下更改将起作用

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;
© www.soinside.com 2019 - 2024. All rights reserved.