首页 > 其他分享 >第四章 保护模式入门

第四章 保护模式入门

时间:2025-01-06 17:35:47浏览次数:1  
标签:保护模式 GDT 入门 32 equ 描述符 第四章 DESC

第四章 保护模式入门

本文是对《操作系统真象还原》第四章学习的笔记,欢迎大家一起交流。

知识部分

为什么要有保护模式?

实模式下安全问题:

  • 实模式下操作系统和用户程序属于同一特权级,平起平坐,没有区别对待;
  • 用户程序所引用的地址都是指向真实的物理地址,也就是说逻辑地址等于物理地址,实实在在的指哪打哪;
  • 用户程序可以自由修改段基址,可以不亦乐乎地访问所有内存,没人拦得住;

实模式下使用上的缺陷:

  • 访问超过 64KB 的内存区域是要切换段基址,转来转去容易晕呼;
  • 一次只能运行一个程序,无法充分利用计算机资源;
  • 共 20 条地址线,最大可用内存为 1MB,这即使在 20 年前也不够用。

而保护模式提供了一种保护机制让程序不能随意访问所有内存空间,同时 CPU 的寻址范围也达到了 4GB。

保护模式的特点

保护模式之寄存器扩展

一张图即可,e 代表 extend

注意段寄存器并没有扩展,进入保护模式后,段寄存器中保存的再也不是段基址了,里面保存的内容叫选择子 selector,该选择子其实就是个数,用这个数来索引全局描述符表中的段描述符,把全局描述符表当成数组,选择子就像数组下标一样在,后面讲 GDT 的时候会详细说。

image

保护模式之寻址扩展

image

保护模式之运行模式反转

操作数反转前缀 0x66,寻址方式反转前缀 0x67。

bits 的指令格式是 [bits 16]或 [bits 32]。
[bits 16]是告诉编译器,下面的代码帮我编译成 1 6 位的机器码 。
[bits 32]是告诉编译器,下面的代码帮我编译成 32 位的机器码。

注:
进入保护模式需要三个步骤。
(1) 打开 A20 。(2) 加载 gdt 。(3) 将 cr0 的 pe 位置 1 。

后面代码部分有详细步骤。

全局描述符表(GDT)

实模式与保护模式寻址的不同

实模式下用 段基址:偏移 ​来寻址,即 段基址*16+偏移​,段基址是存在段寄存器中的。

在保护模式下,要访问 4gb 的内存空间,再采取实模式下的方法是远远不够的,所以段寄存器中存储的数据变成了选择子,其格式如下图所示,其中索引值即 gdt 中索引值,TI 用于指示是去 GDT 还是 LDT 中寻找段基址,RPL 是特权级

image

段描述符

GDT 是一个表格,其中每一个表项就对应一个全局描述符,操作系统在寻址市首先根据 gdtr 寄存器得到 GDT 内存起始地址,然后加上选择子的偏移(8 字节为单位),就找到了对应的段描述符,然后在段描述符里可以获取对应段的起始地址和界限,需要注意的是,GDT 表第 0 个段描述符不可用。因为选择子忘记设置的话,就会是 0(就像我们的 MBR 代码一上来就将段寄存全部初始化为 0),就会访问这个段描述符,而如果这个段描述符有内容的话,就会将段基址定位到其他我们并不想要的地方去,所以干脆直接让 GDT 表第 0 个段描述符不可用,未设置的选择子访问这个段描述符 CPU 就会产生异常并阻止。其中 gdtr 寄存器格式如下图所示:

image

段描述符格式如下图所示,可以看到段基址和段界限被区分成了不同部分,十分奇怪,这其实是为了兼容不同的 cpu 所导致的。

image

段描述符的格式有点复杂,下面对重点字段进行说明,详见书 P151:

G 字段:1 代表单位是 4k,0 代表 1 字节,可以看到段界限共 20 位,为 0 时正好是 1MB,为 1 时正好是 4GB

D/B 字段:1 代表有效地址和数据是 32 位,0 代表 16 位

L 字段:1 代表 64 位代码,0 代表 32 位

AVL 字段:看操作系统需求用,暂时不关注

P 字段:存在位

DPL 字段:0-3,4 个特权级

S 字段:是否是系统段(看是否是硬件需要的)

TYPE 字段:需要和 s 字段结合起来看,如下图所示:

image

再说一下段基址和段界限,我们现在的 cpu 都是处于平坦模型下,即是从 0x00000000-0xffffffff ​所以段基址是 0x0,段界限是 0xfffff​,在对应位填上即可

但是也有的段比较特殊,比如显存段,我们前面说过,显存段的范围是 0xB8000-0xBFFFF​,所以段基址是 0xB8000​,段界限是 (0xBFFFF-0xB8000+1)/4k-1=7

代码部分

首先 mbr 文件和 loader 编译命令要变一下,因为我们 loader 变大了,所以一个扇区不太够,我们直接改成 4 个,一劳永逸。

image

image

下面是 boot.inc 代码,我们新增了很多 GDT 的描述

 ;------------- loader 和 kernel ---------- 
 LOADER_BASE_ADDR equ 0x900 
 LOADER_START_SECTOR equ 0x2


 ;--------------   gdt描述符属性  -------------
DESC_G_4K   equ	  1_00000000000000000000000b    ;  4k粒度
DESC_D_32   equ	   1_0000000000000000000000b    ;  有效地址和数据是32位   
DESC_L	    equ	    0_000000000000000000000b	;  64位代码标记,此处标记为0便可。
DESC_AVL    equ	     0_00000000000000000000b	;  cpu不用此位,暂置为0  
DESC_LIMIT_CODE2  equ 1111_0000000000000000b    ;  代码段段界限高四位 全1
DESC_LIMIT_DATA2  equ DESC_LIMIT_CODE2          ;  数据段段界限 同 代码段
DESC_LIMIT_VIDEO2  equ 0000_000000000000000b    ;  显存段段界限大小为BFFFF-B8000 = 7FFF,在20位段界限下高4位全0
DESC_P	    equ		  1_000000000000000b        ;  存在位
DESC_DPL_0  equ		   00_0000000000000b        ;  r0
DESC_DPL_1  equ		   01_0000000000000b        ;  r1
DESC_DPL_2  equ		   10_0000000000000b        ;  r2
DESC_DPL_3  equ		   11_0000000000000b        ;  r3
DESC_S_CODE equ		     1_000000000000b        ;  表示代码段非系统段
DESC_S_DATA equ	  DESC_S_CODE                   ;  数据段同代码段
DESC_S_sys  equ		     0_000000000000b        ;  系统段
DESC_TYPE_CODE  equ	      1000_00000000b	;x=1,c=0,r=0,a=0 代码段是可执行的,非依从的,不可读的,已访问位a清0.  
DESC_TYPE_DATA  equ	      0010_00000000b	;x=0,e=0,w=1,a=0 数据段是不可执行的,向上扩展的,可写的,已访问位a清0.

;  拼凑出三个段的高32位
DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00
DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00
DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b   ;最后加的是段基址BFFFF的23-16位

;--------------   选择子属性  ---------------
                                                    ;RPL代表特权级
RPL0  equ   00b                                     ;定义选择字的RPL为0
RPL1  equ   01b                                     ;定义选择子的RPL为1
RPL2  equ   10b                                     ;定义选择字的RPL为2
RPL3  equ   11b                                     ;定义选择子的RPL为3
TI_GDT	 equ   000b                                 ;定义段选择子请求的段描述符是在GDT中
TI_LDT	 equ   100b                                 ;定义段选择子请求的段描述符是在LDT中

注释很清楚了,这里不再多说。

下面是 loader.s 的内容

%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR
LOADER_STACK_TOP equ LOADER_BASE_ADDR
jmp  near loader_start 				

