初始加载后如何更新 GDT 条目?

dar*_*t97 2 x86 operating-system osdev i386 gdt

使用 初始化并将 GDT 加载到 GDTR 后lgdt,以后如何更新 GDT?
如果我使用sgdt命令获取基地址,然后更新或添加条目,然后使用 重新加载它,我是否正确lgdt?还有其他方法吗?
或者我是否遗漏了一些东西,并且 GDT 永远不会“意味着”在初始化和加载后进行更新?

Coc*_*ut9 5

我知道这个问题已经很老了,但是我想强调一些评论中没有提到的事情,那就是CPU缓存的内容和没有的内容。

\n
    \n
  1. 一些术语:\n
      \n
    • GDT 的条目称为描述符,对于这个答案,我们只对段描述符感兴趣
    • \n
    • 段寄存器 ( cs, ds, es, fs, gs, ss, ldtr, tr) 分配有指定段描述符的段选择器。段选择器始终为 16 位,由以下部分组成:\n
        \n
      1. 13位:描述符条目索引
      2. \n
      3. 1 位:0 表示 GDT 1 表示 LDT
      4. \n
      5. 2 位:请求的权限级别 (RPL)
      6. \n
      \n
    • \n
    \n
  2. \n
  3. CPU不缓存GDT,加载一个值gdtr只是加载一个值gdtr(由GDT的基地址及其大小组成)
  4. \n
  5. 当每个段寄存器使用新的段选择器加载该段时,CPU会缓存该段寄存器使用的 GDT 描述符:\n
      \n
    • 每个段寄存器有 2 个部分:\n
        \n
      • “可见部分”,包含段选择器
      • \n
      • “隐藏部分”包含段描述符的缓存副本
      • \n
      \n
    • \n
    • 当您执行 时mov es, axax例如值为 0x0010:\n
        \n
      1. “可见部分”的值为 0x0010
      2. \n
      3. “隐藏部分”接收存储在 GDT 第 3 个条目中的信息的副本(因为 0x0010 表示第 3 个条目)
      4. \n
      \n
    • \n
    • 使用段寄存器时,只有“隐藏部分”规定了其特征(基址、限制、访问信息)。\n
        \n
      • 用于加载段寄存器的 GDT 段描述符可能被修改或根本不存在
      • \n
      • 它们gdtr可能指向不同的位置,甚至是无效的位置,并且可能具有任何大小,同样,即使是无效的位置 - CPU 也不关心。
      • \n
      \n
    • \n
    • 除了保存用于加载段寄存器的段选择器之外,“可见部分”绝对不执行任何操作,然后可以通过mov ax, es. (ax变成0x0010,即使认为GDT段描述符可能包含任何内容或者目前可能不存在)
    • \n
    • 因此,为了将新的段描述符加载到段寄存器,您需要加载另一个(甚至相同的)选择器,这将更新重新加载“隐藏部分” - 缓存
    • \n
    \n
  6. \n
  7. 话虽这么说,有很多原因需要保持 GDT 中已使用的条目固定,一个简单的原因是,当从内核模式移动到用户模式(反之亦然)时,您会更改段;因此,这些描述符必须存在于 GDT 中。(CPU 还会在其他情况下自动加载新段,例如远调用、中断、任务门、调用门等)。简而言之,仅当您的操作系统不再使用描述符时才删除它。也更难弄乱一些东西
  8. \n
  9. 最后,为了回答你的问题,如果你想添加一个段描述符(或任何其他描述符),你可以将它添加到当前的 GDT 中,你只需将适当的值放入一个空闲描述符条目中,然后将新的选择器加载到段(如果此时需要,您可以更改 GDT 的大小)。如果你想更新一个段描述符,你可以在GDT中更新它,然后重新加载所有使用它的段,如果你不这样做,段将只使用旧的缓存值。
  10. \n
\n

资料来源:Intel\xc2\xae 64 和 IA-32 Architectures Software Developer\xe2\x80\x99s 手册第 3 卷:系统编程指南第 3 章:保护模式内存管理

\n

我建议您也看看 wiki.osdev.org,特别是:

\n\n

请询问任何澄清

\n