`

(第三章 8 )特权级——CPL、DPL、RPL

 
阅读更多

      很久以后,等我大量翻阅关于“保护模式的特权级检查(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

...
Please choose one: [6] 2
...
To cancel, type 'none'. [.bochsrc] 
...
Please choose one: [6]
...
<bochs:1> c
 


 

发现根本不能运行,这就对了

 
注意到这里涉及到特权级别的几个地方:

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四者的转化和对应关系。

  • 大小: 20 KB
分享到:
评论

相关推荐

    操作系统篇-调用门与特权级(CPL、DPL和RPL).docx

    ### 操作系统篇-调用门与特权级(CPL、DPL和RPL) #### 一、前言 在深入探讨操作系统的核心机制时,理解保护模式下的调用门与特权级至关重要。特权级和调用门是保护模式下确保系统稳定性和安全性的关键组成部分。...

    归纳 DPL RPL CPL

    内核 系统 DPL RPL CPL , 调用门等

    intel DPL RPL详解

    访问数据段或堆栈段时,默认使用CPU和RPL中的最小特权级去访问数据段,因此max{CPL, RPL} ≤ DPL,否则访问会被拒绝。 **2. 代码段访问** - **转跳规则**:所有程序转跳中,CPU不会将段选择子的RPL赋给转跳后程序...

    [自制操作系统] 第10回 认识保护模式之深入浅出特权级.doc

    然而,当用户程序试图访问数据段时,DS寄存器的RPL会被设置为用户进程的CPL(通常是3),此时若数据段的DPL为0,根据特权级检查规则(CPL≤DPL且RPL≤DPL),访问将被拒绝,因为RPL为3无法满足条件。 门结构在特权...

    一个操作系统的实现–关于CPL、RPL、DPL

    4个特权级(或特权层) ,0级到3级。数值越大特权越小。一般用把系统内核放在0级,系统的其他服务程序位于1、2级,3级则是应用软件。一般情况下代码都在自己的级别下做自己 的工作,同一级别之间可以相互访问,而一般...

    第6章 从内核态到用户态1

    特权级的检查涉及CPL(Current Privilege Level)、RPL(Request Privilege Level)和DPL(Descriptor Privilege Level)。CPL存储在CS寄存器中,表示当前执行代码的权限级别;RPL是段选择子的一部分,表明请求访问...

    操作系统高级教程.docx

    特权级(CPL、RPL、DPL、IOPL)用于限制不同级别程序的权限,防止误操作。分页机制也有保护作用,通过页表的权限位(如R/W、U/S)来控制对内存页面的访问,确保数据的安全。 6. **两次设置GDT的原因**: 在`setup`...

    国科大操作系统高级教程-思考题(更新之2023.10.24)

    体现:1)在GDT、LDT及IDT中,均有自己界限,特权级等属性,这是对描述符所描述的对象的保护2)在不同特权级间访问时,系统会对CPL、RPL、DPL、IOPL等进行检验,对不同层级的程序进行保护,同还限制某些特殊指令的...

    2021操作系统高级教程思考题.docx

    - 在不同特权级间的访问时,系统会对 CPL、RPL、DPL、IOPL 等进行检查,保护不同层级的程序,并限制某些特殊指令的使用。 - 分页机制通过 PDE 和 PTE 中的 R/W 和 U/S 等属性提供了页级别的保护,同时也通过将线性...

    Window s 中段页式内存管理硬件实现剖析

    最后根据特权级规则,只有当 Max(CPL, RPL) ≤ DPL 时,才允许访问该段,否则产生异常 13。 Window s 操作系统在 80x86CPU 中的内存管理单元(MMU)的硬件工作原理,实现了内存单元的段页式寻址、保护检查和虚拟...

    操作系统-20180412-期中总结 张慕晖的博客1

    中断描述符表(IDT)用于管理中断和异常,确保不同的特权级访问的合法性,CPL(当前特权级)、RPL(请求特权级)和DPL(描述符特权级)是控制访问权限的关键元素。 总的来说,操作系统设计涉及多方面的复杂交互,...

    2019年复习重点范围1

    数据访问的保护规则规定,DPL(描述符特权级)必须大于等于MAX(CPL, RPL),其中CPL是当前程序的特权级,RPL是请求特权级。段间调用或跳转时,需要考虑限长和特权级的比较,以确保安全的代码执行。 【指令系统】 ...

    龚伦强内核过游戏驱动保护教程

    - **RPL**: 请求特权级,指在访问描述符时请求的特权级。 - **DPL**: 描述符特权级,描述符本身的特权级。 - **CPL**: 当前特权级,执行代码所在的特权级。 #### 5. 调用门机制 - **定义**:调用门是一种特殊的系统...

    PA3实验报告1

    在实验过程中,我们了解到i386架构下的特权级概念,包括DPL(Descriptor Privilege Level)、RPL(Requestor's Privilege Level)和CPL(Current Privilege Level)。这些概念对于理解操作系统如何保护自身免受恶意...

    操作系统-20170407-期中解析1

    MAX(CPL, RPL)&lt;=DPL[段]): 进程管理是操作系统用于管理进程的重要机制,用于控制进程的创建、执行和终止。操作系统需要正确地实现进程管理,以便正确地管理进程。 13. 页面替换算法(三 1. (1) a.尽可能减少页面...

    软件安全原理.pdf

    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)等,这些级别确保了不同级别的程序只能访问相应级别的资源,从而提高了...

Global site tag (gtag.js) - Google Analytics