;构建gdt及其内部的描述符
    GDT_BASE:   dd    0x00000000 
	        dd    0x00000000
    CODE_DESC:  dd  0x0000ffff
            dd    DESC_CODE_HIGH4
    DATA_STACK_DESC:  dd  0x0000ffff
            dd    DESC_DATA_HIGH4
    VIDEO_DESC:  dd  0x80000007     ;段基址:0xB8000到0xBFFFF为文字模式显示内存,此处取后四位
                                    ;limit:0x0007 (bFFFF-b8000+1)/4k = 0x8 由于从0开始,所以再减一
            dd    DESC_VIDEO_HIGH4

    GDT_SIZE   equ   $ - GDT_BASE    ;得到gdt大小
    GDT_LIMIT   equ   GDT_SIZE -	1   ;大小减1即为gdt界限
    times 50 dq 0           ;此处预留50个描述符的slot
    SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0         ; 相当于(CODE_DESC - GDT_BASE)/8 + TI_GDT + RPL0
    SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0	 ; 同上
    SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0	 ; 同上 


   ;以下是定义gdt的指针,前2字节是gdt界限,后4字节是gdt起始地址
   gdt_ptr  dw  GDT_LIMIT 
	    dd  GDT_BASE
   loadermsg db '2 loader in real.'


loader_start:

;------------------------------------------------------------
;INT 0x10    功能号:0x13    功能描述:打印字符串
;------------------------------------------------------------
;输入:
;AH 子功能号=13H
;BH = 页码
;BL = 属性(若AL=00H或01H)
;CX=字符串长度
;(DH、DL)=坐标(行、列)
;ES:BP=字符串地址 
;AL=显示输出方式
;   0——字符串中只含显示字符,其显示属性在BL中。显示后,光标位置不变
;   1——字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变
;   2——字符串中含显示字符和显示属性。显示后,光标位置不变
;   3——字符串中含显示字符和显示属性。显示后,光标位置改变
;无返回值
   
   mov	 sp, LOADER_BASE_ADDR
   mov	 bp, loadermsg           ; ES:BP = 字符串地址
   mov	 cx, 17			 ; CX = 字符串长度
   mov	 ax, 0x1301		 ; AH = 13,  AL = 01h
   mov	 bx, 0x001f		 ; 页号为0(BH = 0) 蓝底粉红字(BL = 1fh)
   mov	 dx, 0x1800		 ;
   int	 0x10                    ; 10h 号中断

;----------------------------------------   准备进入保护模式   ------------------------------------------
									;1 打开A20
									;2 加载gdt
									;3 将cr0的pe位置1
                  
;1 打开A20
    in al, 0x92				
    or al, 0000_0010B
    out 0x92, al

;2 加载gdt
    lgdt [gdt_ptr]

;3 将cr0的pe位置1
    mov eax, cr0
    or eax, 0x00000001
    mov cr0, eax

   jmp  dword SELECTOR_CODE:p_mode_start	     ; 刷新流水线,避免分支预测的影响,这种cpu优化策略,最怕jmp跳转,
					     ; 这将导致之前做的预测失效,从而起到了刷新的作用。

[bits 32]
p_mode_start:
   mov ax, SELECTOR_DATA
   mov ds, ax
   mov es, ax
   mov ss, ax
   mov esp,LOADER_STACK_TOP
   mov ax, SELECTOR_VIDEO
   mov gs, ax

   mov byte [gs:160], 'P'               ; 显示在第二行
                                        ; 默认的文本显示模式是80*25,即每行是 80 个字符(0~79),每个字符占 2 字节,故传入偏移地址是 80*2=160。

   jmp $

上面代码的主要作用还是打印字符,一个是利用 BIOS 字段一个是直接操纵显存打印不同字符,注释很详细了,下面对关键点进行说明

6-15 行:构建 GDT 表,包含代码段描述符,数据/栈段描述符,显存段描述符

17-18 行:得到 GDT 表起始地址和大小,后面填到 gdtr 寄存器

19 行:填充了 50 个空白的段描述符,以便后面使用

20-22 行:得到三个段的选择子

50-56 行:利用 BIOS 字段打印字符

63-74 行:进入保护模式

76 行:无条件跳转,用于刷新流水线,因为在执行下面 32 位代码之前,已经先把代码送上了流水线,进行取指、译码等操作,在这两步 32 位和 16 位又有很大的不同,段寄存器的使用不同,16 位编译 32 位指令会加上 0x66/0x67 等反转符,所以我们要清空流水线,以便顺利进入 32 位

80-90 行:进入到 32 位模式,打印字符 P

最终效果如下:

image

标签:保护模式,GDT,入门,32,equ,描述符,第四章,DESC
From: https://www.cnblogs.com/fdxsec/p/18655799

