2016-11-17 184 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在需要時從內存層次結構中讀取。 –