9.Windows线程切换_TSS
SwapContext這個函數(shù)是Windows線程切換的核心,無論是主動切換還,是系統(tǒng)時鐘導(dǎo)致的線程切換,最終都會調(diào)用這個函數(shù)。
在這個函數(shù)中除了切換堆棧以外,還做了很多其他的事情,了解這些細節(jié)對我們學(xué)習(xí)操作系統(tǒng)至關(guān)重要。
下面我們看看線程切換與TSS的關(guān)系。
棧底開始往上0x210個字節(jié)存儲浮點寄存器的值,以上都是TrapFrame結(jié)構(gòu)(在api3環(huán)進0環(huán)已經(jīng)講過了)。
調(diào)用API進0環(huán)
普通調(diào)用:通過TSS.ESP0得到0環(huán)堆棧
快速調(diào)用:從MSR得到一個臨時0環(huán)棧,代碼執(zhí)行后仍然通過TSS.esp0得到當前線程0環(huán)堆棧。
TSS:
Intel設(shè)計TSS的目的是為了任務(wù)切換(線程切換),但Windows與Linux , 并沒有使用。而是采用堆棧來保存線程的各種寄存器。
一個CPU只有一個TSS.但是線程很多,如何用一個TSS來保存所有線程的ESP0呢?
下面來看看SwapContext代碼分析
SwapContext proc near ; CODE XREF: KiUnlockDispatcherDatabase(x)+72p; KiSwapContext(x)+29p ...or cl, clmov es:[esi+_ETHREAD.Tcb.State],2 ; _KTHREAD(+0x2d state)改為2pushf ; 存儲當前的EFLAGS寄存器loc_40492C: ; CODE XREF: KiIdleLoop()+5Ajmov ecx,[ebx+KPCR+NtTib.ExceptionList] ; ebx存儲KPCR的地址 此處是讀出異常鏈表 3環(huán)的FS:[0]cmp [ebx+KPCR.PrcbData.DpcRoutineActive],0 ; 是否有DPC有就藍屏push ecxjnz loc_404A70cmp ds:_PPerfGlobalGroupMask, 0 ; LOG用的 Windows自己調(diào)試用的別的地方?jīng)]用jnz loc_404A47loc_404949: ; CODE XREF: SwapContext+12Bj; SwapContext+13Cj ...mov ebp, cr0 ; CR0中的保護控制位mov edx, ebpmov cl, [esi+2Ch]mov [ebx+50h], clclimov [edi+_ETHREAD.Tcb.KernelStack],esp ; 將當前的esp存儲到原線程結(jié)構(gòu)中mov eax,[_ETHREAD.Tcb.InitialStack] ; 目標線程棧底mov ecx,[esi+_ETHREAD.Tcb.StackLimt]sub eax, 210h ; -210h 浮點寄存器mov [ebx+KPCR.NtTib.StackLimit],ecxmov [ebx+KPCR.NtTib.StackBase],eaxxor ecx, ecxmov cl,[esi+_ETHREAD.Tcb.NpxState] ; NpxState 浮點寄存器 運行浮點用這個 沒運行就不用and edx, 0FFFFFFF1h ; 判斷NpxState有沒有浮點支持; 如果上一個線程和要替換的線程對浮點支持是一樣的那就不用換CP0 如果不一樣or ecx, edxor ecx, [eax+20Ch]cmp ebp, ecxjnz loc_404A3Flea ecx, [ecx]loc_404983: test dword ptr [eax-1Ch], 20000hjnz short loc_40498F ; 通過KPCR取出TSSsub eax, 10h ; 再減去10h(虛擬8086模式下使用 TrapFrame結(jié)構(gòu))loc_40498F:mov ecx,[ebx+KPCR.TSS] ; 通過KPCR取出TSSmov [ecx+4], eax ; 將修正后的棧底儲存到TSS中mov esp,[_ETHREAD.Tcb.KernelStatck] ; 將目標線程的ESP存儲到ESP中mov eax,[esi+_ETHREAD.Tcb.Teb] ; 當前線程有很多狀態(tài)一份在ETHREAD里面; 還有一個備份在FS中mov ecx,[ebx+KPCR.TSS] ; 通過KPCR取TSSstimov eax,[edi+_ETHREAD.Tcb.ApcState.Process]cmp eax,[esi+_ETHREAD.Tcb.ApcState.Process]mov [edi+_ETHREAD.Tcb.IdleSwapBlock],0jz short loc_4049D7 ; 如果是一個進程內(nèi)的線程切換 跳轉(zhuǎn)mov edi,[esi+_ETHREAD.Tcb.ApcState.Process] ; 如果不是一個進程 取出目標線程_KPROCESStest [edi+_ETHREAD.pcb.LdtDescriptor.LimitLow],0FFFFh ; 判斷LdtDescriptor是否為-1jnz short loc_404A11xor eax, eaxloc_4049B8: lldt axxor eax, eaxmov gs, eax ; GS段寄存器清0 這個能解釋清除 位什么在3環(huán)單步執(zhí)行 GS會清0assume gs:GAPmov eax,[edi+_EPROCESS.Pcb.DirectoryTableBase] ; 得到目標線程CR3mov ebp,[ebx+KPCR.TSS] ; TSS寄存器mov ecx,dword ptr[edi+_EPROCESS.Pcb.IopmOffset]mov [ebp+1Ch], eax ; 將當前TSS中的CR3修改為目標進程的CR3mov cr3, eax ; 切換CR3mov [ebp+66h], cx ; 存儲IO權(quán)限位圖到TSS 當前線程的IO權(quán)限位圖 Windows2000以后不用了jmp short loc_4049D7 ; ---------------------------------------------------------------------------db 8Dh, 49h, 0 ; ---------------------------------------------------------------------------loc_4049D7: mov eax, [ebx+18h]mov ecx, [ebx+3Ch]mov [ecx+3Ah], axshr eax, 10hmov [ecx+3Ch], almov [ecx+3Fh], ahinc dword ptr [esi+4Ch]inc dword ptr [ebx+61Ch]pop ecxmov [ebx], ecxcmp byte ptr [esi+49h], 0jnz short loc_404A00popfxor eax, eaxretnWindows下TSS只有3個用到的分別是esp0,cr3,io權(quán)限位圖,io權(quán)限位圖從Windows2000以后就沒使用了。
總結(jié)
以上是生活随笔為你收集整理的9.Windows线程切换_TSS的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 8.Windows线程切换_时间片管理
- 下一篇: 10.Windows线程切换_FS段寄存