内核保护模式之分段机制

CPU的三种模式

1982年,intel推出了80286处理器,第一次提出了保护模式,在保护模式下,段寄存器中存储的不再是段基址,而是段选择子。

真正的段基址存储在描述符高速缓存中,80286处理器访问内存,不需要段寄存器左移加上偏移。

在x86体系的CPU下,支持三种模式

  1. 实模式:兼容16位CPU的模式,当前的PC系统处于实模式(16位模式)运行状态,在这种状态下软件可访问的物理内存空间不能超过1MB,且无法发挥Intel 80386以上级别的32位CPU的4GB内存管理能力。实模式将整个物理内存看成分段的区域,程序代码和数据位于不同区域,操作系统和用户程序并没有区别对待,而且每一个指针都是指向实际的物理地址。这 样,用户程序的一个指针如果指向了操作系统区域或其他用户程序区域,并修改了内容,那么其后果就很可能是灾难性的。
  2. 保护模式:操作系统所在模式,只有在保护模式下,80386的32根地址线有效,可以寻址高达4G字节的线性内存空间和物理内存空间,可访问64TB的逻辑地址空间(有214个段,每个段最大空间为232个字节),可采用分段管理存储机制分页管理存储机制。这不仅为存储共享和保护提供了硬件支持,而且为实现虚拟存储提供了硬件支持。通过提供4个特权级(R0 ~ R3)和完善的特权级检查制,既能实现资源共享又能保证代码数据的安全及任务的隔离。保护模式下有两个段表:GDT和LDT
  1. 虚拟8086模式:可以模拟多个8086执行多任务

保护模式的分段机制

保护模式部分内容:

保护模式下的分段机制

保护模式下的分页机制

CS段寄存器的值,决定特权等级R0 ~ R3

8086寄存器主要是16位的,共4个CS DS ES SS

32位处理器内,增加了两个:FS GS

32下的段寄存器又分为两部分,16位可见部分,每一个寄存器还有一个不可见部份,称之为描述符高速缓存器,用来存放段的基地址,范围和属性。

段选择子概述

什么是段选择子?

段寄存器可见部分存储的值我们称之为段选择子,共16位

13位描述符表索引 1位:T1 TI = 0 GDT TI = 1 LDT 2位:RPL
     

段寄存器中不可见部分的值,来自于一个叫做描述符表的数组,可见部分的高13位是数组的下标。

当段寄存器被赋值的时候,实际上会从描述符表中的一个描述符中读取数据,将数据加载至段寄存器不可见部分。

TI位表明的是查找全局描述表GDT(Global Descriptor Table),还是局部描述表LDT(L**ocal Descriptor Table)。Windows系统并没有使用局部描述符表LDT。

段描述符

段描述符的结构:

