學(xué)習(xí)筆記
《x86匯編語言:從實模式到保護(hù)模式》
http://www.reibang.com/p/d481cb547e9f
運行結(jié)果
代碼使用
-
nasmide.exe 編譯源碼文件 :加載程序
c13_mbr.asm
慷荔,內(nèi)核程序c15_core.asm
,用戶程序c15.asm
; -
fixvhdwr.exe 寫扇區(qū)二進(jìn)制
.bin
文件:c13_mbr.bin(邏輯扇區(qū)號LBA:0)
宫患、c15_core.bin(LBA:1)
檀蹋、c15.bin(LBA:50)
哩掺; - 運行
VM virtual box
.
執(zhí)行完兩次任務(wù)切換(CALL一次,JMP一次)后的內(nèi)存以及GDT狀態(tài)
- 如圖所示厘擂,被加載到內(nèi)存的昆淡,紅色文字以及綠色文字代表的內(nèi)容均來自于同一個用戶程序
c15.asm
; - 這說明刽严,一個程序可以對應(yīng)著多個運行中的副本昂灵,或者說多個任務(wù),它們彼此之間沒有任何關(guān)系舞萄,在內(nèi)存中的位置不同眨补,運行狀態(tài)也不一樣;
- 正因如此鹏氧,即便兩次切換都是切換到同一個用戶程序渤涌,但本質(zhì)上是切換到不同的任務(wù)佩谣,加上沒有寫任何內(nèi)存管理的代碼(比如重新釋放內(nèi)存)把还,之前的任務(wù)一直留在內(nèi)存里;
任務(wù)管理器
-
任務(wù)管理器茸俭,又稱程序管理器:創(chuàng)建
0特權(quán)級
的內(nèi)核任務(wù)吊履,并將當(dāng)前正在執(zhí)行的內(nèi)核代碼段劃歸該任務(wù),當(dāng)前代碼的作用是創(chuàng)建其他任務(wù)调鬓,管理它們艇炎,所以稱做任務(wù)管理器或者叫程序管理器;
三個TSS描述符
[如圖黑色和灰色部分文字]程序管理器的TSS描述符(位于內(nèi)核程序c15_core.asm
:標(biāo)號start
后面)
;為程序管理器的TSS分配內(nèi)存空間
mov ecx,104 ;為該任務(wù)的TSS分配內(nèi)存
call sys_routine_seg_sel:allocate_memory
mov [prgman_tss+0x00],ecx ;保存程序管理器的TSS基地址
;在程序管理器的TSS中設(shè)置必要的項目
mov word [es:ecx+96],0 ;沒有LDT腾窝。處理器允許沒有LDT的任務(wù)缀踪。
mov word [es:ecx+102],103 ;沒有I/O位圖居砖。0特權(quán)級事實上不需要。
mov word [es:ecx+0],0 ;反向鏈=0
mov dword [es:ecx+28],0 ;登記CR3(PDBR)
mov word [es:ecx+100],0 ;T=0
;不需要0驴娃、1奏候、2特權(quán)級堆棧。0特級不
;會向低特權(quán)級轉(zhuǎn)移控制唇敞。
;創(chuàng)建TSS描述符蔗草,并安裝到GDT中
mov eax,ecx ;TSS的起始線性地址
mov ebx,103 ;段長度(界限)
mov ecx,0x00408900 ;TSS描述符,特權(quán)級0
call sys_routine_seg_sel:make_seg_descriptor
call sys_routine_seg_sel:set_up_gdt_descriptor
mov [prgman_tss+0x04],cx ;保存程序管理器的TSS描述符選擇子
;任務(wù)寄存器TR中的內(nèi)容是任務(wù)存在的標(biāo)志疆柔,該內(nèi)容也決定了當(dāng)前任務(wù)是誰咒精。
;下面的指令為當(dāng)前正在執(zhí)行的0特權(quán)級任務(wù)“程序管理器”后補手續(xù)(TSS)。
ltr cx
- 程序管理器可以沒有自己的LDT旷档,可以將自己使用的段描述符安裝在GDT中模叙;
-
mov word [es:ecx+0],0
,設(shè)置TSS指針域(結(jié)合TSS的格式來看鞋屈,此時ES指向0~4GB內(nèi)存空間,ECX是TSS基地址
) - 程序管理器的TSS描述符必須安裝在GDT中向楼;
- 使用指令
ltr
,將當(dāng)前任務(wù)的TSS選擇子傳送到處理器的TR寄存器谐区;
ltr指令執(zhí)行后湖蜕,處理器用該選擇子訪問GDT
找到相對應(yīng)的TSS描述符,將其B位置“1”
表示該任務(wù)正在執(zhí)行中(或者處于掛起狀態(tài))
同時宋列,還要將該描述符傳送到TR寄存器的描述符高速緩存器中昭抒。
子程序load_relocate_program 里TSS相關(guān)代碼(位于內(nèi)核程序c15_core.asm
)
TSS 與TCB 一 一對應(yīng)
- 登記 TSS基地址、TSS選擇子 到 TCB(這樣理解炼杖,從任務(wù)A切換到任務(wù)B時灭返,這里登記用的就是任務(wù)B的TCB,登記的內(nèi)容就是任務(wù)B的 TSS基地址坤邪、TSS選擇子熙含,保證一個任務(wù)、一個TCB艇纺、一個TSS)怎静;
- 第15章的代碼,是從內(nèi)核程序切換到用戶程序的黔衡,那么內(nèi)核程序就是任務(wù)A蚓聘,用戶程序就是任務(wù)B;
- 并且盟劫,內(nèi)核程序是不需要TCB的夜牡;
- 如圖所示,第15章的代碼要分別用call 以及 jmp 各完成一次切換侣签,同一次任務(wù)我都用相同的顏色畫了TCB和TSS塘装;
;創(chuàng)建用戶程序的TSS
mov ecx,104 ;tss的基本尺寸
mov [es:esi+0x12],cx
dec word [es:esi+0x12] ;登記TSS界限值到TCB
call sys_routine_seg_sel:allocate_memory
mov [es:esi+0x14],ecx ;登記TSS基地址到TCB
...
;在GDT中登記TSS描述符
mov eax,[es:esi+0x14] ;TSS的起始線性地址
movzx ebx,word [es:esi+0x12] ;段長度(界限)
mov ecx,0x00408900 ;TSS描述符急迂,特權(quán)級0
call sys_routine_seg_sel:make_seg_descriptor
call sys_routine_seg_sel:set_up_gdt_descriptor
mov [es:esi+0x18],cx ;登記TSS選擇子到TCB
完整填寫TSS
- 注意這里填的就是TSS的內(nèi)容,不是TSS描述符蹦肴;
- 根據(jù)注釋以及TSS格式來一一填寫即可
;訪問用戶程序頭部袋毙,獲取數(shù)據(jù)填充TSS
mov ebx,[ebp+11*4] ;從堆棧中取得TCB的基地址
mov edi,[es:ebx+0x06] ;取得用戶程序加載基地址
mov edx,[es:edi+0x10] ;登記程序入口點 EIP
mov [es:ecx+32],edx ;到TSS
mov dx,[es:edi+0x14] ;登記程序代碼段 CS 選擇子
mov [es:ecx+76],dx ;到TSS
mov dx,[es:edi+0x08] ;登記堆棧段 SS 選擇子
mov [es:ecx+80],dx
mov dx,[es:edi+0x04] ;登記 程序數(shù)據(jù)段 DS(指向程序頭部段)
mov word [es:ecx+84],dx
mov word [es:ecx+72],0 ;TSS中的 ES=0
mov word [es:ecx+88],0 ;TSS中的 FS=0
mov word [es:ecx+92],0 ;TSS中的 GS=0
pushfd ;將EFLAGS寄存器的內(nèi)容壓入棧
pop edx ;再將其彈出到EDX寄存器
mov dword [es:ecx+36],edx ;登記TSS中的EFLAGS
[如圖紅色文字部分]使用call指令進(jìn)行任務(wù)切換(位于內(nèi)核程序c15_core.asm
:標(biāo)號start
后面)
;創(chuàng)建TCB 這個TCB屬于即將切換去的任務(wù)
mov ecx,0x46
call sys_routine_seg_sel:allocate_memory
call append_to_tcb_link ;將此TCB添加到TCB鏈中
push dword 50 ;用戶程序位于邏輯50扇區(qū)
push ecx ;壓入任務(wù)控制塊起始線性地址
call load_relocate_program ; 會往創(chuàng)建屬于要切換去的任務(wù)的TSS★
; 會往TCB里面填寫TSS選擇子★
;32位間接遠(yuǎn)調(diào)用指令CALL
call far [es:ecx+0x14] ;執(zhí)行任務(wù)切換
;ECX指向要切換任務(wù)(用戶程序)的TCB
;從TCB中取出TSS基地址、TSS選擇子
;CPU發(fā)現(xiàn)這是TSS選擇子冗尤,就知道要執(zhí)行任務(wù)切換
;新任務(wù)的TSS完整內(nèi)容在子程序load_relocate_program中已經(jīng)填寫完畢
[如圖綠色文字部分]使用jmp指令進(jìn)行任務(wù)切換(位于內(nèi)核程序c15_core.asm
:標(biāo)號start
后面)
;創(chuàng)建TCB 這個TCB屬于即將切換去的任務(wù)
mov ecx,0x46
call sys_routine_seg_sel:allocate_memory
call append_to_tcb_link ;將此TCB添加到TCB鏈中
push dword 50 ;用戶程序位于邏輯50扇區(qū)
push ecx ;壓入任務(wù)控制塊起始線性地址
call load_relocate_program ; 會往創(chuàng)建屬于要切換去的任務(wù)的TSS★
; 會往TCB里面填寫TSS選擇子★
;32位間接遠(yuǎn)轉(zhuǎn)移指令JMP
jmp far [es:ecx+0x14] ;執(zhí)行任務(wù)切換
;ECX指向要切換任務(wù)(用戶程序)的TCB
;從TCB中取出TSS基地址听盖、TSS選擇子
;CPU發(fā)現(xiàn)這是TSS選擇子,就知道要執(zhí)行任務(wù)切換
;新任務(wù)的TSS完整內(nèi)容在子程序load_relocate_program中已經(jīng)填寫完畢