x86 / x64:修改TSS字段

时间:2016-11-17 11:15:45

标签: assembly x86 x86-64

当激活时(即TR寄存器指向的那个)TSH的字段发生变化会发生什么?特别是,对ESP0 / RSP0字段的更改是否立即生效?或者处理器是否与段选择器一样保留TSS的高速缓存,因此需要LTR指令来强制处理器重新加载TSS字段?

2 个答案:

答案 0 :(得分:6)

处理器使用TSS存储当前上下文并在任务切换期间加载下一个要调度的上下文
在CPU切换到此类TSS之前,更改TSS结构不会影响任何上下文。

时,CPU执行任务切换
  

软件或处理器可以通过以下方式之一派遣任务执行:

     

•使用CALL指令显式调用任务   •使用JMP指令显式跳转到任务   •(通过处理器)对中断处理程序任务的隐式调用   •对异常处理程序任务的隐式调用   •当EFLAGS寄存器中的NT标志置位时,返回(使用IRET指令启动)。

您可以阅读英特尔手册3第7章中的TSS。

<div class="grid-box"> <div class="first-row"> <div class="grid one"> <img src="http://placehold.it/100x100" alt="" /> </div> <div class="grid two"> <img src="http://placehold.it/100x100" alt="" /> </div> </div> <div class="grid three"> <img src="http://placehold.it/202x100" alt="" /> </div> </div>没有执行交换机,请参阅英特尔手册2:

  

在任务寄存器中加载段选择器后,处理器使用段选择器来定位   全局描述符表(GDT)中TSS的段描述符   然后加载段限制和基数   TSS从段描述符到任务寄存器的地址   任务寄存器指向的任务是   标记为忙,但没有发生任务切换

编辑:我实际测试了CPU是否缓存了来自TSS的静态值。
测试包括一个启动程序(附件)

  • 创建一个GDT,其中包含两个带有DPL 0和3的代码段,两个带DPL 0和3的数据段,一个TSS和一个带DPL 3的调用门,代码段为DPL 0。
  • 切换到保护模式,将TSS中 ESP0 的值设置为 v1 并加载 X509Store store = new X509Store(); store.Open(OpenFlags.ReadOnly); if (args.Parameters["CertificateName"].ToString() != "") { foreach (X509Certificate2 mCert in store.Certificates) { if (mCert.Subject.Contains("OU=" + args.Parameters["CertificateName"].ToString())) { SerialNum = mCert.SerialNumber; break; } } if (SerialNum == String.Empty) { throw new Exception("Certificate not found with name: " + args.Parameters["CertificateName"].ToString() + " ;" + " OU=" + args.Parameters["CertificateName"]); } } else { foreach (X509Certificate2 mCert in store.Certificates) { if (mCert.Subject.Contains("OU=Eua")) { SerialNum = mCert.SerialNumber; break; } } if (SerialNum == String.Empty) { throw new Exception("Haven't found default certificate ;"); } } store=null;
  • 使用DPL 3返回代码段,将 ESP0 的值更改为 v2 并调用“呼叫”门。
  • 检查ESP是 v1 -10h还是 v2 -10h,分别打印1或2(如果由于某种原因不匹配,则为0)。

在我的Haswell和Bochs上,结果是2,这意味着CPU在需要时从内存(层次结构)读取TSS。

虽然对模型的测试不能推广到ISA,但事实并非如此。

ltr

答案 1 :(得分:4)

只在必要时才读取TSS,并且没有特殊的TSS缓存。 (GDT中的TSS描述符与段描述符一样缓存,但不是TSS本身的内容.TSS可以像任何其他内存区域一样缓存在普通的L1 / L2 / L3内存缓存中。)

在不同情况下可以读取TSS的三个不同区域。在适当的情况发生之前,更改TSS中的任何值都无效。他们是:

  1. I / O指令(IN,INS,OUT,OUTS)在Virtual 8086模式下执行,或者当CPL&gt;执行时。 IOPL。这会导致I / O映射基址字段和它指向的I / O映射被读取。
  2. 当CR4.VME为1时,在虚拟8086模式下执行软件中断(INT)。这会导致I / O映射基址字段和它指向的中断重定向位图被读取。
  3. 从较低权限级别更改为更高权限级别(从较高编号环到较低数字环)会导致堆栈切换。这会导致读取SS0 / ESP0,SS1 / ESP1,SS2 / ESP2,RSP0,RSP1或RSP2字段,具体取决于新的权限级别。
  4. 发生任务切换,导致读取新TSS中的所有已定义字段,但I / O映射基址,SS0 / ESP0,SS1 / ESP1,SS2 / ESP2和先前任务链接字段除外。当IRET指令导致任务切换回嵌套任务时,将读取旧TSS的Previous Task Link字段。
  5. 在64位模式下发生任何类型的中断或异常,并且相应IDT条目的IST字段不为0.这会导致读取TSS的相应ISTn字段。
  6. 请注意,在64位模式下,只有情况1,3和5可能发生,因为64位模式不支持Virtual 8086模式,也不支持任务切换。

    LTR指令不会导致读取任何内存区域,除了GDT中与给定选择器对应的条目,也没有任何内部TSS缓存供它冲洗。