还记得吗?我们用调用门和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