知识复习(LDT+TSS+GATE+INTERRUPT)
【1】README
- 1.0)由于實現(xiàn)進程的切換任務,其功能涉及到 LDT + TSS +GATE + INTERRUPT;下面我們對這些內容進行復習;
- 1.1) source code from orange’s implemention of a os .
【2】知識復習(LDT+TSS+GATE + INTERRUPT)
2.1)LDT的復習
- (1)在GDT中定義 LDT 描述符;
- (2)然后在實模式下,初始化 GDT中的LDT描述符;
- (3)還要初始化 LDT中的段描述符(用局部任務代碼去初始化 LDT 中 段描述符的基地址);
- (4)加載GDT到GDTR;
- (5)切換到保護模式;
- (6)做完任務后,跳轉到局部任務(jmp SelectorLDTCodeA:0),SelectorLDTCodeA作為LDT的選擇子,用于索引LDT中段描述符,其初始化在實模式下完成;
- (7)緊接著就跳轉到該選擇子對應的任務代碼段去執(zhí)行;
2.2)對于GDT和LDT的結構,我們再做個總結
LABEL_GDT:
LABEL_DESC_LDT : Descriptor 0, LDTLen - 1, DA_LDT ; LDT
SelectorLDT equ LABEL_DESC_LDT- LABEL_GDT
LABEL_LDT :
LABEL_LDT_DESC_CODEA : Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT: + SA_TIL
; 初始化 LDT 在 GDT 中的描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_LDT
mov word [LABEL_DESC_LDT + 2], ax
shr eax, 16
mov byte [LABEL_DESC_LDT + 4], al
mov byte [LABEL_DESC_LDT + 7], ah
; 初始化 LDT 中的描述符
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_CODE_A
mov word [LABEL_LDT_DESC_CODEA+ 2], ax
shr eax, 16
mov byte [LABEL_LDT_DESC_CODEA+ 4], al
mov byte [LABEL_LDT_DESC_CODEA+ 7], ah
; Load LDT
mov ax, SelectorLDT
lldt ax
jmp SelectorLDTCodeA :0 ; 跳入局部任務
; CodeA (LDT, 32 位代碼段)
[SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A :
mov ax, SelectorVideo
mov gs, ax ; 視頻段選擇子(目的)
mov edi, (80 * 12 + 0) * 2 ; 屏幕第 10 行, 第 0 列。
mov ah, 0Ch ; 0000: 黑底 1100: 紅字
mov al, ‘L’
mov [gs:edi],
(Attention)顯然,我們發(fā)現(xiàn),加載到 ldt 寄存器 的 選擇子是 GDT中 LDT段描述符 的選擇子, 而調用局部描述符對應的目標代碼時,我們用的是 LDT 中的該代碼對應的選擇子;(干貨)
2.2)TSS的復習
- 由于每個任務可能在4個特權級間轉移,故每個任務實際上需要4個堆棧;
- 問題是:我們只有一個ss 和 esp, 那么當發(fā)生堆棧切換,我們該從哪里獲取其他堆棧的ss 和 esp 呢?
我們引入TSS, 它可以解決這個問題。 - 我們再總結一下就是:不同特權級的代碼段間的轉移(更具體點,是從低特權級->高特權級),會發(fā)生堆棧切換,使得調用者的入棧的堆棧是針對調用者本身的堆棧, 而出棧操作是針對被調用者的堆棧,即入棧和出棧的堆棧不一致,使得特權級間跳轉出錯,故引入了 TSS;
(Conclusion)我們再理一理 TSS 和 GDT 的結構關系
; 任務狀態(tài)段描述符 LABEL_DESC_TSS + 選擇子
LABEL_GDT:
………..
LABEL_DESC_TSS : Descriptor 0, TSSLen-1, DA_386TSS ; ( DA_386TSS == 89h )
SelectorTSS equ LABEL_DESC_TSS - LABEL_GDT
; TSS [add] (任務狀態(tài)段的定義)
[SECTION .tss]
ALIGN 32
[BITS 32]
LABEL_TSS :
DD 0 ; Back
DD TopOfStack ; 0 級堆棧
DD SelectorStack ;
DD 0 ; 1 級堆棧
DD 0 ;
DD 0 ; 2 級堆棧
DD 0 ;
DD 0 ; CR3
DD 0 ; EIP
DD 0 ; EFLAGS
DD 0 ; EAX
DD 0 ; ECX
DD 0 ; EDX
DD 0 ; EBX
DD 0 ; ESP
DD 0 ; EBP
DD 0 ; ESI
DD 0 ; EDI
DD 0 ; ES
DD 0 ; CS
DD 0 ; SS
DD 0 ; DS
DD 0 ; FS
DD 0 ; GS
DD 0 ; LDT
DW 0 ; 調試陷阱標志
DW $ - LABEL_TSS+ 2 ; I/O位圖基址
DB 0ffh ; I/O位圖結束標志
TSSLen equ $ - LABEL_TSS
; 初始化 TSS 描述符,實模式
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_TSS
mov word [LABEL_DESC_TSS+ 2], ax
shr eax, 16
mov byte [LABEL_DESC_TSS+ 4], al
mov byte [LABEL_DESC_TSS+ 7], ah
; Load TSS, 在保護模式中,從ring3->ring0之前
; 因為是先通過retf實現(xiàn) ring0->ring3,然后通過門實現(xiàn)ring3->ring0(門目標段的特權級為0),ring3->ring0會發(fā)生堆棧切換,所以在這之前需要加載TSS進入 tr-任務寄存器
mov ax, SelectorTSS
ltr ax ; 在任務內發(fā)生特權級變換時要切換堆棧,而內層堆棧的指針存放在當前任務的TSS中,所以要設置任務狀態(tài)段寄存器 TR。
push SelectorStack3
push TopOfStack3
push SelectorCodeRing3 ; 打印 ‘3’
push 0
retf
(Attention) 從以上代碼,初始化TSS的內存空間,創(chuàng)建 GDT中的 TSS 描述符 以及 在實模式下初始化TSS 的描述符, 最后跳轉到 保護模式,在特權級切換之前,我們把 TSS段描述符在GDT 中的選擇子加載到了 tr-任務寄存器中,這樣方便 不同特權級代碼間的切換 進行堆棧切換;
2.3)GATE的復習
(1)在GDT中定義門描述符+門選擇子 + 該門對應的代碼段描述符及其選擇子,從以下 門和門對應的代碼段描述符 的定義可以看到,門描述符存儲著該代碼段描述符的選擇子以建立它們間的聯(lián)系;
LABEL_DESC_CODE_DEST: Descriptor 0,SegCodeDestLen-1, DA_C+DA_32; 非一致代碼段,32
SelectorCodeDest equ LABEL_DESC_CODE_DEST- LABEL_GDT
; 門 目標選擇子,偏移,DCount, 屬性
LABEL_CALL_GATE_TEST : Gate SelectorCodeDest, 0, 0, DA_386CGate+DA_DPL0
SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT(2)在實模式中初始化測試調用門的代碼段描述符;(門對應的代碼段,我們稱其為調用門目標段)
; 初始化測試調用門的代碼段描述符xor eax, eaxmov ax, csshl eax, 4add eax, LABEL_SEG_CODE_DEST ; (調用門目標段基地址)mov word [LABEL_DESC_CODE_DEST + 2], axshr eax, 16mov byte [LABEL_DESC_CODE_DEST + 4], almov byte [LABEL_DESC_CODE_DEST + 7], ah(3)加載GDT到GDTR,并進入保護模式;
(4)做完任務后,測試調用門(call SelectorCallGateTest:0),注意,它這里的調用地址用的是 調用門選擇子,通過調用門選擇子->調用門描述符->門目標段選擇子->門目標段描述符->門目標段基地址,即通過調用門選擇子尋址到門目標段基地址去運行;
; 測試調用門(無特權級變換),將打印字母 ‘C’
call SelectorCallGateTest:0
2.4)中斷復習step0)構建中斷處理程序函數(shù)(在32位代碼段的保護模式中):
_UserIntHandler: UserIntHandler equ _UserIntHandler - $$mov ah, 0Ch ; 0000: 黑底 1100: 紅字mov al, 'I'mov [gs:((80 * 0 + 70) * 2)], ax ; 屏幕第 0 行, 第 70 列。iretd_SpuriousHandler: SpuriousHandler equ _SpuriousHandler - $$mov ah, 0Ch ; 0000: 黑底 1100: 紅字mov al, '!'mov [gs:((80 * 0 + 75) * 2)], ax ; 屏幕第 0 行, 第 75 列。jmp $iretdstep1)構建IDT,IDT表項也就是門(中斷門+陷阱門),主要是為中斷向量號(依據(jù)表項索引)綁定中斷處理程序,(為演示方便,特別為向量號 80h 綁定了中斷處理程序),要知道,中斷向量號 把中斷異常的處理程序 與 中斷異常類型聯(lián)系了起來;
[SECTION .idt] ALIGN 32 [BITS 32] LABEL_IDT: ; 門 目標選擇子, 偏移, DCount, 屬性 %rep 128Gate SelectorCode32, SpuriousHandler, 0, DA_386IGate %endrep .080h: Gate SelectorCode32, UserIntHandler, 0, DA_386IGate IdtLen equ $ - LABEL_IDT IdtPtr dw IdtLen - 1 ; 段界限dd 0 ; 基地址step2)實模式下,為加載IDTR做準備, 并將IDT(基地址+段界限)加載到 IDTR;
; 為加載 IDTR 作準備xor eax, eaxmov ax, dsshl eax, 4add eax, LABEL_IDT ; eax <- idt 基地址mov dword [IdtPtr + 2], eax ; [IdtPtr + 2] <- idt 基地址; 加載 GDTRlgdt [GdtPtr]; 關中斷cli; 加載 IDTRlidt [IdtPtr]step4)向主8259A寫入OCW1,以開啟定時器中斷, 然后向從8259A寫入OCW1 以屏蔽從8259A所有中斷;
; start Init8259A Init8259A:mov al, 011hout 020h, al ; 主8259, ICW1.call io_delayout 0A0h, al ; 從8259, ICW1.call io_delaymov al, 020h ; IRQ0 對應中斷向量 0x20out 021h, al ; 主8259, ICW2.call io_delaymov al, 028h ; IRQ8 對應中斷向量 0x28out 0A1h, al ; 從8259, ICW2.call io_delaymov al, 004h ; IR2 對應從8259out 021h, al ; 主8259, ICW3.call io_delaymov al, 002h ; 對應主8259的 IR2out 0A1h, al ; 從8259, ICW3.call io_delaymov al, 001hout 021h, al ; 主8259, ICW4.call io_delayout 0A1h, al ; 從8259, ICW4.call io_delaymov al, 11111110b ; 僅僅開啟定時器中斷;mov al, 11111111b ; 屏蔽主8259所有中斷out 021h, al ; 主8259, OCW1.call io_delaymov al, 11111111b ; 屏蔽從8259所有中斷out 0A1h, al ; 從8259, OCW1.call io_delayret ; over Init8259A- step5)觸發(fā)中斷 int 080h;
總結
以上是生活随笔為你收集整理的知识复习(LDT+TSS+GATE+INTERRUPT)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 古巴比伦是现在的哪个国家(位于现今的伊拉
- 下一篇: Makefile浅尝