模拟Linus Torvalds:从头开始创建自己的操作系统(IV)

欢迎回到标题为“模仿Linus Torvalds”的系列文章。 今天我们将看到GDT。 首先,我们必须了解GDT是什么。 根据维基百科:

全局描述符表 or GDT 是由 英特尔 x86-系列处理器以 80286 为了定义程序执行期间使用的各种存储区的特性,包括基地址,大小和访问特权(如可执行性和可写性)

转换后的将是全局描述符表,该数据表是86以来在Intel x80286处理器中使用的数据结构,用于定义程序执行期间使用的各种内存区域的特征。

总而言之,如果我们使用的是Intel x86处理器,则必须定义GDT以正确使用内存。 我们不会做太多复杂的事情,我们将在表中定义3个条目:

  • 所有表都需要一个NULL条目。
  • 该部分的票 data,我们将使用最大值,即32位为4 GB。
  • 该部分的票 ,我们将使用最大值,即32位为4 GB。

如您所见,数据和代码将使用相同的空间。 好的,现在我们要实现它。 为此,我们将使用两种结构,第一种结构将负责包含指向GDT实际数据的指针。 第二个将是包含GDT条目的数组。 让我们先定义它们

struct Entry{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed));
struct Ptr{
uint16_t limit;
uint32_t base;
} __attribute__((packed));

您可能已经注意到结构末尾有一个奇怪的__attribute __((包装))。 这告诉GCC不要优化结构,因为我们想要的是将数据原样传递给处理器。 现在我们要制作一个功能来安装GDT。 在我们应该声明结构之前,现在我们将对其进行初始化。

struct ND::GDT::Entry gdt[3];
struct ND::GDT::Ptr gp;
void ND::GDT::Install()
{
gp.limit=(sizeof(struct ND::GDT::Entry)*3)-1;
gp.base=(uint32_t)&gdt;
}

这样我们就可以建立指向3输入表的指针。

如果使用64位进行编译,则很有可能在此处失败。 这是因为64位系统上的指针显然是64位的,这里我们使用32位类型。 使用-m32选项可能现在有所帮助
现在我们定义一个通用函数将数据放入输入中

void ND::GDT::SetGate(int num, uint32_t base, uint32_t limit, uint8_t access,uint8_t gran)
{
gdt[num].base_low=(base & 0xFFFF);
gdt[num].base_middle=(base >> 16) & 0xFF;
gdt[num].base_high=(base >> 24) & 0xFF;
gdt[num].limit_low=(limit & 0xFFFF);
gdt[num].granularity=(limit >> 16) & 0x0F;
gdt[num].granularity |= (gran & 0xF0);
gdt[num].access=access;
}

我们从安装函数中调用了3次

ND::GDT::SetGate(0,0,0,0,0); /* NULL segmente entry */
ND::GDT::SetGate(1,0,0xFFFFFFFF,0x9A,0xCF); /* 4 GiB for Code Segment */
ND::GDT::SetGate(2,0,0xFFFFFFFF,0x92,0xCF); /* 4 GiB for Data segment */

最后,我们必须告诉处理器我们有一个GDT,以便它可以加载它,并且在我们的例子中,用GRUB加载内核时,请覆盖GRUB GDT。 要加载GDT,在asm中有一条称为lgdt(或lgdtl,具体取决于语法)的指令,我们将使用它。

asm volatile("lgdtl (gp)");
asm volatile(
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movw %ax, %ss \n"
"ljmp $0x08, $next \n"
"next: \n"
);

好了,一旦完成此操作,我们的系统将已经具有GDT。 在下一章中,我们将看到IDT,该表与GDT非常相似,但存在中断。 我在GDT中添加了一些状态和确认消息,因此NextDivel现在看起来像这样:

NextDivel-GDT


发表您的评论

您的电子邮件地址将不会被发表。 必填字段标有 *

*

*

  1. 负责数据:MiguelÁngelGatón
  2. 数据用途:控制垃圾邮件,注释管理。
  3. 合法性:您的同意
  4. 数据通讯:除非有法律义务,否则不会将数据传达给第三方。
  5. 数据存储:Occentus Networks(EU)托管的数据库
  6. 权利:您可以随时限制,恢复和删除您的信息。

  1.   赛隆

    也许64位结构更适合这些时间,这是继续使用8086的延迟。

    1.    阿德里安·阿罗约街

      我一直在寻找有关x86_64中GDT的信息,我认为它遵循旧模型并带有特殊标志。 仍使用32位地址。 现在我不知道确切如何正确地做。 一些链接:
      http://wiki.osdev.org/Entering_Long_Mode_Directly
      http://f.osdev.org/viewtopic.php?f=1&t=16275

  2.   Geronimo中

    首先您的贡献很好,但我认为标题应该是
    “模仿理查德·斯托曼”,或者至少我是这样认为的,
    问候

    1.    Abimaelmartell

      Linus创建了Linux内核,Stallman创建了GNU,这是Unix的工具和命令。

      标题是适当的,因为您正在创建一个核。

      您好!

  3.   红宝石

    非常感谢您回答我的所有问题并耐心等待,我只了解汇编程序的基本知识,对C几乎一无所知,但我真的很喜欢,现在我对GDT有点困惑,让我们看看是否理解。

    GDT将具有始终可由任何程序访问的全局“描述符”,这些描述符指向将要执行(程序)的部分吗? 否则就是这样。