任务和特权级保护(三)——《x86汇编语言:从实模式到保护模式》读书笔记34
任務(wù)和特權(quán)級保護(hù)(三)——《x86匯編語言:從實(shí)模式到保護(hù)模式》讀書筆記34
5.2.7 在GDT中創(chuàng)建LDT描述符
處理器要求在GDT中安裝每個(gè)LDT的描述符。當(dāng)要使用這些LDT時(shí),可以用它們的選擇子來訪問GDT,找到LDT描述符并把它加載到LDTR寄存器。
675 ;在GDT中登記LDT描述符 676 mov eax,[es:esi+0x0c] ;LDT的起始線性地址 677 movzx ebx,word [es:esi+0x0a] ;LDT段界限 678 mov ecx,0x00408200 ;LDT描述符,特權(quán)級0 679 call sys_routine_seg_sel:make_seg_descriptor 680 call sys_routine_seg_sel:set_up_gdt_descriptor 681 mov [es:esi+0x10],cx ;登記LDT選擇子到TCB中LDT描述符的格式如下圖:
LDT本身也是一種特殊的段,最大尺寸為64KB;
G:粒度位,用來表示LDT的界限值是以字節(jié)為單位還是以4KB為單位;
D:固定為0;
L:固定為0;
AVL和P:含義與存儲器的段描述符相同;
S:固定為0;表示系統(tǒng)的段描述符或者門描述符,以區(qū)別于存儲器的段描述符(S=1);
TYPE:固定為0010b,表示這是一個(gè)LDT描述符;
第678行:我認(rèn)為是作者的筆誤,應(yīng)該是
678 mov ecx,0x00008200第681行:將返回的選擇子(RPL=0)登記到TCB中;
5.2.8 為用戶程序創(chuàng)建TSS
關(guān)于TSS的知識,可以參考我的博文TSS詳解 ——《x86匯編語言:從實(shí)模式到保護(hù)模式》讀書筆記33
684 mov ecx,104 ;tss的基本尺寸 685 mov [es:esi+0x12],cx 686 dec word [es:esi+0x12] ;登記TSS界限值到TCB 687 call sys_routine_seg_sel:allocate_memory 688 mov [es:esi+0x14],ecx ;登記TSS基地址到TCB以上代碼做的工作有:
1. 申請TSS所需的空間(104字節(jié));
2. 登記TSS的界限值(104-1=103)和基地址到TCB;
接下來,填寫TSS表格的內(nèi)容。
1. Previous Task Link = 0;
2. 填寫ESPx和SSx(x=0,1,2)(從TCB中拷貝);
3. 填寫LDT選擇子(從TCB中拷貝);
4. 填寫I/O位圖偏移(從TCB中拷貝,等于TSS的界限值103);
5. T=0;
5.2.9 在GDT中創(chuàng)建TSS描述符
和LDT一樣,處理器要求必須在GDT中安裝TSS的描述符。
第722行:我覺得是作者的筆誤,應(yīng)該是0x00008900. G=0,P=1,DPL=0,B=0;
第725行:登記TSS的選擇子(RPL=0)到TCB;
以上5.2節(jié)的內(nèi)容,算是把過程load_relocate_program說完了,接下來說如何轉(zhuǎn)到戶程序執(zhí)行。
6. 如何轉(zhuǎn)到用戶程序執(zhí)行
任務(wù)寄存器TR總是指向當(dāng)前任務(wù)的TSS,而LDTR寄存器也總是指向當(dāng)前任務(wù)的LDT。TSS是任務(wù)的主要標(biāo)志,因此要使TR寄存器指向當(dāng)前任務(wù);而使用LDTR的原因是可以在任務(wù)執(zhí)行期間加速對段的訪問。
在多任務(wù)環(huán)境中,從舊任務(wù)切換的新任務(wù)的時(shí)候,TR和LDTR寄存器的值都會更新,以指向新任務(wù)。但是,目前我們只有一個(gè)任務(wù),而且是特權(quán)級為3的任務(wù),我們遇到的問題可以表述為:如何從任務(wù)的全局空間(處于特權(quán)級0)轉(zhuǎn)移到它自己的局部空間(處于特權(quán)級3)?
答案是分為兩步:
1. 確立身份,使TR和LDTR寄存器指向這個(gè)任務(wù);
2. 假裝從調(diào)用門返回;
6.1. TR和LDTR寄存器
TR和LDTR寄存器都包括16位的選擇器部分和描述符高速緩存器部分(如下圖所示)。選擇器部分的內(nèi)容是TSS和LDT描述符的選擇子。
6.2. ltr和lldt指令
加載任務(wù)寄存器TR的指令是ltr,其格式為
ltr r/m16加載局部描述符表寄存器LDTR的指令是lldt,其格式為
lldt r/m16原理與上述類似,只不過操作數(shù)是16位的LDT選擇子。
848 mov eax,mem_0_4_gb_seg_sel 849 mov ds,eax 850 851 ltr [ecx+0x18] ;加載任務(wù)狀態(tài)段 852 lldt [ecx+0x10] ;加載LDT注意,851~852中的ECX的值是TCB的基地址。以上的代碼執(zhí)行完,用戶任務(wù)的身份算是確立了。
6.3. 假裝從調(diào)用門返回
854 mov eax,[ecx+0x44] 855 mov ds,eax ;切換到用戶程序頭部段以上兩行,向DS中加載用戶程序頭部段的選擇子(RPL=3,TI=1)。
857 ;以下假裝是從調(diào)用門返回。摹仿處理器壓入返回參數(shù) 858 push dword [0x08] ;調(diào)用前的堆棧段選擇子 859 push dword 0 ;調(diào)用前的esp 860 861 push dword [0x14] ;調(diào)用前的代碼段選擇子 862 push dword [0x10] ;調(diào)用前的eip 863 864 retf這段代碼要結(jié)合用戶程序頭部的格式和調(diào)用門的返回過程來分析。
用戶程序頭部的格式如下圖(為了方便閱讀,我總是樂此不疲地貼圖)。
注意,被內(nèi)核重定位后的選擇子,其RPL的值都等于3.
關(guān)于調(diào)用門的返回過程,強(qiáng)烈建議復(fù)習(xí)一下我的博文調(diào)用門詳解
這篇博文中講解的從調(diào)用門的返回過程是:
858~862執(zhí)行完后,棧的布局如下(這其實(shí)是內(nèi)核的棧,并不是用戶的0特權(quán)級棧):
我們對著上面的返回步驟,一步一步來看。
1. 因?yàn)橛脩舫绦虻腃S寄存器中的RPL=3,所以在返回的時(shí)候特權(quán)級要發(fā)生改變。
2. 彈出用戶程序的EIP和CS(綠色部分)加載EIP和CS寄存器。
3. 第864行的retf指令不帶參數(shù),所以這步跳過。
4. 從棧中將用戶程序的ESP和SS(藍(lán)色部分)彈出,并把值代入寄存器ESP和SS,切換到調(diào)用者的棧(實(shí)際是用戶程序的3特權(quán)級棧)。
5. 第864行的retf指令不帶參數(shù),所以這步跳過。
6. 因?yàn)镈S中的內(nèi)容是用戶程序頭部段的選擇子,其DPL=3,所以不會把數(shù)值0傳到DS;至于ES、FS和GS,它們一般會指向內(nèi)核數(shù)據(jù)段,其DPL=0,所以這些寄存器很可能被數(shù)值0加載,所以用戶程序中應(yīng)該對它們先初始化再引用。
囿于篇幅,就寫到這里吧。下次我們正式進(jìn)入用戶程序的執(zhí)行…
總結(jié)
以上是生活随笔為你收集整理的任务和特权级保护(三)——《x86汇编语言:从实模式到保护模式》读书笔记34的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过对象引用访问成员
- 下一篇: 读入10个数,显示互不相同的数的数目,并