Chinaunix
标题:
讨论一下 x64 体系中 long mode 下的一个 bug
[打印本页]
作者:
mik
时间:
2009-04-10 00:52
标题:
讨论一下 x64 体系中 long mode 下的一个 bug
本来以为对 x64 还是很了解,但要非常透彻清晰地理解,还需要每个细节都要掌握透彻。
最近发现 x64 体系上的一个 bug,是否有这么一回事,讨论一下。
按 x64 体系的设计思路: long mode 的 compatibility 模式应该与原来的 x86 行为一致,使用原有的 32 位软件能平滑地直接在 64 位 OS 中运行。
事实上真能做到。比如:在我的 vista x64 上就能很好的运行原来的 32 位软件。
64 位的 OS 的核心代码(kernel)及相关核心组件必定是运行在 long mode 的 64 bit 模式下。那么64位用户程序运行在 64 bit 模式下,而原来的 32 位软件则是运行在 compatibility 模式下。
对于 long mode 下的 system descriptor 及 gate descriptor AMD 的文档中明确说明:
1、system descriptor(LDT & TSS)仅仅在 64 bit 模式下才被扩展为 64 位的 descriptor(共 16 个字节),在 compatibility 模式下还是原来的 32 位 descriptor(共 8 个字节)。
2、gate descriptor 在 long mode 下被扩展为 64 位的 descriptor,包括 compatibility 和 64 bit 模式。
--------------------------------------------------------------------
bug : (根据最新的 AMD 文档)
LDT、TSS 和 gate descriptor 的 type 在
long mode 模式(compatibility 和 64 bit)
被修改为:64bit-LDT、64bit-TSS 以及 64bit-gate(call、interrupt/trap)。
按 AMD 的论述:
仅在 64 bit 模式下 LDT 和 TSS 才被扩展为 64 位,
不包括 compatibility 模式。在这里就前后矛盾了。若:也仅在 64 bit 模式下,它们的 type 才被修改为 64 LDT 和 64 TSS,在 compatibility 模式下还是原来的 types。这样才符合设计方案。
这不知是 AMD 文档上论述上的一个 bug,还是确实是这样。确实这样的话:这可算是一个 bug。
在 compatiblity 模式下是否真的被定义为 64 TSS,这是一个很重要的问题:
64 位的 TSS 与 32 位的 TSS 相差甚远,关键的一点是:64 位的 TSS 中 stack pointer 是 64 位的,并且没有 SS selector 存在。而 32 位的 TSS 中 stack pointer 包括了 SS 与 ESP,它们是 32 位的。
所以,当原来的 32 位软件运行在 compatiblity 下,若有代码使用 call gate 来调用高权限的例程时,而 call gate 最终却使用的是 64 位的系统例程。发生 stack 切换时
,
应该要使用了 64 位的 TSS 。但是居然使用了 32 位的 TSS,就会产生问题。
实际上:
这个 bug 的产生来自“仅在 64 bit 模式下 TSS 才被扩展为 64 位”。
恰恰相反:
“在 long mode 模式(包括 compatiblity 和 64 bit)下 TSS 被扩展为 64 位”---- 这是对的。
gate(包括 call、interrupt/trap)在 long mode 下被扩展为 64 位,TSS 也应该是而“在 long mode 下被扩展”,而不是“仅仅在 64 bit 模式下才被扩展”。TSS 应该与 gate 相配套。
问题的产生在于:使用 call gate 调用高权限的
系统例程
的时侯。系统例程是属性系统软件 OS 的部件。
在 x64 体中的 long mode 下的 gate 必须是使用 64 位的 code,所以 long mode 下 gate 是 64 位--- 这个观点正确
。
在 64 位的 OS 核心运行在 64 位下,那么由 call gate 调用的系统例程应该是 64 位代码。因此,发生 stack 切换时,必须使用 64 位的 TSS 来获取 64 位的 stack pointer(RSP)。
因此:
应该是 TSS 在 long mode 下被扩展为 64 位,而不是仅在 64 bit 才被扩展为 64 位。
-----------------------------------------------------------------------------
在这里,我宁可当 AMD 文档论述的 bug,而不是实际上的 bug。 实际上更不要指望 Intel 的手册能说清楚,Intel 的手册论述得更差劲!
又或者:是我的理解错误。
作者:
mik
时间:
2009-04-10 14:44
主贴里,确实是我理解错误了。 收回我的这方面的言论。
“TSS 仅仅在 64 bit 模式下才被扩展为 64 位”----- 这是对的。
-----------------------------------------------------------------------
因为:
x64 体系中设计:gate 在 long mode (包括 compatibility 和 64 bit)下扩展为 64 位。
这一设计理念也是正确的。
gate(包括 call、interrupt / trap)目的是构建
系统的服务例程
,如:核心的服务例程,中断服务例程等。64 位的 gate 必须指向 64 位的 code segment。
在 64 位的 OS 中,核心的组件运行在 64 bit 模式下,包括前面提到的系统服务例程。
在 64 位的 OS 中,当运行原来 x86 的 32 位应用软件时,32 位的软件运行在 compatibility 模式下。如果:原来运行在 compatibility 的 32 位软件中,执行调用 call-gate 来调用
系统服务例程。
1、由于 call-gate 最终执行 64 位的代码。
那么就发生了:
processor 由 compatibility 模式切换到 64 bit 模式
。由于 processor 已切换到 64 bit 模式,那么此时的 TSS 也被切换到 64-TSS 模式。
由于 CPL 的改变,导致了 stack 的切换。此时的 TSS 已经切换到 64-TSS 模式,因此在 64 bit 代码下,获取了正确的 64 位 stack pointer (RSP),此时的 stack 环境是正确的。
故“仅在 64 bit 模式下 TSS 才被扩展为 64 TSS“ 这个策略是正确的。
2、 在 long mode 的 compatibility 模式下,TSS 依然是原来的 16 或 32 位 TSS。
若运行在 compatibility 模式下的 32 位代码当中:有指令使用 TSS selector 或者 task gate 进行任务的切换。那么此时的 TSS 必须是原来的 TSS,不能是 64 位的 TSS 。
---------------------------------------------------------------
基于上述 2 个方面:
在 compatibility 模式下 TSS 不能被扩展为 64 位 TSS。而 64 bit 下必须被扩展为 64 位 TSS 。
至于,AMD 文档上面说:在 long mode(包括 compatibility 和 64 bit)下,TSS descriptory 的 types 中:32-TSS 被重新定义为 64-TSS。
-------
这种前后矛盾的说法,相信这是文档论述方面的错误。
作者:
mik
时间:
2009-04-10 20:42
仔细再看了看,AMD/Intel 文档中自相矛盾的地方太多了。MD 的太不认真,太不负责任的。
还是小平同志说得对:实验是检验真理的唯一标准。
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2