assembly - x86/x64 : modifying TSS fields

标签 assembly x86 x86-64

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

最佳答案

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

当 CPU 执行任务切换时

Software or the processor can dispatch a task for execution in one of the following ways:

• A explicit call to a task with the CALL instruction.
• A explicit jump to a task with the JMP instruction.
• An implicit call (by the processor) to an interrupt-handler task.
• An implicit call to an exception-handler task.
• A return (initiated with an IRET instruction) when the NT flag in the EFLAGS register is set.



您可以在英特尔手册 3 的第 7 章中阅读有关 TSS 的信息。
ltr 不执行开关,来自英特尔手册 2:

After the segment selector is loaded in the task register, the processor uses the segment selector to locate the segment descriptor for the TSS in the global descriptor table (GDT).
It then loads the segment limit and base address for the TSS from the segment descriptor into the task register.
The task pointed to by the task register is marked busy, but a switch to the task does not occur.



编辑 :我实际上已经测试过 CPU 是否缓存了来自 TSS 的静态值。
测试包括一个 bootstrap (附加)
  • 创建一个 GDT,其中包含两个 DPL 0 和 3 的代码段、两个 DPL 0 和 3 的数据段、一个 TSS 和一个 DPL 3 的调用门到 DPL 0 的代码段。
  • 切换到保护模式,将 TSS 中 ESP0 的值设置为 v1 并加载 tr
  • 回到DPL 3的代码段,将ESP0的值改为v2,调用Call gate。
  • 检查 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
    

    关于assembly - x86/x64 : modifying TSS fields,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40653480/

    相关文章:

    pointers - 在方括号中添加两个寄存器是什么意思?

    ubuntu - 汇编 x86 nasm 输出浮点值

    c - C 代码的 x86 反汇编生成 : orq $0x0, %(rsp)

    assembly - 多核 CPU 中的核之间/跨核访问寄存器

    C++ 在嵌入式系统中需要汇编

    assembly - 如何在不污染缓存的情况下从内存加载值?

    assembly - 在 MASM 中使用常量初始化大数

    assembly - pic汇编中如何计算超过255?

    gcc - 我如何要求汇编程序 "give me a full size register"?

    macos - 向 x86-64 二进制文件写入跳转命令