還記得嗎。我們用調用門和lcall指令實現特權級由低到高的轉移.
假設我們想由代碼A轉移到代碼B,運用一個調用門G,即調用門G中的目標選擇子指向代碼B的段。實際上我們要考慮4個要素:CPL、RPL、DPL_B(代碼B的DPL)、DPL_G(調用門G的DPL)。
第一步,當A訪問調用門G時,規則相當於訪問一個資料區段,要求CPL和RPL都小於或者等於DPL_G.也就是CPL和RPL需要在更高的特權級上。
第二步,除了上面系統還將比較CPL和DPL_B。如果是一致程式碼片段的話,要求DPL_B<=CPL;如果是非一致程式碼片段的話,call指令要求DPL_B<=CPL;jmp指令要求DPL_B==CPL.
當我們用call和調用門實現從ring3到ring0的轉移時,會從TSS載入ring0的堆棧STACKR0,然後將調用者ring3的ss、esp壓入新堆棧STACKR0,然後從調用者堆棧STACKR3中複製Param Count個參數併入棧,然後將當前ring3的cs和ip入棧,然後載入調用門中的新的cs和ip,開始執行被調用者的過程。
TSS結構如下: [plain] view plain copy LABEL_TSS: .4byte 0 # Back .4byte TopOfStack # 0 級堆棧 .4byte SelectorStack .4byte 0 # 1 級堆棧 .4byte 0 # .4byte 0 # 2 級堆棧 .4byte 0 # .4byte 0 # CR3 .4byte 0 # EIP .4byte 0 # EFLAGS .4byte 0 # EAX .4byte 0 # ECX .4byte 0 # EDX .4byte 0 # EBX .4byte 0 # ESP .4byte 0 # EBP .4byte 0 # ESI .4byte 0 # EDI .4byte 0 # ES .4byte 0 # CS .4byte 0 # SS .4byte 0 # DS .4byte 0 # FS .4byte 0 # GS .4byte 0 # LDT .2byte 0 # 調試陷阱標誌 .2byte . - LABEL_TSS + 2 # I/O位元影像基址 .byte 0xff # I/O位元影像結束標誌 .set TSSLen,(. - LABEL_TSS)
不過我想在一個開機磁區內搞定,而我們只用到了0級堆棧,所有我寫成了這樣: [plain] view plain copy LABEL_TSS: .4byte 0 /* Back Link */ .4byte TopOfStackR0 /* ESP0 */ .4byte SelectorStackR0 /* SS0 */ .set TSSLen, (. - LABEL_TSS)
添加ring0的堆棧: [plain] view plain copy LABEL_STACKR0: .space 20, 0 .set TopOfStackR0, (. - LABEL_STACKR0)
添加ring0堆棧的描述符和TSS的描述符以及對應的選擇子,然後初始化
Descriptor_STACKR0:Descriptor(0,TopOfStackR0, (DA_DRWA + DA_32))
LABEL_DESC_TSS: Descriptor(0, (TSSLen - 1), DA_386TSS)
.set SelectorStackR0, (Descriptor_STACKR0 - GDT_START)
.set SelectorTSS, (LABEL_DESC_TSS - GDT_START)
InitDescrptor(Descriptor_STACKR0,LABEL_STACKR0);
InitDescrptor(LABEL_DESC_TSS,LABEL_TSS);
將調用門描述符的DPL改為DA_DPL3,將其選擇子的RPL改為SA_RPL3
Descriptor_Gate_Call:Gate(Selector_Code_Gate,0,0,(DA_386CGate+DA_DPL3))
.set Selector_Code_Gate,(Descriptor_CODE_GATE-GDT_START+ SA_RPL3)
添加載入TSS的代碼:
movw $(SelectorTSS), %ax /* Load TSS to TR register */
ltr %ax
在ring3代碼中列印完字元‘3’後添加
lcall $Selector_Gate_Call,$0
回到ring0
代碼如下: [plain] view plain copy #define Descriptor(base,lim,attr)\ .word lim&0xffff;\ .word base&0xffff;\ .byte (base>>16)&0xff;\ .word ((lim>>8)&0xf00)|(attr&0x0f0ff);\ .byte ((base>>24)&0xff) /* *InitDescrptor(Descriptor,SegBase)初始化描述符函數 *Descriptor:要初始化的描述符 *SegBase:段基址 */ #define InitDescrptor(Descriptor,SegBase)\ xor %eax,%eax; \ mov %cs,%ax ; \ shl $4,%eax ; \ addl $(SegBase), %eax ;\ movw %ax, (Descriptor + 2);\ shr $16, %eax;\ movb %al, (Descriptor + 4);\ movb %ah, (Descriptor + 7) #define Gate(Selector,Offset,PCount,Attr)\ .2byte (Offset&0xffff);\ .2byte (Selector);\ .2byte (PCount&0x1f)|((Attr<<8)&0xff00);\ .2byte ((Offset>>16)&0xffff) DA_386CGate = 0x8c DA_C = 0x98 DA_32 = 0x4000 DA_DRW = 0x92 DA_DRWA=0x93 SA_TIL = 0x4 DA_LDT = 0x82 SA_RPL3 = 3 DA_DPL0=0x00 DA_DPL1=0x20 DA_DPL2=0x40 DA_DPL3=0x60 DA_386TSS=0x89 .text .globl start .code16 start: jmpl $0x0, $code /**----------------------------------------------------------------- * 通用描述元表: GDT *-------------------------------*/ GDT_START: Descriptor_DUMMY: Descriptor(0x0,0x0,0x0) Descriptor_CODE32:Descriptor(0x0,0xffffffff,DA_C+DA_32) Descriptor_STACKR0:Descriptor(0,TopOfStackR0, (DA_DRWA + DA_32)) Descriptor_VIDEO: Descriptor(0xb8000,0x0ffff,DA_DRW + DA_DPL3) Descriptor_CODE_GATE:Descriptor(0x0,CodeGLen,DA_C+DA_32) Descriptor_CODE3:Descriptor(0x0,0xffffffff,DA_C+DA_32+DA_DPL3) Descriptor_STACKR3:Descriptor(0,TopOfStackR3, (DA_DRWA + DA_32 + DA_DPL3)) LABEL_DESC_TSS: Descriptor(0, (TSSLen - 1), DA_386TSS) /*門描述符*/ Descriptor_Gate_Call:Gate(Selector_Code_Gate,0,0,(DA_386CGate+DA_DPL3)) GDT_END: GdtPtr: .word (GDT_END-GDT_START)-1 # so does gdt .long GDT_START # This will be rewrite by code. /**----------------------------------------------------------------- * GDT中的選擇子 *-------------------------------*/ .set selector_Code32,(Descriptor_CODE32-GDT_START) .set SelectorStackR0, (Descriptor_STACKR0 - GDT_START) .set Selector_Video,(Descriptor_VIDEO-GDT_START) .set Selector_Code_Gate,(Descriptor_CODE_GATE-GDT_START+ SA_RPL3) .set selector_CodeR3,(Descriptor_CODE3-GDT_START+SA_RPL3) .set SelectorStackR3,(Descriptor_STACKR3- GDT_START + SA_RPL3) .set SelectorTSS, (LABEL_DESC_TSS - GDT_START) /*調用門選擇子*/ .set Selector_Gate_Call,(Descriptor_Gate_Call-GDT_START) /* 32-bit ring 3 stack segment. */ .align 4 LABEL_STACKR0: .space 20, 0 .set TopOfStackR0, (. - LABEL_STACKR0) LABEL_STACKR3: .space 20, 0 .set TopOfStackR3, (. - LABEL_STACKR3) LABEL_TSS: .4byte 0 /* Back Link */ .4byte TopOfStackR0 /* ESP0 */ .4byte SelectorStackR0 /* SS0 */ .set TSSLen, (. - LABEL_TSS) /****************************************** *程式從這裡開始 */ code: mov %cs,%ax mov %ax,%ds mov %ax,%es mov %ax,%ss mov $0x8000,%sp /*初始全域描述符Descriptor_CODE32*/ InitDescrptor(Descriptor_CODE32,LABEL_SEG_CODE32); /*初始全域描述符Descriptor_CODE_GATE*/ InitDescrptor(Descriptor_CODE_GATE,LABEL_CODE_G); /*初始全域描述符LABEL_STACKR0 ring0堆棧*/ InitDescrptor(Descriptor_STACKR0,LABEL_STACKR0); /*初始全域描述符LABEL_STACKR3 ring3堆棧*/ InitDescrptor(Descriptor_STACKR3,LABEL_STACKR3); /*初始全域描述符Descriptor_CODE3*/ InitDescrptor(Descriptor_CODE3,LABEL_CODE_3); InitDescrptor(LABEL_DESC_TSS,LABEL_TSS); /*載入gdtr即將通用描述元表gdt的首地址和gdt的界限賦給gdtr寄存器*/ lgdt GdtPtr /*關中斷*/ cli /*開啟地址線A20*/ inb $0x92,%al or $0x02,%al outb %al,$0x92 /*設定cr0寄存器,切換到保護模式*/ movl %cr0,%eax or $1,%eax movl %eax,%cr0 /*真正進入保護模式,執行此命令後CS=0x8,IP=0*/ ljmp $selector_Code32,$0 LABEL_SEG_CODE32: .align 32 .code32 movw $(SelectorStackR0), %ax movw %ax, %ss movl $(TopOfStackR0), %esp movw $Selector_Video,%ax movw %ax,%gs/* 視頻段選擇子(目的)*/ movl $((80*11+79)*2),%edi/*第11行,79列*/ movb $0x0c,%ah/*高四位表示黑底,低四位表示紅字*/ movb $'P',%al/*顯示的字元*/ movw %ax,%gs:(%edi) #ljmp $selector_CodeR3,$0 movw $(SelectorTSS), %ax /* Load TSS to TR register */ ltr %ax #lcall $Selector_Gate_Call,$0 pushl $SelectorStackR3 pushl $TopOfStackR3 pushl $selector_CodeR3 pushl $0 lret lcall $Selector_Gate_Call,$0 jmp . LABEL_CODE_G: movl $((80*12+0)*2),%edi/*第10行,0列*/ movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示紅字*/ movb $'G',%al/*要顯示的字元*/ movw %ax,%gs:(%edi) lret .set CodeGLen,(. - LABEL_CODE_G) LABEL_CODE_3: movw $Selector_Video,%ax movw %ax,%gs/* 視頻段選擇子(目的)*/ movl $((80*12+10)*2),%edi/*第10行,0列*/ movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示紅字*/ movb $'3',%al/*要顯示的字元*/ movw %ax,%gs:(%edi) lcall $Selector_Gate_Call,$0 jmp . .set Code3Len,(. - LABEL_CODE_3) .org 0x1fe, 0x90 .word 0xaa55