特权级--ring0到ring3

内核要和用户程序分开,内核一定要安全,不能被用户程序干涉,但是有时候用户程序也需要读取内核的某些数据,怎么办呢?x86就引入了访问特权等级(0-3)的机制,x86 cpu共有4个特权级 level0 到 level3 其中level0特权级最高,level3特权级最高。处理器通过识别CPL、DPL、RPL这3中种特权级进行特权级检验。
CPL(Current Privilege Level)是当前执行的程序或任务的特权级。它被存储在CS和SS的第0位和第1位上。
DPL(Descriptor Privilege Level)表示段或者门的特权级。它被存储在段描述符或者门描述符的DPL字段中。
RPL(Requessted Privilege Level)是通过段选择子的第0位和第1位表现出来的。
jmp和call所能进行的代码间转移是非常有限的,对于非一致代码段,只能在相同特权级代码间转移;对于一致代码段,可以从低到高,且CPL不会改变。
我们一般用调用门和lcall指令实现特权级由低到高的转移,通过lret指令实现特权级由高到低的转移。

其实我们一直在特权级0下工作,下面我们就用lret实现特权级由高到低的转移,ring0--->ring3

#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 
  
.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_VIDEO: Descriptor(0xb8000,0x0ffff,DA_DRW + DA_DPL3)  
Descriptor_CODE_GATE:Descriptor(0x0,CodeGLen,DA_C+DA_32)
Descriptor_LDT:   Descriptor(0x0,LDTLen - 1, DA_LDT)
Descriptor_CODE3:Descriptor(0x0,0xffffffff,DA_C+DA_32+DA_DPL3)
Descriptor_STACKR3:Descriptor(0,TopOfStackR3, (DA_DRWA + DA_32 + DA_DPL3))

/*门描述符*/ 
Descriptor_Gate_Call:Gate(Selector_Code_Gate,0,0,(DA_386CGate+DA_DPL0))  
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	Selector_Video,(Descriptor_VIDEO-GDT_START)     
.set  Selector_Code_Gate,(Descriptor_CODE_GATE-GDT_START)
.set	SelectorLDT,(Descriptor_LDT-GDT_START)
.set	selector_CodeR3,(Descriptor_CODE3-GDT_START+SA_RPL3)
.set    SelectorStackR3,(Descriptor_STACKR3- GDT_START + SA_RPL3)
/*调用门选择子*/
.set	Selector_Gate_Call,(Descriptor_Gate_Call-GDT_START)

/**-----------------------------------------------------------------
 * 局部描述符表: LDT
 *-------------------------------*/
LDT_START:
/*                       段基址    段界限      属性*/
Descriptor_LDT_CODEA: Descriptor(0, CodeALen - 1, DA_C + DA_32)# Code, 32 位

.set    LDTLen,(. - LDT_START)

#LDT 选择子
.set  SelectorLDTCodeA,(0x0 + SA_TIL)



/* 32-bit ring 3 stack segment. */
.align  4
LABEL_STACKR3:
.space  10, 0
.set    TopOfStackR3, (. - LABEL_STACKR3)
msg:  
 .string "Hello world!"  
   
   
code:  
    mov     %cs,%ax     
    mov     %ax,%ds   
    mov     %ax,%es      
    mov     %ax,%ss    
    mov  $0x8000,%sp    
    /*显示HelloWorld字符串*/  
    mov $msg   ,%ax  
    mov %ax    ,%bp  
    mov $12    ,%cx  
    mov $0x1301,%ax  
    mov $0x000c,%bx  
    mov $0     ,%dl  
      
    int $0x10  
      
  
/*初始全局描述符Descriptor_CODE32*/  
InitDescrptor(Descriptor_CODE32,LABEL_SEG_CODE32); 

/*初始全局描述符Descriptor_LDT*/
InitDescrptor(Descriptor_LDT,LDT_START);
  
/*初始全局描述符Descriptor_CODE_GATE*/  
InitDescrptor(Descriptor_CODE_GATE,LABEL_CODE_G);  
/*初始全局描述符LABEL_STACKR3 */
InitDescrptor(LABEL_STACKR3,Descriptor_STACKR3);

/*初始LDT 中的描述符Descriptor_LDT_CODEA*/
InitDescrptor(Descriptor_LDT_CODEA,LABEL_CODE_A);

/*初始全局描述符Descriptor_CODE3*/  
InitDescrptor(Descriptor_CODE3,LABEL_CODE_3);

/*加载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 $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 
    
    pushl $SelectorStackR3
    pushl $TopOfStackR3
    pushl $selector_CodeR3
    pushl $0
    lret  
    
    lcall $Selector_Gate_Call,$0  
  
    #ljmp  $Selector_Code_Gate,$0
    movw $SelectorLDT,%ax
	lldt %ax/*加载lgtr*/

	ljmp	$SelectorLDTCodeA,$0	/* 跳入局部任务 LABEL_CODE_A*/
 
      
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_A:
	movw $0x10,%ax
	movw %ax,%gs/* 视频段选择子(目的)*/
	movl $((80*12+10)*2),%edi/*第10行,0列*/
	movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/
	movb $'A',%al/*要显示的字符*/
	movw %ax,%gs:(%edi)

jmp .
.set CodeALen,(. - LABEL_CODE_A)

LABEL_CODE_3:
	movw $0x10,%ax
	movw %ax,%gs/* 视频段选择子(目的)*/
	movl $((80*12+10)*2),%edi/*第10行,0列*/
	movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/
	movb $'3',%al/*要显示的字符*/
	movw %ax,%gs:(%edi)

jmp .
.set Code3Len,(. - LABEL_CODE_3)
  
.org 0x1fe, 0x90   
.word 0xaa55 


 

具体改动点如下:
DA_DRWA=0x93
SA_RPL3 = 3
DA_DPL3=0x60

我们将的描述符Descriptor_VIDEO设为DA_DPL3,添加描述符Descriptor_CODE3和Descriptor_STACKR3
Descriptor_VIDEO: Descriptor(0xb8000,0x0ffff,DA_DRW + DA_DPL3)
Descriptor_CODE3:Descriptor(0x0,0xffffffff,DA_C+DA_32+DA_DPL3)
Descriptor_STACKR3:Descriptor(0,TopOfStackR3, (DA_DRWA + DA_32 + DA_DPL3))

添加选择子selector_CodeR3和SelectorStackR3
.set selector_CodeR3,(Descriptor_CODE3-GDT_START+SA_RPL3)
.set  SelectorStackR3,(Descriptor_STACKR3- GDT_START + SA_RPL3)

ring3下的堆栈
.align  4
LABEL_STACKR3:
.space  10, 0
.set    TopOfStackR3, (. - LABEL_STACKR3)

/*初始全局描述符LABEL_STACKR3 */
InitDescrptor(LABEL_STACKR3,Descriptor_STACKR3);

/*初始全局描述符Descriptor_CODE3*/  
InitDescrptor(Descriptor_CODE3,LABEL_CODE_3);

在ring3下打印'3'
LABEL_CODE_3:
 movw $0x10,%ax
 movw %ax,%gs/* 视频段选择子(目的)*/
 movl $((80*12+10)*2),%edi/*第10行,0列*/
 movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/
 movb $'3',%al/*要显示的字符*/
 movw %ax,%gs:(%edi)

jmp .
.set Code3Len,(. - LABEL_CODE_3)

实现从ring0到ring3的跳转
pushl $SelectorStackR3      //ss入栈
    pushl $TopOfStackR3      //esp入栈
    pushl $selector_CodeR3//cs入栈
    pushl $0                              //ip入栈
    lret                                        //将栈中的内容弹出   

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值