2016-11-17 54 views
1

当活动(即由TR寄存器指向的那个)TSS的字段发生改变时会发生什么?特别是,对ESP0/RSP0字段的更改是否立即生效?或者处理器是否像段选择器一样保留TSS缓存,所以需要LTR指令来强制处理器重新加载TSS字段?x86/x64:修改TSS字段

回答

5

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

CPU执行任务切换时

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

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

可以在英特尔手册的第七章读到TSS 3.


ltr不执行开关,从英特尔手册2:

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


编辑:如果CPU缓存从TSS的静态值,我实际测试。在引导程序(附后)

  • 与DPL 0两个代码段和图3,两个数据段与DPL 0和3,TSS与DPL 3呼叫栅极创建GDT
    测试包括与DPL 0
  • 切换到保护模式的代码段,ESP0在TSS值设置为V1并加载tr
  • 返回到带DPL 3的代码段,将ESP0的值更改为v2并调用Call门。
  • 检查ESP是否为v1 -10h或v2 -10h,分别打印1或2(或者如果由于某种原因没有匹配,则为0)。

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

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


BITS 16 

xor ax, ax   ;Most EFI CPS need the first instruction to be this 

;But I like to have my offset to be close to 0, not 7c00h 

jmp 7c0h : WORD __START__ 

__START__: 

    cli 

    ;Set up the segments to 7c0h 

    mov ax, cs 
    mov ss, ax 
    xor sp, sp 
    mov ds, ax 


    ;Switch to PM 

    lgdt [GDT] 

    mov eax, cr0 
    or ax, 1 
    mov cr0, eax 

    ;Set CS 

    jmp CS_DPL0 : WORD __PM__ + 7c00h 

__PM__: 

    BITS 32 

    ;Set segments 

    mov ax, DS_DPL0 
    mov ss, ax 
    mov ds, ax 
    mov es, ax 

    mov esp, ESP_VALUE0 

    ;Make a minimal TSS BEFORE loading TR 

    mov eax, DS_DPL0 
    mov DWORD [TSS_BASE + TSS_SS0], eax 
    mov DWORD [TSS_BASE + TSS_ESP0], ESP_VALUE1 


    ;Load TSS in TR 

    mov ax, TSS_SEL 
    ltr ax 

    ;Go to CPL = 3 

    push DWORD DS_DPL3 | RPL_3 
    push DWORD ESP_VALUE0 
    push DWORD CS_DPL3 | RPL_3 
    push DWORD __PMCPL3__ + 7c00h 
    retf 

__PMCPL3__: 

    ;UPDATE ESP IN TSS 

    mov ax, DS_DPL3 | RPL_3 
    mov ds, ax 

    mov DWORD [TSS_BASE + TSS_ESP0], ESP_VALUE2 


    ;SWITCH STACK 

    call CALL_GATE : 0 

    jmp $ 


__PMCG__: 

    mov eax, esp 


    mov bx, 0900h | '1' 
    cmp eax, ESP_VALUE1 - 10h 
    je __write 

    mov bl, '2' 
    cmp eax, ESP_VALUE2 - 10h 
    je __write 

    mov bl, '0' 

__write: 

    mov WORD [0b8000h + 80*5*2], bx 

    cli 
    hlt 


GDT dw 37h 
    dd GDT + 7c00h  ;GDT symbol is relative to 0 for the assembler 
       ;We translate it to linear 

    dw 0 


    ;Index 1 (Selector 08h) 
    ;TSS starting at 8000h and with length = 64KiB 

    dw 0ffffh 
    dw TSS_BASE 
    dd 0000e900h 


    ;Index 2 (Selector 10h) 
    ;Code segment with DPL=3 

    dd 0000ffffh, 00cffa00h 

    ;Index 3 (Selector 18h) 
    ;Data segment with DPL=0 

    dd 0000ffffh, 00cff200h 


    ;Index 4 (Selector 20h) 
    ;Code segment with DPL=0 

    dd 0000ffffh, 00cf9a00h 

    ;Index 5 (Selector 28h) 
    ;Data segment with DPL=0 

    dd 0000ffffh, 00cf9200h 

    ;Index 6 (Selector 30h) 
    ;Call gate with DPL = 3 for SEL=20 

    dw __PMCG__ + 7c00h 
    dw CS_DPL0 
    dd 0000ec00h 


    ;Fake partition table entry 

    TIMES 446-($-$$) db 0 

    db 80h, 0,0,0, 07h 


    TIMES 510-($-$$) db 0 
    dw 0aa55h 

    TSS_BASE EQU  8000h 
    TSS_ESP0 EQU  4 
    TSS_SS0 EQU  8 

    ESP_VALUE0 EQU 7c00h 
    ESP_VALUE1 EQU 6000h 
    ESP_VALUE2 EQU 7000h 

    CS_DPL0 EQU 20h 
    CS_DPL3 EQU 10h 
    DS_DPL0 EQU 28h 
    DS_DPL3 EQU 18h 
    TSS_SEL EQU 08h 
    CALL_GATE EQU 30h 


    RPL_3  EQU 03h 
+0

正确,但仍有一个细节:TSS还包含用于权限级别更改的堆栈指针。它们不会立即用于上下文切换。处理器是否将它们加载到“影子副本”中的上下文切换上,然后在需要时使用这些副本? –

+1

@GiuseppeGuerrini我相信他们在需要的时候被阅读,手册中的'call'指令描述和调用门描述似乎暗示了这一点。这可以很容易地通过测试,也许我可以调查。 –

+2

@GiuseppeGuerrini我已经测试了CPU的行为,在我的模型中,需要时会从内存中读取值。我相信这可以推广到任何模型。 –

3

的TSS是只在需要时阅读,而且也没有特别的TSS缓存。 (GDT中的TSS描述符与段描述符一样被高速缓存,但不是TSS本身的内容.TSS可像其他任何内存区域一样高速缓存在正常的L1/L2/L3内存中)。在不同情况下读取TSS的三个不同领域。在恰当的情况发生之前,更改TSS中的任何值都不起作用。它们是:

  1. I/O指令(IN,INS,OUT,OUTS)在Virtual 8086模式或CPL> IOPL时执行。这会导致读取I/O映射基址字段和它指向的I/O映射。
  2. 当CR4.VME为1时,将在虚拟8086模式下执行软件中断(INT)。这会导致读取I/O映射基本字段和它指向的中断重定向位图。
  3. 从较低特权级别改变为较高特权级别(从较高编号的环到较低编号的环)导致堆叠交换机。这会根据新的权限级别读取SS0/ESP0,SS1/ESP1,SS2/ESP2,RSP0,RSP1或RSP2字段。
  4. 发生任务切换,导致除了I/O映射基地址,SS0/ESP0,SS1/ESP1,SS2/ESP2和先前的任务链接字段外,读取新TSS中的所有定义字段。当IRET指令导致任务切换回嵌套任务时,将读取旧TSS的“先前任务链接”字段。
  5. 在64位模式下发生任何类型的中断或异常,并且对应的IDT条目的IST字段不为0.这导致TSS的相应ISTn字段被读取。

请注意,在64位模式下,由于64位模式不支持Virtual 8086模式,因此只能出现1,3和5情况,也不支持任务切换。

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

+0

我的问题特别是关于第(3)点。我想知道RSPx中的更改是否足以影响后续的授权更改,或者需要某种“刷新/重新加载”操作。你的答案意味着RSPx的变化已经足够了,而玛格丽特布鲁姆的建议却恰恰相反(见上面我的评论) –

+2

@GiuseppeGuerrini我相信Ross和我说的是同样的事情,TSS在需要时从内存层次结构中读取。 –