还记得吗?我们用调用门和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结构如下:
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级堆栈,所有我写成了这样:
LABEL_TSS: .4byte 0 /* Back Link */ .4byte TopOfStackR0 /* ESP0 */ .4byte SelectorStackR0 /* SS0 */ .set TSSLen, (. - LABEL_TSS)
添加ring0的堆栈:
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
代码如下:
#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