段寄存器如何参与内存地址转换?

How are segment registers involved in memory address translation?

到目前为止我学到的关于细分的知识:

所以,我的问题是:

通常的翻译如下:

 Logical address   -->   GDT -->  Linear address          --> Page tables --> Physical Address
(segment:offset)                 (segment base + offset)         

\______________________________________________________/ 
                  Virtual address                                     
             (can be either logical or linear)

如果 运行 在 VMX 非 root 模式下(即在 VM 中)并且启用了 EPT,则:

 Logical address   -->   GDT -->  Linear address          --> Page tables --> Guest Physical Address --> EPT --> (System) Physical Address
(segment:offset)                 (segment base + offset)         

\______________________________________________________/                      \__________________________________________________________/
                  Virtual address                                                        Physical address
             (can be either logical or linear)

如果存在 IOMMU(如保护伞技术 VT-d):

Logical address   -->   GDT -->  Linear address          --> Page tables --> Guest Physical Address --> EPT --> (System) Physical Address  -->  1 or 2 level translation --> (IO) Physical address
(segment:offset)                 (segment base + offset)         

\______________________________________________________/                     \___________________________________________________________________________________________________________________/
                  Virtual address                                                        Physical address
             (can be either logical or linear)

MMIO甚至可以进行Guest Virtual Address或Guest Physical Address的转换(其目的之一是将应用程序的Virtual address具体化为硬件,简化过多地址的管理spaces 在翻译过程中遇到)。

注意正如Hadi Brais所指出的,术语"Virtual address"在Intel和AMD手册中仅指定线性地址。
我发现将逻辑地址和线性地址都标记为虚拟地址更有用,因为它们在页面转换步骤之前。


段寄存器保存一个段选择器,它索引一个段描述符,用于执行安全检查并获取段base逻辑地址.
的偏移部分相加 之后就大功告成了。

在指令级指定的每个地址都是一个逻辑地址 - 需要查找段描述符
为了避免每次指令访问内存时都从内存中读取它,CPU 缓存它 - 否则会成为性能杀手。

OS 根据需要执行的操作设置段寄存器,但无论如何它很少需要超过四个段。

分段(在 PM 中)的主要目的是通过为每个程序定义非重叠分段来实现进程隔离。
一个程序通常只需要一个堆栈段、一个数据段和一个代码段——其他三个是为了避免 saving/restoring 当时的数据段,当时段最大大小为 64KiB(阅读:实模式。fsgs 是后来添加的)。

今天 OSes 使用平面模型,其中只有两个部分(代码和 data/stack - 这是一种简化,需要其他部分)包含整个地址 space , 再加上 OS 特定段,例如 TLS 或 PEB/TEB.
所以六个段寄存器甚至超过了它的需要,GDT 的 8192 个条目在那里以备不时之需(如果甚至)需要。

第1题: 好吧,直到下一个 virtual/logical 地址被加载到段寄存器,当前选择器才会出现。(没有变化,保持相同的虚拟地址)。

第2题: 最初,发生分段过程(即将虚拟地址转换为 32 位线性地址)。

首先,16 位选择器将被加载到一个段寄存器中。这个 16 位选择器包含(13 位描述符编号,1 位 Table 索引,2 位 RPL[请求的特权级别])。

现在 GDT/LDT 的 32 位基地址(GDT 如果 TI=0)来自 GDTR/LDTR 与 13 位指针相加并指向相应 GDT 中的描述符? LDT.

描述符是一个 8 字节的条目,包含内存段的 32 位基地址、访问权限和内存段的 Limits/length/size。

现在上面提到的所有3个实体都被复制到所选段寄存器的程序员不可见缓存寄存器部分。

这个来自缓存的32位基地址与虚拟地址或逻辑地址的32位偏移量相加,形成线性地址。 如果禁用分页,这将用作物理地址,否则,将进行页面转换以获取内存段中某个段的物理地址。

第3题:

这真的无关紧要,因为描述符中 8 位访问权限中的位将内存段的使用指定为 code/data/stack/extra 段。