当活动(即由TR寄存器指向的那个)TSS的字段发生改变时会发生什么?特别是,对ESP0/RSP0字段的更改是否立即生效?或者处理器是否像段选择器一样保留TSS缓存,所以需要LTR指令来强制处理器重新加载TSS字段?x86/x64:修改TSS字段
回答
处理器使用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
的TSS是只在需要时阅读,而且也没有特别的TSS缓存。 (GDT中的TSS描述符与段描述符一样被高速缓存,但不是TSS本身的内容.TSS可像其他任何内存区域一样高速缓存在正常的L1/L2/L3内存中)。在不同情况下读取TSS的三个不同领域。在恰当的情况发生之前,更改TSS中的任何值都不起作用。它们是:
- I/O指令(IN,INS,OUT,OUTS)在Virtual 8086模式或CPL> IOPL时执行。这会导致读取I/O映射基址字段和它指向的I/O映射。
- 当CR4.VME为1时,将在虚拟8086模式下执行软件中断(INT)。这会导致读取I/O映射基本字段和它指向的中断重定向位图。
- 从较低特权级别改变为较高特权级别(从较高编号的环到较低编号的环)导致堆叠交换机。这会根据新的权限级别读取SS0/ESP0,SS1/ESP1,SS2/ESP2,RSP0,RSP1或RSP2字段。
- 发生任务切换,导致除了I/O映射基地址,SS0/ESP0,SS1/ESP1,SS2/ESP2和先前的任务链接字段外,读取新TSS中的所有定义字段。当IRET指令导致任务切换回嵌套任务时,将读取旧TSS的“先前任务链接”字段。
- 在64位模式下发生任何类型的中断或异常,并且对应的IDT条目的IST字段不为0.这导致TSS的相应ISTn字段被读取。
请注意,在64位模式下,由于64位模式不支持Virtual 8086模式,因此只能出现1,3和5情况,也不支持任务切换。
LTR指令不会导致读取任何区域的内存,除非GDT中的条目与给定的选择器相对应,也没有任何内部TSS高速缓存供它刷新。
我的问题特别是关于第(3)点。我想知道RSPx中的更改是否足以影响后续的授权更改,或者需要某种“刷新/重新加载”操作。你的答案意味着RSPx的变化已经足够了,而玛格丽特布鲁姆的建议却恰恰相反(见上面我的评论) –
@GiuseppeGuerrini我相信Ross和我说的是同样的事情,TSS在需要时从内存层次结构中读取。 –
- 1. 随时修改一个字段另一个字段被修改
- 2. 字段 'Invoice_Date' 不能修改
- 3. 修改cookie中的字段
- 4. 修改对象的字段
- 5. 修改Django ModelForms字段
- 6. 修改表单字段
- 7. NSMutableURLRequest修改标题字段
- 8. 有没有“修改”字段?
- 9. mysql修改重复字段
- 10. Bash修改CSV以更改字段
- 11. 修改表单输入字段
- 12. 检查字段是否已被修改
- 13. 修改Varchar字段中的数据
- 14. 如何修改StackedInline中的字段?
- 15. 修改私有静态只读字段
- 16. 更新Systemdate修改日期字段asp.net
- 17. 修改Django用户模型字段
- 18. CRM:工作流:修改隐藏字段
- 19. 修改项目 - 状态字段
- 20. 创建/修改字段命名约定?
- 21. 无法修改字段在Python列表
- 22. 动态修改文本字段。 Angular.js
- 23. logstash过滤器修改数组字段
- 24. Rails:检查修改后的字段
- 25. 从前端修改自定义字段
- 26. 如何修改android.os.Build的静态字段?
- 27. 使用logstash修改字段的内容
- 28. asp.net隐藏字段 - 被修改?
- 29. cakePHP - 修改字段不更新
- 30. SharePoint 2007获取修改字段
正确,但仍有一个细节:TSS还包含用于权限级别更改的堆栈指针。它们不会立即用于上下文切换。处理器是否将它们加载到“影子副本”中的上下文切换上,然后在需要时使用这些副本? –
@GiuseppeGuerrini我相信他们在需要的时候被阅读,手册中的'call'指令描述和调用门描述似乎暗示了这一点。这可以很容易地通过测试,也许我可以调查。 –
@GiuseppeGuerrini我已经测试了CPU的行为,在我的模型中,需要时会从内存中读取值。我相信这可以推广到任何模型。 –