尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
操作系统之保护模式基础
1.为什么要进入保护模式1.1在没有保护模式的情况下在没有进入保护模式的情况下也就是实模式我们来看看一些的操作这会带来什么问题在讲解这些操作之前我们最好理解这里的操作指的是什么也就是计算机操作。我觉得最好的办法是用代码描述这种操作而不是纯文字因为用中文描述会感觉很抽象而且计算机只能听懂代码。我们来看看在没有保护模式的情况下实模式的一些代码操作:mov ax, 0xb800 ; 文本模式显存段 mov ds, ax mov byte [0xb0], H ; 向显存写入字符我们知道0xb8000处是显存段上述代码向显存段写入了字符。在实模式下CPU 不会阻止这段代码执行哪怕它是一个普通用户程序。这就带来了问题操作系统是管理硬件的唯一管理者如果任何用户程序都能随意修改显存、改写硬件状态那操作系统的管理就形同虚设了。用户程序想要操作硬件应该向操作系统申请。mov ax, 0x0000 ; 中断向量表所在段 mov ds, ax mov byte [0x30], 0x00 ; 破坏中断向量表内容实模式下0x00000~0x003FF处存放的是中断向量表。上述代码直接改写了中断向量表的内容。如果此时发生对应的中断CPU 会按照被破坏的地址去寻找中断服务程序这极易导致系统崩溃死机。1.2保护模式核心思想分析上面的操作本质问题就是代码可以随意访问内存的各个段那么保护模式怎么解决这个问题呢想象一下有一天你去荒野求生了发现河边有条草鱼你肯定会兴奋的去抓它但是如果你看见一只熊猫你还会去抓它吗尽管它很可爱但本质原因是你知道它是保护动物这个信息所以阻止了你这个行为。所以可以这么说你做的每一步动作都是基于信息来决定你是否该执行的。就好像有人给你做了道牛欢喜的菜在你不知道者是什么的时候你吃的很香但是如果你知道它是什么的时候你吃这个动作可能就不会执行了~代码是一种CPU执行的动作它可以有各种动作有些动作会破坏内存中的某个段。那么我们是不是可以给内存的每个段增加一些“属性信息”比如谁可以访问它能写还是只能读在 CPU 准备执行代码操作的时候由 CPU 硬件强制根据这些信息来判断是否允许执行此次操作。这就是保护模式的核心思想。下篇文章我们来看看这些“信息”到底是什么以及 CPU 是怎么根据它们来拦截操作的。1.3描述符1.3.1描述符分类这些用于描述内存段属性信息的数据结构在 x86 中就被称为描述符。描述符可以有多种但无论何种描述符都只占8个字节。描述符可以分两大类:存储器的段描述符:用于描述一般的数据段代码段。系统描述符:门描述符描述与程序执行有关的逻辑结构LDT 描述符指向局部描述符表 LDTTSS 描述符指向任务状态段 TSS那么既然描述符都是8字节那么该如何区分它们呢8字节大小比特编号从 0 到 63 核心判断字段S 位第 44 位1 比特描述符大类判断标志S 位 0 → 该描述符是系统描述符S 位 1 → 该描述符是存储器的段描述符Type 字段第 40~43 位4 比特描述符具体类型判断标志若为系统描述符S0Type 字段用于指定系统段的类型或门的具体类型若为存储器段描述符S1Type 字段用于指定是代码段还是数据段以及相关属性1.3.2存储器的段描述符结构存储器的段描述符是最基本的描述符所以我们开始先讲最基本的东西那么我们来看看存储器的段描述符结构吧看看这个描述符具体描述了代码段数据段的哪些信息。我们知道了存储器段描述符S1Type 字段用于指定是代码段还是数据段Type字段有四位最高位是X位据此分为数据段和代码段X0,则该描述符描述的是数据段→剩余 3 位为 E、W、A 位E 位扩展方向位expandE1向下扩展从高地址向低地址扩展通常是栈段E0向上扩展从低地址向高地址读写属于普通数据段假设一个段的描述符中基地址为0x00000000,段界限为0x7c00。当E0,可以访问的范围是0x00000000~0x00007C00;当E1,可以访问的范围是0x00007C01~0xFFFFFFFFFW 位可写位writableW0段只读写入会引发处理器异常中断W1段可正常写入A 位已访问位accessedA0:描述符创建时A 位清零A1:段被访问时处理器自动将 A 位置 1X1,则该描述符描述的是代码段→剩余 3 位为 C、R、A 位C 位依从位C0非依从代码段仅特权级相同的程序可直接转移执行C1依从代码段低特权级程序可直接转移执行无特殊要求通常清零此位仅作了解当学到特权级保护后就知道了R 位可读位R0代码段不可读R1代码段可读可像只读存储器一样使用A 位已访问位accessedA0:描述符创建时A 位清零A1:段被访问时处理器自动将 A 位置 1数据段和代码段描述符共同字段→(简单了解即可只有用到了才知道有什么用)低双字0~15位高双字16~19位:段界限低双字16~31位高双字0~7和24~32位:段基地址高双字13~14位DPL对段的访问实施管控限制可访问该段的程序取值与特权级对应00→0 级、01→1 级、10→2 级、11→3 级(0为最高特权级3最低特权级)高双字的位15位P位指示描述符对应的段是否可立即访问高双字的位 20:AVL位规则处理器不使用此位完全保留给操作系统自定义使用高双字的位 21:L位指示是否为 64 位代码段32 位系统要求此位固定置 0高双字的位 22:D/B位作用指示段的默认操作位数D/B0段按 16 位进行操作D/B1段按 32 位进行操作影响决定向下扩展段的界线最大值0xFFFF/0xFFFFFFFF以及使用 SP 还是 ESP 寄存器高双字的位 23:G位粒度位核心作用解释段界线的计数单位G0段界线以字节为单位G1段界线以4KB0x1000 字节为单位实际界线计算公式G1 时实际段界线 描述符中的段界线 × 0x1000 0xFFF1.4描述符表1.4.1描述符表分类这些描述符表得有个地方集中存放吧不然CPU怎么找到呢。x86 保护模式下描述符集中存放在内存中形成一个表格叫做描述符表。描述符表主要包括 GDT、LDT 和 IDT。其中 GDT 和 LDT 存放段描述符IDT 存放门描述符。GDT 全局唯一LDT 可以有多个。1.4.2 全局描述符表GDT那么这么多张表CPU怎么知道要用哪张表拿GDT举例处理器内部有一个 48 位的全局描述符表寄存器 GDTR用于跟踪 GDT。如图所示。那么LDT和IDT是不是也有个寄存器跟踪LDTR和IDTR?还真是。但这不是本文重点就不讲解了。1.4.3全局描述符表寄存器GDTR那么来看看GDTR的结构吧看看它是怎么跟踪GDT的。GDTR寄存器总共有48位如图所示。0~15位:GDT表的界限值也就是这张表有多大界限为 16 位 → GDT 最大64 KB每个描述符 8 字节 → 最多可容纳8192个描述符。16~47位:GDT表的起始线性地址也就是这张表起始的位置再哪线性地址即内存的连续地址通常等于物理地址。1.5保护模式相关工作1.5.1如何进入保护模式那么讲了这么多该如何进入保护模式呢其实很简单只需要设置CR0寄存器即可。CR0 是处理器内部的 32 位控制寄存器包含一系列控制处理器操作模式和运行状态的标志位。位 0PE 位Protection Enable保护模式允许位。将此位置 1处理器即进入保护模式并按保护模式规则运行。1.5.2进入保护模式之前的相关工作设置 PE 位进入保护模式之前必须保证已通过端口0x92开启 A20地址线。执行CLI指令禁止中断保护模式下的中断机制与实模式完全不同原有中断向量表不再适用新的中断处理机制尚未建立BIOS 中断也不能再用若此时发生中断必然出错。in al,0x92 ;南桥芯片内的端口 or al,0000_0010B out 0x92,al ;打开A20 cli ;保护模式下中断机制尚未建立应 ;禁止中断 mov eax,cr0 or eax,1 mov cr0,eax ;设置PE位1.6保护模式内存访问方式1.6.1通过描述符表的索引值找到描述符进入保护模式后那么CPU怎么访问某个内存段呢既然每个内存段的信息都保存在描述符中而这些描述符又一个个的保存在描述符表中所以要访问某个内存段应该通过这张表的索引值来找到对应的描述符。描述防护里有内存段的地址等属性信息有了描述符找到想找的内存段不是轻而易举了吗就比如我拿到了你的身份证找到你家的地址是不是很简单还是和前文一样的道理这里说的内存访问只是中文描述这很抽象我们将其转化为代码:mov cx, 00000000000_01_000B mov ds, cx进入保护模式后段寄存器传入的不再是逻辑地址而是描述符选择子选择子由三部分组成 结构如下:其中位3到15位存的是描述符表的索引CPU通过GDTR寄存器找到描述符表的基地址然后再用描述符表索引值*8GDT基地址(因为每个描述符是8字节)即可找到对应的描述符。1.6.2将描述符存入高速缓存寄存器找到了描述符这个时候是不是要存起来了那么存放哪里呢32 位处理器为每个段寄存器增加了一个不可见的部分——描述符高速缓存器用于存放段的线性基地址段的界限值段的访问属性所谓不可见说的是我们无法访问。1.6.3内部流程当一条指令将选择子加载到段选择器时处理器自动执行以下内部过程mov cx, 00000000000_01_000B mov ds, cx将选择子中的索引号 × 8得到该描述符在 GDT 中的字节偏移量根据TI 位确定使用哪个描述符表此处 TI0使用 GDT从GDTR中取出 GDT 的线性基地址将 GDT 基地址 索引偏移量 目标描述符的线性地址从内存中读取 8 字节描述符将其解析的内容基地址、界限、属性加载到描述符高速缓存器中至此ds的描述符高速缓存器中存放了该内存段的描述符下次访问该段时直接通过描述符高速缓存器中取出对应的描述符例如以下代码:mov bx,0x000A mov ax,0x000B mov [ds:bx],ax注意只要不修改ds的值下次内存访问时CPU 就直接用之前缓存的描述符不需要重新查表了这是硬件加速的机制。
RELATED

