免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2723 | 回复: 2
打印 上一主题 下一主题

讨论一下 x64 体系中 long mode 下的一个 bug [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-10 00:52 |只看该作者 |倒序浏览
30可用积分
本来以为对 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 的手册论述得更差劲!


  又或者:是我的理解错误。

论坛徽章:
0
2 [报告]
发表于 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。
  ------- 这种前后矛盾的说法,相信这是文档论述方面的错误。

论坛徽章:
0
3 [报告]
发表于 2009-04-10 20:42 |只看该作者

仔细再看了看,AMD/Intel 文档中自相矛盾的地方太多了。MD 的太不认真,太不负责任的。

还是小平同志说得对:实验是检验真理的唯一标准。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP