首页 > 其他分享 >操作系统:保护模式(一)GDT 与分段机制

操作系统:保护模式(一)GDT 与分段机制

时间:2024-10-01 17:25:57浏览次数:6  
标签:保护模式 GDT 分段 mov LABEL 描述符 ax

GDT 与分段机制

CPU开机时运行于实模式,寻址方式是段寄存器 \(\times\) 10+偏移寄存器=物理地址,主要原因是因为 8086 地址线和数据线不匹配导致的。但是这种寻址方式既不安全也不支持现代操作系统所需的、多任务支持、cpu 特权模式等。

在实模式下,对于基址,变址寻址的寄存器有明确要求。在保护模式下,除了 esp 以外的所有通用寄存器均可以用于基址,变址寻址。

在 x86 引入的保护模式下,CPU的32条地址线全部有效,可寻址高达4G字节的物理地址空间。为了维护保护模式所支持的各类信息,同时为了兼容,x86 仍然采用分段的方式划分内存,这些关于内存段的限制信息放在一个叫做 全局描述符表(Global Descriptor Table,全球描述符表)的结构里。全局描述符表中含有一个个表项,每一个表项称为段描述符(Descriptor)。而在保护模式下要生成最终的地址,显然就变成了先到 GDT 里拿段基址,再和偏移地址组合起来。而 GDT 由于存了很多段,所以就需要有个指针指向哪个段,这个指针就是段选择子(Selector),平时放在段寄存器里。

注意:GDT 的第 0 个描述符被保留为无效
目的是为了防止非法的段访问,并提供一种有效的机制来检测和处理无效的段引用。通过这种设计,可以增强系统的安全性和稳定性。

由于历史原因,段的基址与界限等被分割为几个块存放到描述符中。

  1. 段基址(32 位):是该内存段的基地址
  2. 段界限表示段边界的扩张最值,即最大扩展多少或最小扩展多少,用20位来表示,它的单位可以是字节,也可以是 4KB,这是由G位决定的(G为1时表示单位为4KB)。
  3. 段的属性和权限标志,它与界限的高 4 位组合在一起。典型的段属性包括:
    • 段类型(可执行、可读写等)
    • DPL(Descriptor Privilege Level,描述符特权级别)
    • P 位(Present 位,段是否存在)
    • G 位(Granularity,粒度位)
    • AVL 保留备用
    • D/B 位(默认操作大小位,用于指示段是16位模式还是32位模式)

\[实际段界限边界值=(描述符中的段界限+1) \times 段界限的单位大小(即字节或4KB))-1 \]

这样,每个段在GDT中都规定了大小然后选择子选择了段后,只能访问这个段内的内存,CPU 在越界访问会发生异常。达到了保护模式的效果。

段选择子(Selector) 实际上是 GDT 表索引与三位属性的组合:

  • 低 2 位即第 0~1 位, 用来存储 RPL,即请求特权级 ( 0、 1、 2、 3 四种特权级,数字越小权限越大)
  • 第 2 位是 TI 位,即 Table Indicator,用来指示选择子是在 GDT 中,还是 LDT 中索引描述符

于是,x86 的分段寻址机制如图所示:

LDT: 历史的遗留

LDT(Local Descriptor Table,本地描述符表)是 x86 架构中用于内存管理的一个结构,最早是在 x86 保护模式下引入的。它的主要作用是定义任务或进程的内存段。LDT 是 GDT(Global Descriptor Table,全局描述符表)的补充,但它针对的是每个任务或进程的局部内存段定义。

在 x86 的段式内存管理中,内存通过段(segment)来访问。段可以定义代码段、数据段或堆栈段等不同类型的内存区域。每个段有自己的基地址、限制(size),以及访问权限控制。这些段的信息存储在一个描述符表中。GDT 和 LDT 就是用于存储这些段描述符的表。

LDT 的设计是为了支持多任务和进程的隔离。它允许每个任务定义自己的段,使得内存保护和隔离更加灵活。LDT 的选择子可以为 1.

但由于现代操作系统普遍采用扁平内存模型和分页机制,LDT 的使用逐渐减少甚至被废弃。它的功能已被分页机制很好地取代,同时也简化了系统的内存管理和任务切换。

简单的引导程序:进入 32 位保护模式

进入保护模式,需要

  1. 设定 GDT 表,GDT 通常第一个描述符是空描述符,它的基地址和段界限都为 0。
  2. 加载 GDTR:寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。
  3. 关中断 (cli):保护模式的中断机制与默认实模式不同
  4. 打开地址线A20: 历史遗留问题,这是为了避免“回卷”现象出现
  5. 将 cr0 寄存器的 PE 位置为 1,此时 CPU 就已经进入保护模式
  6. 跳转到 保护模式的代码段 (jmp dword)

