- 论坛徽章:
- 0
|
该部分内容需要仔细阅读Intel或者AMD的相关文档,Intel文档名为Intel 64 and IA-32 Architectures Software Developer's Manual, AMD的文档名是:AMD64 Architecture Programmer's Manual,这些文档在intel和amd的官方网站上都可以下到,据我了解intel甚至提供纸质的文档供开发者使用(需要自己提交申请)。 这些文档基本上围绕x86的系统编程展开,包括x86的指令集,一般情况下大家很少会自己去写一个操作系统,那么大部分情况下阅读这些文档是为了理解Linux内核,所有关于x86系统编程方面的文档都不会超出上面提到的这两篇。个人的建议是IA32看Intel的文档,64位的看AMD64文档。
关于x86 64位的历史这里也简单提一下,当年AMD提出64位概念时,是要兼容以前的32位x86处理器的,而当时intel正忙于安腾处理器,这是个全新的架构,也就是现在说的IA64(Intel Architecture 64),和x86处理器完全不兼容。就技术本身而言,很难说安腾是个失败的产品,但是最终还是市场说了算,因为x86 32位多年历史的积累,上面运行着无数的应用程序,而这些程序将无法在安腾(Itanium)处理器上运行,导致了IA64无法在市场上获得成功, intel曾经有team专门在二进制级别上将x86 32的指令翻译成IA64指令,希望在市场全面转向IA64时作为一个兼容x86的临时解决方案。而AMD64处理器因为兼容32位而最终被市场所接受。历史上AMD的股价在05年底06年初时曾达到40多美元,那段时间对intel来说是比较郁闷的,直到后来core架构的出现。客观地说AMD在其发展历史上曾有过很多不错的技术与创新,可惜差不多都昙花一现,其中原因很多,我想外部因素主要应该有以下两方面,一方面是因为其对手Intel在x86领域深厚的技术沉淀与积累,另一方面是Intel具有强大的资金资源与市场影响力。很多时候AMD弄出来的东西Intel会明确表态不予支持,那么这个东西基本上就不会有多少市场(MSFT OS都不支持了,Application会去支持吗?!),搞得AMD不但必须得推倒自己的东西,而且还要反过来支持intel的,因为无论技术如何,最终还是由市场说了算。现在我们提x86 64位,比较中立的说法是x86 64,这估计也是intel乐于见到的,因为在x86 64位上,实际是AMD首先实现的,所以AMD将64位x86称之为AMD64. 有点扯远了...
下面回到本帖的主题,在x86处理器上如何进行代码特权级的检查。我将一些比较容易引起混淆的概念整理如下:
1. 对于数据段访问的权限检查:
在处理器把要访问的数据段选择子加载到相应的段寄存器(DS, ES, SS, FS, GS)之前,处理器会先做个权限检查。它会比较CPL,要加载的数据段选择子的RPL以及选择子所选择的数据段描述符中的DPL.只有当下列条件满足时,才可以访问相应的数 据段:
DPL >= CPL && DPL >= RPL. 否则就产生一个通用保护异常,这种情况下段寄存器并不会被加载。
2. 堆栈段作为一种特殊的数据段,其权限检查比较特别:只有当CPL=RPL=DPL时,堆栈段才允许被访问。
3. 对于代码间的转移,有几种不同的情况:
a)Far形式的JMP, CALL, RET指令后跟的目标代码段的选择子(该selector中的低2位代表RPL,当前CS寄存器的低2位代表CPL)
这里又分两种情况,非一致代码段和一致代码段:
Nonconforming Code Segment --这种情况要求CPL一定要等于DPL,其次RPL<=DPL.如果成功转移到了目标代码段,CPL保持不变,即跳转前后无特权级变化。
Conforming Code Segment --这种情况要求CPL >= DPL,RPL则无需检查。转移后特权级也不变化。因为转移前后CPL没有变化,所以也没有堆栈切换发生。
绝大多数代码段都是非一致代码段,这种情况下(Far JMP, CALL, RET CS_Selector)不会引起特权级变化。
一致代码段还是非一致代码段由目标代码段所属描述符的Type字段决定。
b)如果想在不同特权级代码间穿越,则必须使用门这种机制。x86处理器提供四种门:
调用门 陷进门 中断门 任务门
任务门用来做任务切换,陷阱门和中断门是一种特殊的调用门,用来呼叫陷阱和中断处理函数。
调用门 -- 通过调用门除了可以在不同特权级代码间转换外,还可以在16-bit和32-bit的代码间实现穿越。调用们描述符只存在于GDT或者
LDT,不在IDT中。用Far CALL/JMP gate_selector, offset就可以通过调用门实现代码的穿越。指令中的offset虽然需要,但是
处理器不会使用,应为被调用的代码段入口点将由调用们描述符中的offset来替换。
在权限检查方面,CALL指令与JMP指令稍有区别。但是它们都会检查以下四个部分:CPL, RPL, 调用门的DPL和目标代码段描述符的
DPL.
CALL和JMP要想访问调用门,首先必须确保both CPL and RPL <= DPL of the call gate. 其次对于非一致的目标代码段的描述符
中的DPL(简写为DDPL, Destination DPL),对于CALL指令要求:DDPL <= CPL,对于JMP指令,要求DDPL=CPL.所以,对于非一致目标
代码段而言,CALL指令可以切换到更高的优先级,而JMP则不可以。一旦CALL指令成功切换到更高优先级代码段,CPL=DDPL并伴有
堆栈的切换。
原帖链接:http://www.embexperts.com/forum. ... &extra=page%3D1 |
|