相关推荐

聚簇索引、非聚簇索引与回表

聚簇索引、非聚簇索引与回表

一、聚簇索引(Clustered Index)核心特点:索引和数据放在一起,叶子节点直接存整行数据。InnoDB 里,主键索引就是聚簇索引。B 树的叶子节点存放的是完整的一行数据找到索引,就等于找到了整行,不需…

📅 2026/10/15 4:07:51
gdb与cgdb

gdb与cgdb

1.gdb与cgdb介绍与安装我们在使用vim编写完代码之后,想要和VS那样调试代码看看有没有什么问题,这个时候就需要gdb与cgdb来协助了。gdb(GNU Debugger)是 GNU 项目提供的一种调试工具,用于调试 C、C 和其他编程语言编写的…

📅 2026/10/15 4:02:51
香味油墨与普通油墨有什么区别?一文讲清

香味油墨与普通油墨有什么区别?一文讲清

摘要:香味油墨作为功能性特种油墨,与普通油墨在配方组成、印刷工艺、成品性能和应用场景上存在明显差异。本文从多个维度系统对比两者的区别,帮助印刷厂和品牌方在选型时做出合理判断。一、引言:为什么要区分香味油墨与普通油墨 在…

📅 2026/10/15 4:02:51
MORE NEWS

更多资讯

