特权级--ring3到ring0

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


 

 

 

你可能感兴趣的:(特权级--ring3到ring0)