Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C GDT段重新加载失败_C_Bochs_Gdt - Fatal编程技术网

C GDT段重新加载失败

C GDT段重新加载失败,c,bochs,gdt,C,Bochs,Gdt,我正在用c为x86平台编写一个小内核,但是在加载gdt和重新加载段选择器时遇到了问题 我正在使用bochs测试我的内核 问题是,当我加载GDT但不重新加载段选择器时,我可以停止程序,键入info GDT,并得到一个好结果: 当我不加载GDT时: <bochs:2> info gdt Global Descriptor Table (base=0x00000000000010b0, limit=32): GDT[0x0000]=??? descriptor hi=0x00000000,

我正在用c为x86平台编写一个小内核,但是在加载gdt和重新加载段选择器时遇到了问题

我正在使用bochs测试我的内核

问题是,当我加载GDT但不重新加载段选择器时,我可以停止程序,键入
info GDT
,并得到一个好结果: 当我不加载GDT时:

<bochs:2> info gdt
Global Descriptor Table (base=0x00000000000010b0, limit=32):
GDT[0x0000]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x0008]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x0010]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x0018]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
<bochs:3> 
<bochs:2> info gdt
Global Descriptor Table (base=0x00000000001022a0, limit=48):
GDT[0x0000]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x0008]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, 32-bit
GDT[0x0010]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write
GDT[0x0018]=Code segment, base=0x00000000, limit=0x00000fff, Execute-Only, Non-Conforming, 32-bit
GDT[0x0020]=Data segment, base=0x00000000, limit=0x00000fff, Read-Only
GDT[0x0028]=??? descriptor hi=0x00000000, lo=0x00000000
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
<bochs:3> 
这样,当我再次输入
info-gdt
时,它会给我一个非常大的数组, 它甚至不适合我的终端回滚功能。 以下是最后几行:

GDT[0xffd8]=??? descriptor hi=0x72670074, lo=0x64696c61
GDT[0xffe0]=16-Bit TSS (available) at 0x6c65725f, length 0xc6275
GDT[0xffe8]=Data segment, base=0x5f726700, limit=0x0002636f, Read-Only, Expand-down, Accessed
GDT[0xfff0]=Data segment, base=0x00657266, limit=0x00086572, Read/Write, Accessed
GDT[0xfff8]=Data segment, base=0x675f6275, limit=0x00057267, Read/Write
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
它说我想访问GDT之外的数据

以下是我迄今为止编写的代码:

enum SEG_类型{
//资料
SEG_类型_DRO=0b0000,
SEG_类型_DRW=0b0010,
SEG_类型_DROE=0b0100,
SEG_类型_DRWE=0b0110,
//代码
SEG_类型_CEO=0b1000,
SEG类型CER=0b1010,
SEG_类型_CEOC=0b1100,
SEG_类型_CERC=0b1110,
};
枚举SEG_AC{
SEG_AC_内核=0b11,
SEG_AC_用户=0b00,
};
void gdt_entry_init(struct gdt_entry*entry、u32 base、u32 limit、枚举SEG_类型、枚举SEG_AC访问权限){
//基址
条目->基础0\u 15=基础;
条目->基础16\u 23=基础>>16;
条目->基础24\u 31=基础>>24;
//极限
输入->限制\u 0\u 15=限制;
条目->限制\u 16\u 19=限制>>16;
//段类型
条目->类型=类型;
//访问权
条目->dpl=访问权限;
//AVL
条目->avl=0;
//默认操作设置为32位
条目->数据库=1;
//代码段
输入->l=0;
//出席(总是出席)
输入->p=1;
//描述符类型(代码或数据)
输入->s=1;
//粒度(以4KB增量启用)
输入->g=1;
}
结构gdt_条目{
u32限值(0)15:16 ;;
u32基值(0)15:16 ;;
u32基_16_23:8;
u32型:4例;
u32s:1;
u32 dpl:2;
u32p:1;
u32限值_16_19:4;
u32平均值:1;
U32L:1;
u32db:1;
u32g:1;
u32基_24_31:8;
}_uuu属性_uuu((压缩));
结构gdt\u r{
u16极限;
u32碱基;
}_uuu属性_uuu((压缩));
结构gdt_条目gdt[6];
void gdt_init(){
//空段
struct gdt_entry null_entry={0};
gdt[0]=空_项;
//内核代码段
gdt_条目_init(gdt+1、0x0、0xFFFFFF、SEG_类型_CER、SEG_AC_内核);
//内核数据段
gdt_条目_init(gdt+2,0x0,0xFFFFFFFF,SEG_类型_DRW,SEG_AC_内核);
//用户代码段
gdt_条目_init(gdt+3,0x0,0x0,SEG_类型_CEO,SEG_AC_用户);
//用户数据段
gdt_条目_init(gdt+4,0x0,0x0,SEG_类型_DRO,SEG_AC_用户);
//TSS
gdt[5]=空_项;
结构gdt_r gdtr;
gdtr.base=(u32)gdt;
gdtr.limit=sizeof(gdt);
asm易失性(“lgdt%0\n”
:/*无输出*/
:“m”(gdtr)
:“记忆”);
//0x10是内核数据段的地址
asm volatile(“movw 0x10,%%ax\n”:;
asm易失性(“movw%%ax,%%ds\n”:;
asm易失性(“movw%%ax,%%fs\n”:;
asm易失性(“movw%%ax,%%gs\n”:;
asm易失性(“movw%%ax,%%ss\n”:;
//0x8是内核代码段的地址
asm易失性(“pushl 0x8\n”
“pushl$1f\n”
“lret\n”
“1:\n”
:/*无输出*/);
}

如果你们知道这是怎么回事。

结果是一个非常聪明的人发现了问题:

  • 在编写内联asm时,我错过了直接值前面的
    $
  • //0x10是内核数据段的地址
    asm volatile(“movw$0x10,%%ax\n”:;
    asm易失性(“movw%%ax,%%ds\n”:;
    asm易失性(“movw%%ax,%%fs\n”:;
    asm易失性(“movw%%ax,%%gs\n”:;
    asm易失性(“movw%%ax,%%ss\n”:;
    //0x8是内核代码段的地址
    asm易失性(“pushl$0x8\n”
    “pushl$1f\n”
    “lret\n”
    “1:\n”
    :/*无输出*/);
    
  • 我为内核和用户交换了权限,应该是正确的
  • enum SEG\u AC{
    SEG_AC_KERNEL=0b00,
    SEG_AC_USER=0b11,
    };
    
    这不是编写gcc内联asm的安全方法。编译器不承诺在
    asm
    语句之间保留
    %ax
    或其他通用寄存器的内容。您必须将整个内容放在一个块中,并将所有内容被修改的通用寄存器声明为clobber。请参阅以获取一些资源。
    GDT[0xffd8]=??? descriptor hi=0x72670074, lo=0x64696c61
    GDT[0xffe0]=16-Bit TSS (available) at 0x6c65725f, length 0xc6275
    GDT[0xffe8]=Data segment, base=0x5f726700, limit=0x0002636f, Read-Only, Expand-down, Accessed
    GDT[0xfff0]=Data segment, base=0x00657266, limit=0x00086572, Read/Write, Accessed
    GDT[0xfff8]=Data segment, base=0x675f6275, limit=0x00057267, Read/Write
    You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'