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

最佳答案

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

CPU在以下情况下执行任务切换

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

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

您可以在Intel手册3的第7章中阅读有关TSS的信息。

从Intel手册2:ltr不执行切换:

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



编辑:我实际上已经测试过CPU是否从TSS缓存了静态值。
该测试包含一个引导程序(附带),该程序可以

  • 创建一个GDT,其中包含两个DPL 0和3的代码段,两个DPL 0和3的数据段,一个TSS和一个DPL 3到DPL 0的代码段的呼叫门。
  • 切换到保护模式,将TSS中ESP0的值设置为v1并加载tr
  • 返回DPL 3的代码段,将ESP0的值更改为v2,并调用“呼叫”门。
  • 检查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
    

    08-16 09:40