特权级--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                                        //将栈中的内容弹出   

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
rtCell 实时微内核-具有下列功能: 1. 完全抢占的实时微内核结构,独立的内核栈,中断和系统调用均切换到内核栈执行; 2. 256(64、32)个优先,0为最高优先(系统保留),256(64、32)为空闲优先; 3. 不同优先任务完全抢占,同优先之间可按先进先出或时间片轮转方式执行; 4. 在一系统(定时器服务)任务中实现内核定时器,用于超时等待内核对象、周期性定 时器、任务延迟、一次定时(此时需定义一超时后执行的过程);此服务任务的优先 由其客户任务的最高优先驱动,随之动态改变,以消除隐式优先反转现象; 5. 提供任务(Task)、互斥锁(Mutex)、信号量(Semaphore)、位域标志(Flag)、 定时器(Timer)、优先消息(Message)和环形队列(Ring buffer)内核对象; 6. 任何内核对象用一整数ID标识,而非指针,从而可避免用户任务野指针的副作用,内 核对象总数不超过61440(即60K); 7. 互斥锁支持优先继承和优先置顶协议,在创建时设置该协议,且总按优先等待, 优先继承协议时仅支持同一互斥锁的嵌套调用,优先置顶协议还可支持不同互斥 锁的多次嵌套调用; 8. 其它对象的等待方式有:优先等待和先进先出(节省内存)等待,在创建时设置; 9. 内核数据的同步,除在任务切换,及任务和内核之间切换堆栈时暂时关中断外,其它 地方均以延迟过程调用(DPC)方式执行; 10. 任务对象支持异步过程调用(Window用语APC,相当于UNIX中的信号机制),从而可 引导任务异步的执行一个过程(前提是任务栈不小于1024字节),此过程将在该任务 下次被调度时执行; 11. 删除避免机制,拥有互斥锁的任务及处于占有状态的互斥锁均具有防止被删除的机制, 要删除拥有互斥锁的任务必须自行终止或调用任务终止函数,而要删除任一个互斥锁 则必须先使其处于空闲状态,即没有任何任务占有此互斥锁,否则禁止删除; 12. 对象命名机制,同类内核对象可用唯一的名称标识来获取其ID,达到引用目的。 13. 在内核中实现了中断的进出接口,因此用户中断处理只需写标准的C函数,而不必关 心中断底层处理的细节; 14. 系统调用以陷阱指令(x86中int指令)实现,易于扩展到“内存保护”的进程模式; 15. 在内核库之外提供了一个简单的堆内存分配机制,用于内核对象动态内存分配时调用; 16. 支持毫秒定时器,内核定时器周期为一毫秒; 17. 支持 X387/287 硬件浮点协处理器的任务状态保护,被动方式的任务浮点状态切换(开 中断执行,由于使用了特权指令实现,因此只能在纯DOS实模式下或虚拟机X386/X387及 后续机型上执行,而无法在Windows的DOS窗口中运行,但可在DOS的全屏方式下运行)。 giCell 视口裁减及消隐处理引擎-功能如下: 1. 完善而精巧的多视口裁剪和消隐处理引擎,与微内核rtCell紧密结合; 2. 真正的事件(或消息)驱动的多窗口(视口)技术,支持顶层窗口和透明窗口的显示和 裁剪处理; 3. 当前支持Label、Edit、Botton、Slider、Listbox、TreeView、ListView、Scrollbar和 Checkbox控件,其中的Edit控件支持剪切、复制和粘贴(ctrl+x,ctrl+c,ctrl+v); 4. 类 Windos 窗口,支持平移、缩放,光标切换、窗口系统按钮,及窗口和控件的过程回调; 5. 基于透明视口(或窗口)的裁剪和消隐处理,可生成任何非矩形(多态)窗口,本示例 中的三角形窗口就是基于透明视口来实现的; 7. 支持图形内存设备(GDC),有效避免窗口重绘时闪烁,易于实现视频及动画处理; 8. ListView支持标题栏平移和缩放,Scrollbar支持鼠标滚轮驱动; 9. 内存需求小,窗口和控件的缺省状态均不使用GDC(而是采用直接屏技术),所耗内存小, 因此实用性强,包括rtCell调度器、鼠标、键盘及图形驱动的库文件在DOS下仅70余K。 关于可文件Engine.lib和mcOutLib.obj: 1. 考虑到DOS内存的限制,库文件Engine.lib中的rtCell内核仅支持32个任务优先(因为 优先队列太占用内存),这样即使在640K内存下,也可创建上数百个内核及GUI对象,可满 足一定规模的应用程序要求; 2. 库文件mcOutLib.obj是目录giCell\mcOSLib下文件的编译结果,用于处理任务的浮点协 处理器(硬件)状态切换,任务浮点数状态初始化,内存分配,信息显示等操作(主要用于 内核),用户也可自己编译giCell\mcOSLib目录下的文件,注意:Borland C/C++ 3.1可能无 法识别其中的某些浮点数操作指令; 3. 文件MAIN.C是对Engine.lib使用的具体实例,在Borland C/C++ 3.1中编译时必须打开X 387/287选项和C函数参数传递约定,此文件还对任何使用透明窗口来生成非矩形窗口,以及 如何使用GDC生成动画进行了演示; 4. 注意其中的一些执行顺序:浮点数操作不得放到回调函数中执行,而只能在其它任务中 执行(可从回调函数中向其它任务发送消息来实现),否则程序将进行无限循环; 5. 因为浮点协处理器的任务状态切换机制使用了特权指令,所生成的可执行文件只能在纯 DOS实模式下或虚拟机X386/X387及后续机型上执行,而无法在Windows的DOS窗口中运行; 6. 由MAIN.C所生成的可执行文件在AMD机器DOS实模式、X86虚拟机qemu-0.9.0-windows以及 Bochs-2.1.1下均执行良好,注意:生成的可执行文件依然是16位实模式。 压缩文件中包含窗口及其子控件的源代码,演示文件MAIN.C和DateTime.c,以及一个专用于 Borland C/C++ 3.1(GUI.DSK, GUI.PRJ)的工程文件。能力所限,不足之处,敬请指正! 请将其中的“BUG”发送到邮件:[email protected], [email protected],多谢!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值