描述符构造宏

%macro Descriptor 3
	dw	%2 & 0FFFFh				; 段界限1
	dw	%1 & 0FFFFh				; 段基址1
	db	(%1 >> 16) & 0FFh			; 段基址2
	dw	((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)	; 属性1 + 段界限2 + 属性2
	db	(%1 >> 24) & 0FFh			; 段基址3
%endmacro ; 共 8 字节

示例:在 DOS 下进入 x86 保护模式

%include	"pm.inc"	; 常量, 宏, 以及一些说明

org	0100h
	jmp	LABEL_BEGIN

[SECTION .gdt]
; GDT
;                              段基址,      段界限     , 属性
LABEL_GDT:	   Descriptor       0,                0, 0           ; 空描述符
LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段
LABEL_DESC_VIDEO:  Descriptor 0B8000h,           0ffffh, DA_DRW	     ; 显存首地址
; GDT 结束

GdtLen		equ	$ - LABEL_GDT	; GDT长度
GdtPtr		dw	GdtLen - 1	; GDT界限
		dd	0		; GDT基地址

; GDT 选择子
SelectorCode32		equ	LABEL_DESC_CODE32	- LABEL_GDT
SelectorVideo		equ	LABEL_DESC_VIDEO	- LABEL_GDT
; END of [SECTION .gdt]

[SECTION .s16]
[BITS	16]
LABEL_BEGIN:
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	ss, ax
	mov	sp, 0100h

	; 初始化 32 位代码段描述符
	xor	eax, eax
	mov	ax, cs
	shl	eax, 4
	add	eax, LABEL_SEG_CODE32
	mov	word [LABEL_DESC_CODE32 + 2], ax
	shr	eax, 16
	mov	byte [LABEL_DESC_CODE32 + 4], al
	mov	byte [LABEL_DESC_CODE32 + 7], ah

	; 为加载 GDTR 作准备
	xor	eax, eax
	mov	ax, ds
	shl	eax, 4
	add	eax, LABEL_GDT		; eax <- gdt 基地址
	mov	dword [GdtPtr + 2], eax	; [GdtPtr + 2] <- gdt 基地址

	; 加载 GDTR
	lgdt	[GdtPtr]

	; 关中断
	cli

	; 打开地址线A20
	in	al, 92h
	or	al, 00000010b
	out	92h, al

	; 准备切换到保护模式
	mov	eax, cr0
	or	eax, 1
	mov	cr0, eax

	; 真正进入保护模式
	jmp	dword SelectorCode32:0	; 执行这一句会把 SelectorCode32 装入 cs,
					; 并跳转到 Code32Selector:0  处
; END of [SECTION .s16]


[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS	32]

LABEL_SEG_CODE32:
	mov	ax, SelectorVideo
	mov	gs, ax			; 视频段选择子(目的)

	mov	edi, (80 * 11 + 79) * 2	; 屏幕第 11 行, 第 79 列。
	mov	ah, 0Ch			; 0000: 黑底    1100: 红字
	mov	al, 'P'
	mov	[gs:edi], ax

	; 到此停止
	jmp	$

SegCode32Len	equ	$ - LABEL_SEG_CODE32
; END of [SECTION .s32]

从 x86 保护模式返回实模式

[SECTION .gdt]
; GDT
;
LABEL_DESC_NORMAL: Descriptor    0,         0ffffh, DA_DRW    ; Normal 描述符
; ....

[SECTION .s16]
[BITS	16]
LABEL_BEGIN:
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	ss, ax
	mov	sp, 0100h

	mov	[LABEL_GO_BACK_TO_REAL+3], ax
	mov	[SPValueInRealMode], sp
;....

LABEL_REAL_ENTRY:		; 从保护模式跳回到实模式就到了这里
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	ss, ax

	mov	sp, [SPValueInRealMode]

	in	al, 92h		; `.
	and	al, 11111101b	;  | 关闭 A20 地址线
	out	92h, al		; /

	sti			; 开中断

	mov	ax, 4c00h	; `.
	int	21h		; /  回到 DOS
; END of [SECTION .s16]

; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
[SECTION .s16code]
ALIGN	32
[BITS	16]
LABEL_SEG_CODE16:
	; 跳回实模式:
	mov	ax, SelectorNormal
	mov	ds, ax
	mov	es, ax
	mov	fs, ax
	mov	gs, ax
	mov	ss, ax

	mov	eax, cr0
	and	al, 11111110b
	mov	cr0, eax

LABEL_GO_BACK_TO_REAL:
	jmp	0:LABEL_REAL_ENTRY	; 段地址会在程序开始处被设置成正确的值

Code16Len	equ	$ - LABEL_SEG_CODE16

; END of [SECTION .s16code]

指令扩展

在 实模式,保护模式下的部分指令 mul, div, push, pop 等行为有明显差异,例如 push

  • 如果操作数为 8 位,实模式会扩展到 16 位,保护模式 (32 位) 户扩展到 32 位压入栈
  • 如果操作数为 16 位或32位,实模式和保护模式都直接压入 sp - 2 / sp - 4

标签:保护模式,GDT,分段,mov,LABEL,描述符,ax
From: https://www.cnblogs.com/himu-qaq/p/18442980

相关文章

  • 操作系统:保护模式(二)内存模型
    平坦内存模型现代操作系统一般不会使用过于复杂的分段机制,而是采用平坦内存模型+分页模型来管理内存。平坦内存模型(FlatMemoryModel),这是现代操作系统(如Linux和Windows)常用的内存模型。在这种模型中,所有段的段基址都为0,段界限为4GB,使得整个内存空间看起来像一个连续的内......
  • 操作系统:保护模式(五)特权
    特权机制特权特权级数值越大,级别越小。通常,因为操作系统是为所有程序服务的,可靠性最高,而且必须对软硬件有完全的控制权,所以它的主体部分必须拥有特权级0,并处于整个环形结构的中心。也正是因为这样,操作系统的主体部分通常又被称做内核(Kernel、Core)。特权级1和2通常赋予那......
  • 【高中数学/函数/零点】求分段函数f(x)=x^2-4x+2(x>=1) f(x)=|lg(1-x)| (x<1)的零点个
    【问题】已知分段函数f(x)=x^2+2x(当x<=0时),f(x)=|lgx|(当x>0时),则函数g(x)=f(1-x)-1的零点个数为几个?【来源】《高考数学极致解题大招》P137变式训练第1题 中原教研工作室编著【解答】f(1-x)-1=0即f(1-x)=1当1-x>0,即x<1时,f(1-x)=|lg(1-x)|=1去掉绝对值符号有两种可能,lg(1-x)=1......
  • 使用memcpy进行分段copy
    一、概述使用场景:在音视频开发中,用YUV数据+OpenGL进行画面渲染。经常会将Y分量、U分量、V分量分开。分别上传到GPU,由GPU转换为RGB进行最终展示。使用这种方式的原因是基于GPU计算效率高为前提的。在这个过程中经常会用到一个c函数memcpy。将yuv数据分别c......
  • 什么是内存分页和分段
    内存分页和分段是操作系统用于管理内存的一种技术,旨在提高内存的使用效率和安全性。它们各自有不同的结构和目的。1.内存分页(Paging)概述内存分页是一种将物理内存划分为固定大小的块(称为页,通常为4KB)和将逻辑地址空间划分为相同大小的块(称为页表)的机制。分页允许不连续的物理内......
  • Datawhale X 李宏毅苹果书 AI夏令营-深度学习入门班-task2-分段线性曲线
    引入上一篇文章中我们了解了机器学习中最基本的模型线性模型(Linearmodels),由于其过于简单(只能调整其斜率w与截距b)无法反映真实数据中多数折线或曲线情况这种限制称为模型偏差(modelbias)。下文介绍:如何构建更复杂,误差更小的函数解决问题。注:此处的bias与线性模型中的b不同。......
  • MEMS 传感器 4GDTU 说明书
        本系统经过精心设计,可无缝对接三石峰的振动管理系统平台。通过该平台,用户可直观查看传感器数据、分析振动趋势、预警潜在故障,并依据分析结果制定针对性的维护策略,从而有效提升设备运行的可靠性与安全性。    本产品广泛应用于工业制造、交通运输、能源......
  • 洛谷P1182 数列分段 Section II
    传送门:P1182数列分段SectionII消灭人类暴政,世界属于三体题目意思:题目说的很明白了思路:考虑部分分:20%的数据保证n<10,直接爆搜;40%的数据保证n<1000,n^2+前缀和搞定100%的数据:求每段最大和的最小值:明显的二分(n在10^5的范围也说明了这一点,因为二分查找的......
  • C# Rsa加密(私钥加密、公钥解密、密钥格式转换、支持超大长度分段加密)
        此为工具类,这个和java版本的加密对比过了,结果是一样的,代码赋值黏贴直接用,不多比比,直接上代码(需要在nuget上寻找"Portable.BouncyCastle"包安装):  (java端有个和c#端不一样的地方,base64编码有好几套,有时候对不上大概率是base64那边的问题)     usingOrg.Bouncy......
  • chapter11------进入保护模式
    全局描述符表(GDT)这里要先说明下,保护模式下对内存段的访问是有限制的,简单来说就是你不能再随意的访问了,只能访问授权给你的,然后段的访问限制等等信息就记载在一个叫做全局描述表里段描述符段描述符存储了某个段的具体信息,就像我们每个人的档案一样,记录着我们的信息然后段描述......