segment descriptor http://www.mouseos.com/arch/descriptor64.html

long mode 下的 segment descript


注意:
    本文针对的是 long mode 下的 segment descriptor 情况,当然包括:

  • 64-bit mode
  • compatibility mode

对于 gate descriptor 来说,在 long mode 下是固定 16 bytes,但是对于 segment descriptor 来说在 long mode 下的 64bit mode 和 compatibility mode 是表现是不同的。

segment descriptor
legacy x86 mode
long mode
comatibility mode
64-bit mode
user segment descriptor
(code/data segment)
32 位 descriptor
32 位 descriptor
32 位 descriptor
system segment descriptor
(LDT/TSS segment)
32 位 descriptor
32 位 descriptor
64 位 descriptor

仅仅在 64 位模式下,LDT 和 TSS segment descriptor 被看作是 64 位的 descriptor

再一次说明 user segment 是指:

  • code segment
  • data segment

system segment 是指:

  • LDT segment
  • TSS segment

 

1. 64 位模式下的 user segment descriptor 结构

在 long mode 下对 user segment descriptor 有两种解释结果:

  • 64 位模式下的 descriptor
  • compatibility 模式下的 descriptor

compatibility 模式下 code segment descriptor 与 legacy x86 的 code segment descriptor 在意义在只有一点差异:

  • L 属性位

在 legacy x86 模式下不存在 L 属性,但是这个 L 位在 legacy x86 模式下是 0 值。而 compatibility 模式下的 L 属性是 0 值。实际上它们是相等的。

下面是在 64 位模式下的解释:

 

它们的 segment descriptor 的 S = 1 指示它们是 user segment descriptor

上图灰色部分limitbase 在 user segment descriptor 里是无效被忽略的,有部分属性是支持的。

然而 attribute 部分对于 Code segment descriptor 和 Data segment descriptor 有着不同的表现,粉红色部分在 code segmnt descriptor 里是有效的,在 data segment descriptor 里是无效的。

 

1.1 Code segment descriptor

上图中的白色部分红色部分在 code segment descriptor 里是有效的,它们是:

  • CConforming):指示 code segment 是 conforming 还是 non-conforming 类型,它们在权限控制上的表现是不一样的。
  • DPLDescriptor Privilige Level): 指示访问 code segment 需要的权限
  • PPresent):指示 code segment 是否加载在内存中
  • LLong):指示 code segment 是 64 位模式代码还是 compatibility 模式代码
  • DDefault operand size):指示 code segment 的 default operand size

这些 attribute 位加载到 CS 寄存器后,在 CS 寄存器的 attribute 里同样是有效的。

虽然 x64 体系非常想抛弃 segmentation 机制,但是为了整个 x86 架构的兼容性不得以而为之:

  • C DPL 为权限控制和转移而保留
  • L D 为 processor 模式和指令操作数而设
  • P 恐怕是最没有异议

图中绿色部分比较特别:

  • Ssystem) 标志
  • C/DCode/Data)标志

虽然这两个标志是无效的,但是您必须为它设置初始值,在设置初始值后你不能进行更改,这是无效的一面。

对于 Code segment descriptor 来说,它必须设为(注意是:必须):

  • S = 1
  • C/D = 1

说明这个 descriptor 是 code segment descriptor,如果你尝试加载一个 S = 0 或者 C/D = 0 的 descriptor 进入 CS 寄存器,将会产生 #GP 异常。

而下面两个类型属性是无效的:

  • RReadable
  • AAccessed

那么 Code segment 在 64 位模式下强制为 Readable 可读。

 

1.2 Data segment descriptor

在 data segment descriptor 情况有些特别。

对于加载到 ES, DS, SS 寄存器的 data segment descriptor 来说仅有一个属性是有效的:

  • PPresent

对于加载到 FSGS 寄存器的 data segment descriptor 来说 base 是有效的,那么可以在 FSGS 寄存器的 base 里设置非 0 的 segment base

同样必须设置 SC/D 属性,在 data segment descriptor 里它们必须为:

  • S = 1
  • C/D = 0

指示该 descriptor 是 data segment descriptor,如果尝试加载 S = 0 或者 C/D = 1 的 descriptor 进入 DSESSSFS 以及 GS 寄存器会产生 #GP 异常

下面的类型属性是无效的:

  • EExpand-Down
  • WWritable
  • AAccessed

那么在 64 位模式下,data segment 被强制为 Expand-Up Writable 的。

 

2. 64 位模式下的 System segment descriptor 结构

64 位模式下的 system segment descriptor 是 16 bytes 共 128 位,包括:

  • 20 位的 segment limit
  • 64 位的 segment base
  • 12 位的 segment attribute

system segment descriptor 包括了 LDT segment descriptor TSS segment descriptor

64 位模式下 user segment descriptor 是 8 bytes,而 system segment descriptor 是 16 bytes 的,它们存放在 GDT 表中就可能会产生了跨 descriptor 边界的问题

 

2.1 GDT 表中的跨 descriptor 边界

上图显示了在 64 位模式下的一个跨 descriptor 边界产生 #GP 异常的示例:

当使用 selector = 0x20 企图访问一个 user segment descriptor,但是并不如愿,+0x20 位置上并不是一个有效 user segment descriptor,它只是 LDT descriptor高半部分

结果会怎样?答案是:未知

因此为了防止这种未知结果的产生,x64 体系中建议:须将 system descirptor(包括 call gate descriptor)的高 64 位中的对应 S 标志和 type 位置上置 00000,但是不包括 interrupt gate trap gate

由于 00000代表 0 类型的 system descriptor)是无效的 descriptor 类型,因此访问这样的 descriptor 会导致 #GP 异常的发生。从而避免未知结果的产生

这就是上图中上半部分的 S 和 type 域为何置为 00000 的原因。

当然这个跨 descriptor 边界的情况在 LDT 也可能发生。但是在 IDT 是不可能发生的,那是因为 IDT 只能存在 system descriptor 不可存放 user segment descriptor。因此 IDT 表的索引因子固定为 16,这就是 interrupt gatetrap gate 的高半部分 s 和 type 域不用置为 00000 的原因。

 

2.2 system segment descriptor 属性位

LDT/TSS segment descriptor 大部分属性是有效的,包括:

  • type
  • S
  • DPL
  • P
  • AVL
  • G

它们的 type 包括:

  • type = 2 :64-bit LDT
  • type = 9 :available 64-bit TSS
  • type = B :busy 64-bit TSS

64 位模式的 system segment descriptor 已经不支持 16 位的 TSS,原来的 32 位 TSS 变成了 64 位的 TSS

 

3. comaptibility mode 下的 system segment descriptor

system segment descriptor 在 compatibility mode 下依旧是 32 位的 descriptor,这和 64 bit 模式下区别很大

在一个可以执行 legacy 32 位程序的 OS 里,应该要准备两份 LDT/TSS segment descriptor:64 位的 LDT/TSS segment descriptor 和 32 位的 LDT/TSS segment descriptor

 

 

版权 mik 所有,转载请注明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值