typedef struct Descriptor{    unsigned int base;  // 段基址    unsigned int limit; // 段限长    unsigned short attribute; // 段属性}

在保护模式下,增加了很多机制,使得段产生了不少种类:

  • 数据段(用于存储程序,供程序读写)
  • 代码段(用于执行代码)
  • 系统段(用于操作系统提供特殊功能)

每个段描述能够描述出一段内存从哪里开始,到哪里结束,还能描述这个段是什么类型(代码段、数据段、系统段),当然,也能描述这个段是否可读,是否可写,是否可执行,甚至还能描述这个段的权限是什么,在什么权限下才能使用这一段内存。

通用断描述符

  • 描述符有效位P位: 0无效 1有效
  • 段限长Limit:处理器会把段描述符。两个段限长字段组合成一个20位的值,并根据颗粒度标志G来指定段限长Limit值的实际含义
  • 粒度位G:

    G = 0;Limit的单位是字节,段的大小范围为1字节到1Mb(0~0xFFFFF) , 每个单位为1字节。

    G = 1;Limit的单位是4KB,段的大小范围是1字节到4Gb(0~0xFFFFFFFF), 每个单位为4Kb。

  • 基地址字段Base:描述了一个段的起始位置,由三个部分组成,一共是32位,段基地址可以是0~4GB范围内的任意地址(这同实模式不同,实模式下段基地址要求16字节对齐)。但是,为了让这个程序具有最佳性能,还是建议段基地址对齐16字节边界。
  • S与TYPE:应用程序有数据段和代码段,CPU还有系统段和门描述符,他们用来管理事物、异常和中断。并非所有的描述符都定义一个段,门描述符中存放着一个指向过程入口点的指针,S和Type字段表明了描述符的类型信息。
S位 S = 1代表是一个代码段或者数据段,S = 0代表是一个系统段
Type域 一共4位,S为不同代表的含义不同
  • L位:是64位代码段标志,保留此位给64位处理器使用
  • AVL:是软件可以使用的位,通常由操作系统来用,处理器并不使用它
  • DPL:存在于段描述中,描述了访问本段的内存所需要的权限

数据段描述符

  • B位:

B = 1,内存寻址是32位,堆栈使用ESP,段的内存最大大小为4GB

B = 0,内存寻址是16位,堆栈使用SP,段的最大大小位64KB

  • A访问位

表示该位最后一次被操作系统清零后,该段是否被访问过,每当处理器将该段选择符置入某个段寄存器时,就将该位置1

  • W是否可写
    • 指示段的读写属性
    • W = 0;段不允许写入,否则会引发处理器异常中断
    • W = 1;段允许写入
  • 扩展方向
    • E = 0;表示向上扩展的段(上扩段),逻辑地址中的偏移范围可以从0到Limit
    • E = 1;表示向下扩展的段(下扩段,通常是栈段),逻辑地址中的偏移范围可以从Limit到0xFFFF(B = 0)或者0xFFFF_FFFF(当B = 1)时。

代码段描述符

  • B位:

B = 1,内存寻址是32位,堆栈使用ESP,段的内存最大大小为4GB

B = 0,内存寻址是16位,堆栈使用SP,段的最大大小位64KB

  • A访问位

表示该位最后一次被操作系统清零后,该段是否被访问过,每当处理器将该段选择符置入某个段寄存器时,就将该位置1

  • W是否可写
    • 指示段的读写属性
    • W = 0;段不允许写入,否则会引发处理器异常中断
    • W = 1;段允许写入
  • 扩展方向
    • E = 0;表示向上扩展的段(上扩段),逻辑地址中的偏移范围可以从0到Limit
    • E = 1;表示向下扩展的段(下扩段,通常是栈段),逻辑地址中的偏移范围可以从Limit到0xFFFF(B = 0)或者0xFFFF_FFFF(当B = 1)时。

代码段描述符

  • D位:

D = 1,默认值是32位的地址和32位或者8位的操作数

D = 0,默认值是16位的地址和16位或者8位的操作数

  • A(已访问)

表示该位最后一次被操作系统清零后,该段是否被访问过,每当处理器将该段选择符置入某个段寄存器时,就将该位置1

  • R位(可读)
    • 堆栈必须R = 0,代码段不可读,只能执行
    • R = 1;代码段可读,可执行
    • 在保护模式下,代码段是不可写的
  • C位(一致性
    • C = 0;表示非一致性代码段,这样的代码段可以被同级代码段调用,或者通过门调用。
    • C = 1;表示一致性代码段,可以从低特权级的程序转移到该段执行(但是低特权级的程序仍然保持自身的特权级)

段类型检查

  • 加载段选择符进入段寄存器的时候
    • CS寄存器只能存放可执行段的选择符
    • 不可读可执行段的选择符不能被加载进入数据段寄存器(因为数据段都是可读的)
  • 指令访问一个段,段描述符已经被加载到段寄存器,指令只能用某些预定义的方法来访问某些段
    • 不能写可执行段(代码段不可写)
    • 不能写一个可写位没有设置的数据段
    • 不能读可读位没有设置的可执行段

段权限检查

当我们给段寄存器赋值的时候,实际上是从GDT中获取相应的段描述符加载到段寄存器的不可见部分。

在这个过程中有一个权限检查的问题,请注意,在你给段寄存器赋值的时候就已经进行段权限检查了,如果成功,就说明可以访问这个段

权限检查的三个概念:

  • CPL:当前代码的执行权限,CS段的B0和B1
  • DPL:存在于段描述符中,描述了访问本段的内存所需要的权限
  • RPL:存在于段寄存器加载时的段选择子中,描述了访问者使用什么样的权限对目标进行访问

全局描述符表

在一个系统中, 描述符的种类有多个, 分别有数据段,代码段, 系统段. 系统段又分为多种,有调用门,中断门,陷阱门,任务门. 因此, 在一个系统中, 描述符是存在多个的. 这些描述符被统一打包存储在内存中, 它们所形成的一个数组被称之为全局描述符表.

全局描述符的小标则保存于16位的段寄存器中.

一个16位的段寄存器实际由一下部分组成:

段寄存器实际的长度为96位, 16位的值, 只是寄存器的可见部分, 段寄存器还有80位是隐藏部分 , 这个隐藏部分只能被CPU所操作,无法通过任何指令来操作它.

这可见部分的16位的值也并非全部用于保存全局描述符的下标, 它被划分为以下格式:

也就是说, 只有13位是用于保存全局描述符表的下标.

T1 - 用于记录,保存的下标是GDT(全局描述符表)的还是LDT(本地描述符表)的(windows操作系统没有LDT)

RPL - 当前请求级别 , 用作权限检查. 一共有4个值: 0~3 , 数值越小,权限越大, 0代表最高权限.

由于段寄存器用于保存段选择子, 因此, 给一个段寄存器赋值,就不单单是赋值一个数字了,例如:

mov ax,2Bhmov ds,ax

这条指令可看成将0x2B赋值给ds寄存器, 实际不是.

将0x2b的二进制展开: 0000 0000 0010 1011 , 段选择子的格式为: 13 : 1 : 3.

那么在0x2b这个数中, 描述符表索引,T1位,RPL分别为:

也就说, 0x2b这个数代表的是GDT表中第5个段描述符. 当前请求级别为最低权限的2。

mov ds,ax这条指令执行之后做了什么?

CPU执行这条指令后, 会将GDT表中第5个段描述符存储在段寄存器隐藏部分, 将段选择子存储到16位可见部分. 当然, 在做这些之前, CPU还需要做权限检查。

原文地址:https://www.cnblogs.com/TJTO/p/11414726.html

时间: 2024-11-03 21:41:10

内核保护模式之分段机制的相关文章

Lab_1:练习3——分析bootloader进入保护模式的过程

文章链接:https://www.cnblogs.com/cyx-b/p/11809742.html 作者:chuyaoxin 一.实验内容 BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中的位置执行bootloader.请分析bootloader是如何完成从实模式进入保护模式的. 提示:需要阅读小节"保护模式和分段机制"和lab1/boot/bootasm.S源码,了解如何从实模式切换到保护模式,需要了解: 为何开启A20,以及如何开启A20 如何初始化GDT表 如何使能和

Linux内核系列—操作系统开发之进入32位保护模式

源码如下: ; ========================================== ; pmtest1.asm ; 编译方法:nasm pmtest1.asm -o pmtest1.bin ; ========================================== %include "pm.inc" ; 常量, 宏, 以及一些说明 org 07c00h jmp LABEL_BEGIN [SECTION .gdt] ; GDT ; 段基址, 段界限 , 属

CPU保护模式深入探秘

原文链接为:http://www.chinaunix.net/old_jh/23/483510.html 保护方式的体系结构 主要问题:          保护方式的寄存器模型          保护方式的描述符与页表项          保护方式的存储器管理与地址转换          多任务机制与保护实现          虚拟 8086 模式 一.保护方式的寄存器模型   新增四个寄存器 (指针 -----  指向内存中的特殊的数据表):  全局描述符表寄存器 GDTR  局部描述符表寄存

【OS】实模式和保护模式区别及寻址方式

实模式和保护模式区别及寻址方式 转载请注明出处:http://blog.csdn.NET/rosetta 64KB-4GB-64TB? 我记得大学的汇编课程.组成原理课里老师讲过实模式和保护模式的区别,在很多书本上也有谈及,无奈本人理解和感悟能力实在太差,在很长一段时间里都没真正的明白它们的内含,更别说为什么实模式下最大寻址空间为1MB?段的最大长度不超过64KB?而保护模式下为啥最大寻址能力就变成了64TB?每个段最大也达4GB? 更甚者分段和分页这两个高深的概念像我这种菜鸟怎么也理解不了啊!

实模式与保护模式下的分段分页机制

1. 实模式 在实模式下,CPU不会为任务提供任务的保护机制,代码任意运行.8086处理器是学习实模式的常用例子.它内部大致有以下寄存器: 8个16位的通用寄存器: AX (可以拆分成两个AH/AL的8位寄存器) BX (BH,BL) CX (CH,CL) DX (DH,DL) SI (source index, 源索引寄存器) DI (destination index, 目的索引寄存器) BP (base pointer, 基数指针寄存器) SP (stack pointer, 堆栈指针寄存

Linux内核系列—12.b.操作系统开发之从Loader跳入保护模式

现在,内核已经被我们加载进内存了,该是跳入保护模式的时候了. 首先是GDT以及对应的选择子,我们只定义三个描述符,分别是一个0~4GB的可执行段.一个0~4GB的可读写段和一个指向显存开始地址的段: ; GDT ; 段基址 段界限, 属性 LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR|DA_32|DA_LIMIT_4K ;0-4G LABEL_DESC_FLAT_RW: D

Linux内核系列—操作系统开发之保护模式的优势

在上一篇中我们虽然成功进入了保护模式,但是并没有体验到保护模式带给我们的便利.其实在保护模式下寻址空间可以达到4GB,实模式下1MB的寻址能力差得太远了.那么下面,我们就把程序稍作修改,体验一下它对超过1MB内存的访问能力. 我们来试验一下读写大地址内存.在前面程序的基础上,新建一个段,这个段以5MB为基址,远远超出实模式下1MB的界限.我们先读出开始处8字节的内容,然后写入一个字符串,再从中读出8字节,如下所示: call TestRead call TestWrite call TestRe

第十四天、保护模式开启

loader的任务有两个:开启保护模式,将核心 kernel 载入内存.保护模式照抄上次的代码就行, kernel 嘛,先读个文本文件到内存,然后显示出来--检查下效果就行. 常量里加上 kernel.bin 载入内存的段基址 ; Constant.inc ; 常量 ; 四彩 ; 2015-11-17 %ifndef _CONSTANT_INC %define _CONSTANT_INC ; ====================================================

Linux内存寻址之分段机制

http://blog.xiaohansong.com/2015/10/03/Linux内存寻址之分段机制/ .段的起始地址.段的长度等等,而在保护模式下则复杂一些.IA32将它们结合在一起用一个8字节的数表示,称为描述符 .IA32的一个通用的段描述符的结构从图可以看出,一个段描述符指出了段的32位基地址和20位段界限(即段长).这里我们只关注基地址和段界限,其他的属性略过. 段描述符表 各种各样的用户描述符和系统描述符,都放在对应的全局描述符表.局部描述符表和中断描述符表中.描述符表(即段表