很久以后,等我大量翻阅关于“保护模式的特权级检查(DPL,RPL,CPL, 一致代码段,非一致代码段)”的资料后,我才发现这篇博客理解得太肤浅了,而且有错(但后面的实验步骤和代码还是可以凑合看一下的),因此特意写了另一篇(主要是转载),名为“(第三章 8 )特权级——保护模式的特权级检查(DPL,RPL,CPL, 一致代码段,非一致代码段)”。
本节见书P48~49。在IA32的分段机制中,特权级共有4个特权级别,从高到低分别是0>1>2>3. 下面通过一个例子来说明CPL、DPL、RPL.
1. 先要明确CPL、DPL、RPL的概念,以及她们在哪里
DPL ,Descriptor Privilege Level,表示段或门的特权级。它是一个静态的概念,包含于段描述符的属性字段部分(P32),只要代码写好了,每个段的特权级就定了。
以本章第一个程序chapter3/a/pmtest1.asm(见P25~)为例,
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C+DA_32 中最后一个字段指定属性,这里采用默认的DPL特权级0(没有显式指定)
RPL ,Requested Privilege Level,是“调用过程”的选择子的第0位和第1位(P32下面)。
以本章第一个程序chapter3/a/pmtest1.asm为例,
...
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
至此,如果SelectorCode32对应的代码段[SECTION .s32]被调用时(如执行jmp dword SelectorCode32:0),RPL就会被设置成SelectorCode32的第0位和第1位。此时执行jmp dword SelectorCode32:0的过程称“调用过程”,而[SECTION .s32]这个代码段称为“被调用过程”。
CPL ,Current Privilege Level,是“被调用过程”(当前执行程序或任务)的特权级,它被存储在cs和ss的第0位和第1位上。
以本章第一个程序chapter3/a/pmtest1.asm为例,在[SECTION .s16]最后,
jmp dword SelectorCode32:0执行之前,CPL是[SECTION .s16]的DPL,此时为0;
jmp dword SelectorCode32:0执行时,会将SelectorCode32装入cs(注:选择子和cs都是两个字节的,见P32),因为CPL是cs的第0位和第1位,所以CPL就变成了SelectorCode32对应段的DPL,此时也是0.
CPL虽然直接由cs中的最低2位决定,但最终是由“jmp到被调用段时指定的选择子”(此处jmp dword SelectorCode32:0,被调用段的选择子SelectorCode32中最低2位为0,则跳转后CPL=0)决定的。
对于数据的访问,特权级检验还是比较简单的,只要CPL和RPL都小于被访问的数据段的DPL就可以了。
2. 例子
执行方式如下:
1. asm生成com文件
[hadoop@sam1 c]$ pwd
/home/hadoop/Desktop/OSImpl/一个操作系统的实现/chapter3/c
[hadoop@sam1 c]$ nasm pmtest3.asm -o pmtest3.com
2. 将编译好的com文件复制到软盘b(镜像为pm.img)
[hadoop@sam1 bochs-2.6]$ pwd
/home/hadoop/Desktop/OSImpl/bochs-2.6
[hadoop@sam1 bochs-2.6]$ sudo mount -o loop pm.img /mnt/floppy/
[hadoop@sam1 bochs-2.6]$ sudo cp /home/hadoop/Desktop/OSImpl/一个操作系统的实现/chapter3/c/pmtest3.com /mnt/floppy/
[hadoop@sam1 bochs-2.6]$ sudo umount /mnt/floppy/
3. 启动freedos(软盘a:镜像freedos.img),加载软盘b(镜像pm.img)中的com文件
[hadoop@sam1 bochs-2.6]$ ./bochs
发现根本不能运行,这就对了
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW+DA_DPL1; Data
...
SelectorDataequLABEL_DESC_DATA- LABEL_GDT + SA_RPL3
...
[SECTION .s32]; 32 位代码段. 由实模式跳入.
LABEL_SEG_CODE32:
movax, SelectorData
movds, ax; 数据段选择子
... 然后尝试访问Data段,就会失败,因为CPL=0 (当前段[SECTION .s32]的特权级),RPL=3(使用的段选择子SelectorData里面末两位),被访问数据段的DPL=1。不满足 CPL<DPL && RPL<DPL
下面是完整代码:
; ==========================================
; pmtest3.asm
; 编译方法:nasm pmtest3.asm -o pmtest3.com
; ==========================================
%include"pm.inc"; 常量, 宏, 以及一些说明
org0100h
jmpLABEL_BEGIN
[SECTION .gdt]
; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW; Normal 描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段, 32
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C; 非一致代码段, 16
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW+DA_DPL1; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA + DA_32; Stack, 32 位
LABEL_DESC_LDT: Descriptor 0, LDTLen - 1, DA_LDT; LDT
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW; 显存首地址
; GDT 结束
GdtLenequ$ - LABEL_GDT; GDT长度
GdtPtrdwGdtLen - 1; GDT界限
dd0; GDT基地址
; GDT 选择子
SelectorNormalequLABEL_DESC_NORMAL- LABEL_GDT
SelectorCode32equLABEL_DESC_CODE32- LABEL_GDT
SelectorCode16equLABEL_DESC_CODE16- LABEL_GDT
SelectorDataequLABEL_DESC_DATA- LABEL_GDT + SA_RPL3
SelectorStackequLABEL_DESC_STACK- LABEL_GDT
SelectorLDTequLABEL_DESC_LDT- LABEL_GDT
SelectorVideoequLABEL_DESC_VIDEO- LABEL_GDT
; END of [SECTION .gdt]
[SECTION .data1] ; 数据段
ALIGN32
[BITS32]
LABEL_DATA:
SPValueInRealModedw0
; 字符串
PMMessage:db"In Protect Mode now. ^-^", 0; 进入保护模式后显示此字符串
OffsetPMMessageequPMMessage - $$
StrTest:db"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
OffsetStrTestequStrTest - $$
DataLenequ$ - LABEL_DATA
; END of [SECTION .data1]
; 全局堆栈段
[SECTION .gs]
ALIGN32
[BITS32]
LABEL_STACK:
times 512 db 0
TopOfStackequ$ - LABEL_STACK - 1
; END of [SECTION .gs]
[SECTION .s16]
[BITS16]
LABEL_BEGIN:
movax, cs
movds, ax
moves, ax
movss, ax
movsp, 0100h
mov[LABEL_GO_BACK_TO_REAL+3], ax
mov[SPValueInRealMode], sp
; 初始化 16 位代码段描述符 ==> [LABEL_SEG_CODE16]在“GDT本段对应的全局描述符”中已经设置了“段长度”和“段属性”,这里实际上是把“段基址”混入进去,使得“GDT本段对应的全局描述符”完整了!!!
movax, cs
movzxeax, ax
shleax, 4
addeax, LABEL_SEG_CODE16
movword [LABEL_DESC_CODE16 + 2], ax
shreax, 16
movbyte [LABEL_DESC_CODE16 + 4], al
movbyte [LABEL_DESC_CODE16 + 7], ah
; 初始化 32 位代码段描述符
xoreax, eax
movax, cs
shleax, 4
addeax, LABEL_SEG_CODE32
movword [LABEL_DESC_CODE32 + 2], ax
shreax, 16
movbyte [LABEL_DESC_CODE32 + 4], al
movbyte [LABEL_DESC_CODE32 + 7], ah
; 初始化数据段描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_DATA
movword [LABEL_DESC_DATA + 2], ax
shreax, 16
movbyte [LABEL_DESC_DATA + 4], al
movbyte [LABEL_DESC_DATA + 7], ah
; 初始化堆栈段描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_STACK
movword [LABEL_DESC_STACK + 2], ax
shreax, 16
movbyte [LABEL_DESC_STACK + 4], al
movbyte [LABEL_DESC_STACK + 7], ah
; 初始化 LDT 在 GDT 中的描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_LDT
movword [LABEL_DESC_LDT + 2], ax
shreax, 16
movbyte [LABEL_DESC_LDT + 4], al
movbyte [LABEL_DESC_LDT + 7], ah
; 初始化 LDT 中的描述符
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_CODE_A
movword [LABEL_LDT_DESC_CODEA + 2], ax
shreax, 16
movbyte [LABEL_LDT_DESC_CODEA + 4], al
movbyte [LABEL_LDT_DESC_CODEA + 7], ah
; 为加载 GDTR 作准备
xoreax, eax
movax, ds
shleax, 4
addeax, LABEL_GDT; eax <- gdt 基地址
movdword [GdtPtr + 2], eax; [GdtPtr + 2] <- gdt 基地址
; 加载 GDTR
lgdt[GdtPtr]
; 关中断
cli
; 打开地址线A20
inal, 92h
oral, 00000010b
out92h, al
; 准备切换到保护模式
moveax, cr0
oreax, 1
movcr0, eax
; 真正进入保护模式
jmpdword SelectorCode32:0; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY:; 从保护模式跳回到实模式就到了这里
movax, cs
movds, ax
moves, ax
movss, ax
movsp, [SPValueInRealMode]
inal, 92h; ┓
andal, 11111101b; ┣ 关闭 A20 地址线
out92h, al; ┛
sti; 开中断
movax, 4c00h; ┓
int21h; ┛回到 DOS
; END of [SECTION .s16]
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS32]
LABEL_SEG_CODE32:
movax, SelectorData
movds, ax; 数据段选择子
movax, SelectorVideo
movgs, ax; 视频段选择子
movax, SelectorStack
movss, ax; 堆栈段选择子
movesp, TopOfStack
; 下面显示一个字符串
movah, 0Ch; 0000: 黑底 1100: 红字
xoresi, esi
xoredi, edi
movesi, OffsetPMMessage; 源数据偏移
movedi, (80 * 10 + 0) * 2; 目的数据偏移。屏幕第 10 行, 第 0 列。
cld
.1:
lodsb ; [esi] --byte--> al
testal, al ; 若已经到达最后一个字符0,则结束循环显示每个字符
jz.2
mov[gs:edi], ax ; ax(ah: 黑底红字 al: ASCII字符) --2 bytes--> [gs:edi]
addedi, 2 ; [gs:edi] 向后跳两个字节
jmp.1 ; 显示下一个字符
.2:; 显示完毕
callDispReturn
; Load LDT
movax, SelectorLDT
lldtax
jmpSelectorLDTCodeA:0; 跳入局部任务
; ------------------------------------------------------------------------
DispReturn:
pusheax
pushebx
moveax, edi
movbl, 160
divbl
andeax, 0FFh
inceax
movbl, 160
mulbl
movedi, eax
popebx
popeax
ret
; DispReturn 结束---------------------------------------------------------
SegCode32Lenequ$ - LABEL_SEG_CODE32
; END of [SECTION .s32]
; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
[SECTION .s16code]
ALIGN32
[BITS16]
LABEL_SEG_CODE16:
; 跳回实模式:
movax, SelectorNormal
movds, ax
moves, ax
movfs, ax
movgs, ax
movss, ax
moveax, cr0
andal, 11111110b
movcr0, eax
LABEL_GO_BACK_TO_REAL:
jmp0:LABEL_REAL_ENTRY; 段地址会在程序开始处被设置成正确的值
Code16Lenequ$ - LABEL_SEG_CODE16
; END of [SECTION .s16code]
; LDT
[SECTION .ldt]
ALIGN32
LABEL_LDT:
; 段基址 段界限 属性
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位
LDTLenequ$ - LABEL_LDT
; LDT 选择子
SelectorLDTCodeAequLABEL_LDT_DESC_CODEA- LABEL_LDT + SA_TIL
; END of [SECTION .ldt]
; CodeA (LDT, 32 位代码段)
[SECTION .la]
ALIGN32
[BITS32]
LABEL_CODE_A:
movax, SelectorVideo
movgs, ax; 视频段选择子(目的)
movedi, (80 * 12 + 0) * 2; 屏幕第 10 行, 第 0 列。
movah, 0Ch; 0000: 黑底 1100: 红字
moval, 'L'
mov[gs:edi], ax
; 准备经由16位代码段跳回实模式
jmpSelectorCode16:0
CodeALenequ$ - LABEL_CODE_A
; END of [SECTION .la]
小结:
理解“选择子”和DPL, RPL, CPL四者的转化和对应关系。
相关推荐
### 操作系统篇-调用门与特权级(CPL、DPL和RPL) #### 一、前言 在深入探讨操作系统的核心机制时,理解保护模式下的调用门与特权级至关重要。特权级和调用门是保护模式下确保系统稳定性和安全性的关键组成部分。...
内核 系统 DPL RPL CPL , 调用门等
访问数据段或堆栈段时,默认使用CPU和RPL中的最小特权级去访问数据段,因此max{CPL, RPL} ≤ DPL,否则访问会被拒绝。 **2. 代码段访问** - **转跳规则**:所有程序转跳中,CPU不会将段选择子的RPL赋给转跳后程序...
然而,当用户程序试图访问数据段时,DS寄存器的RPL会被设置为用户进程的CPL(通常是3),此时若数据段的DPL为0,根据特权级检查规则(CPL≤DPL且RPL≤DPL),访问将被拒绝,因为RPL为3无法满足条件。 门结构在特权...
4个特权级(或特权层) ,0级到3级。数值越大特权越小。一般用把系统内核放在0级,系统的其他服务程序位于1、2级,3级则是应用软件。一般情况下代码都在自己的级别下做自己 的工作,同一级别之间可以相互访问,而一般...
特权级的检查涉及CPL(Current Privilege Level)、RPL(Request Privilege Level)和DPL(Descriptor Privilege Level)。CPL存储在CS寄存器中,表示当前执行代码的权限级别;RPL是段选择子的一部分,表明请求访问...
特权级(CPL、RPL、DPL、IOPL)用于限制不同级别程序的权限,防止误操作。分页机制也有保护作用,通过页表的权限位(如R/W、U/S)来控制对内存页面的访问,确保数据的安全。 6. **两次设置GDT的原因**: 在`setup`...
体现:1)在GDT、LDT及IDT中,均有自己界限,特权级等属性,这是对描述符所描述的对象的保护2)在不同特权级间访问时,系统会对CPL、RPL、DPL、IOPL等进行检验,对不同层级的程序进行保护,同还限制某些特殊指令的...
- 在不同特权级间的访问时,系统会对 CPL、RPL、DPL、IOPL 等进行检查,保护不同层级的程序,并限制某些特殊指令的使用。 - 分页机制通过 PDE 和 PTE 中的 R/W 和 U/S 等属性提供了页级别的保护,同时也通过将线性...
最后根据特权级规则,只有当 Max(CPL, RPL) ≤ DPL 时,才允许访问该段,否则产生异常 13。 Window s 操作系统在 80x86CPU 中的内存管理单元(MMU)的硬件工作原理,实现了内存单元的段页式寻址、保护检查和虚拟...
中断描述符表(IDT)用于管理中断和异常,确保不同的特权级访问的合法性,CPL(当前特权级)、RPL(请求特权级)和DPL(描述符特权级)是控制访问权限的关键元素。 总的来说,操作系统设计涉及多方面的复杂交互,...
数据访问的保护规则规定,DPL(描述符特权级)必须大于等于MAX(CPL, RPL),其中CPL是当前程序的特权级,RPL是请求特权级。段间调用或跳转时,需要考虑限长和特权级的比较,以确保安全的代码执行。 【指令系统】 ...
- **RPL**: 请求特权级,指在访问描述符时请求的特权级。 - **DPL**: 描述符特权级,描述符本身的特权级。 - **CPL**: 当前特权级,执行代码所在的特权级。 #### 5. 调用门机制 - **定义**:调用门是一种特殊的系统...
在实验过程中,我们了解到i386架构下的特权级概念,包括DPL(Descriptor Privilege Level)、RPL(Requestor's Privilege Level)和CPL(Current Privilege Level)。这些概念对于理解操作系统如何保护自身免受恶意...
MAX(CPL, RPL)<=DPL[段]): 进程管理是操作系统用于管理进程的重要机制,用于控制进程的创建、执行和终止。操作系统需要正确地实现进程管理,以便正确地管理进程。 13. 页面替换算法(三 1. (1) a.尽可能减少页面...
2. **特权级管理**:通过CPL(Current Privilege Level)、DPL(Descriptor Privilege Level)、RPL(Requested Privilege Level)等机制实现权限控制。 3. **宏内核与微内核**: - **宏内核**:所有核心功能都在...
第三阶段则通过互联网实现远程控制,使用Java applet和网络服务器进行交互。 软件开发过程中,VB语言用于快速编程开发(RPD),并与RSL兼容。通过三维线框图,用户可以在PC上观察和控制机器人的运动。仿真功能包括...
保护模式还引入了权限级别的概念,包括RPL(Request Privilege Level)、CPL(Current Privilege Level)、DPL(Descriptor Privilege Level)等,这些级别确保了不同级别的程序只能访问相应级别的资源,从而提高了...