📰

一和零:从01背包到二维费用背包的进阶之路

今天想聊聊题号474这道经典题:一和零。它在动态规划题单里的地位很特殊,名字看着像字符串处理,本质上却是一道非常标准的二维费用背包问题。很多朋友刷到这道题时,01背包刚上手,一看数组里全是字符串,又要数…

📰

蓝牙SDP协议深度解析:服务发现原理与故障排查实战

1. 这不是“蓝牙配对弹窗”背后的玄学,而是服务发现协议(SDP)在真实设备间无声运转的日常你有没有过这样的经历:把手机靠近蓝牙耳机,几秒内自动连接成功;车载系统一启动就识别出你的手表心率数据&#xff1…

📰

Ubuntu 18.04安装NVIDIA驱动450.80.02与CUDA 11.0.3实战指南

1. 项目概述:为什么在Ubuntu 18.04上装NVIDIA驱动CUDA 11.0,至今仍有大量开发者在做这件事“Ubuntu 18.04下NVIDIA驱动CUDA 11.0安装”这个标题看起来像一份过时的操作手册——毕竟Ubuntu 18.04早在2023年4月就结束了标准支持,CUDA 11.0也已停…

📰

小红书宝藏新品冷启动:真实生活验证的种草方法论

简介:本资源为小红书官方发布的2024年「宝藏新品」招商通案PDF,面向品牌方、市场营销从业者及电商运营人员,系统解答如何借力小红书平台实现新品高效种草与冷启动。方案深度解析平台级新品营销IP的底层逻辑,涵盖用户洞察&#xff…

📰

贫穷陷阱的底层逻辑:从随机对照实验看理性决策的边界

《贫穷的本质》这本书,我前前后后翻了三遍。第一遍是当经济学通俗读物看,第二遍是为了整理读书笔记,第三遍是因为做项目调研时发现自己踩了书里明确警告过的坑——把贫困问题简单归结为"穷人不努力"或者"资源不够"这两个…

📰

PyTorch分布式训练核心:DDP原理、启动与排障实战

1. 为什么不是DataParallel,而是DistributedDataParallel——从单卡幻觉到多卡真相刚接触PyTorch分布式训练的人,十有八九会先撞上DataParallel(DP):改两行代码、加个.cuda()、套个nn.DataParallel(model),…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