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