相关文章

  • C++从入门到精通(第6版)PDF、EPUB免费下载
    电子版仅供预览,下载后24小时内务必删除,支持正版,喜欢的请购买正版书籍点击原文去下载内容简介《C++从入门到精通(第6版)》从初学者角度出发,以通俗易懂的语言和丰富多彩的实例,详细讲解了C++程序开发需要掌握的知识。本书分为4篇共19章:第1篇是基础知识,包括绪论,数据类型,运算符与表......
  • 第四章、连上 Internet
    4.1Linux连上Internet前的注意事项由前面几章的数据我们知道,想要连上Internet你得要设定一组合法的IP参数才可以,主要是IP,Netmask,Gateway,DNSIP以及主机名等。那我们也知道,其实整个主机最重要的设定,就是『先要驱动网络卡』,否则主机连网络卡都捉不到时,怎么设......
  • 2025最新版漏洞挖掘教程,一文讲清挖漏洞需要掌握哪些技术,网络安全零基础入门到精通收藏
    经常有小伙伴问我,为什么自己总是挖不到漏洞呢?渗透到底是什么样的流程呢?所以全网最详细的渗透测试流程来了!!!全篇文章内容较长,请耐心观看!文章目录渗透测试一确定目标二信息收集三漏洞探测四漏洞利用五内网转发六内网横向渗透七痕迹清除八撰写渗透测试保......
  • 黑客入门教程(非常详细)从零基础入门到精通,看完这一篇就够了
    一、什么是网络安全网络安全可以基于攻击和防御视角来分类,我们经常听到的“红队”、“渗透测试”等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。无论网络、Web、移动、桌面、云等哪个领域,都有攻与防两面性,例如Web安全技术,既有Web渗透,......
  • 网络安全就业前景怎么样?有哪些岗位?好找工作吗?零基础入门到精通,收藏这一篇就够了
    众所周知,网络安全与我们息息相关,无论是企业还是个人都应该重视网络安全。而且网络安全是一个新兴行业,人才需求量远大于供给,因此在薪资福利上具有很大的优势,但对于初学者而言,很多人依然担心前景问题,那么网络安全就业前景如何?本文为大家介绍一下。从目前市场情况来讲,网络安全......
  • 网络安全入门教程(非常详细)从零基础入门到精通_网路安全 教程
     前言1.入行网络安全这是一条坚持的道路,三分钟的热情可以放弃往下看了。2.多练多想,不要离开了教程什么都不会了,最好看完教程自己独立完成技术方面的开发。3.有时多百度,我们往往都遇不到好心的大神,谁会无聊天天给你做解答。4.遇到实在搞不......
  • 网络安全入门教程(非常详细)从零基础入门到精通_网路安全 教程
     前言1.入行网络安全这是一条坚持的道路,三分钟的热情可以放弃往下看了。2.多练多想,不要离开了教程什么都不会了,最好看完教程自己独立完成技术方面的开发。3.有时多百度,我们往往都遇不到好心的大神,谁会无聊天天给你做解答。4.遇到实在搞不......
  • Scss 入门
    Scss是对CSS的扩展,提供了比CSS更简洁的语法和更强大的功能。不过,在部署时,我们要先把Scss编译成CSS,才能让浏览器识别。编译Scss的方法有很多,这里我们使用VSCode的插件LiveSassCompiler进行自动编译。基本准备配置保存目录。在VSCode配置文件中添加如下配置......
  • 【爆肝4万字】PyTorch从入门到精通:张量操作、自动微分、梯度下降全解析
    文章目录前言一、张量的创建1.1基本创建方式1.1.1常用方法1.1.2示例代码1.1.3输出结果1.2创建线性和随机张量1.2.1常用方法1.2.2示例代码1.2.3输出结果1.3创建0和1张量1.3.1常用方法1.3.2示例代码1.3.3输出结果1.4张量元......
  • 数学建模入门——描述性统计分析
     摘要:本篇博客主要讲解了数学建模入门的描述性统计分析,包括基本统计量的计算、数据的分布形态、数据可视化和相关性分析。往期回顾:数学建模入门——建模流程-CSDN博客数学建模入门——数据预处理(全)-CSDN博客一、基本统计量基本统计量是描述性统计分析的重要组成部分......