《Orange's 一个操作系统的实现》学习笔记--实践认识保护模式


有了保护模式的理论基础,今天就来实站一下,没有看的一定要看,在结合下面程序的分析,一定就会懂的,下面程序我又加了一些注释,理论上应该没有什么问题了。

; ==========================================
; pmtest1.asm
; 编译方法:nasm pmtest1.asm -o pmtest1.bin
; ==========================================

DA_32		EQU	4000h	; 32 位段
DA_C		EQU	98h	; 存在的只执行代码段属性值
DA_DRW		EQU	92h	; 存在的可读写数据段属性值
ATCE32		EQU	4098h   ;存在的只执行32代码段属性值

;下面是存储段描述符的宏定义
; 有三个参数:段界限,段基址,段属性其中宏定义中的%1代表参数1,%2代表参数2,%3代表参数3
%macro Descriptor 3  

	dw	%2 & 0FFFFh				; 段界限1(参数2的低16位)
	dw	%1 & 0FFFFh				; 段基址1(参数1的低16位)
	db	(%1 >> 16) & 0FFh			; 段基址2(参数1的16-23位)
	dw	((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)	; 属性1(高4位) + 段界限2(高4位) + 属性2(低8位)
	db	(%1 >> 24) & 0FFh			; 段基址3(参数1的24-31位)
%endmacro ; 共 8 字节
;段界限共20位,段基地址30位,段属性共16位(含段界限高4位)

org	07c00h
	jmp	LABEL_BEGIN

[SECTION .gdt]  ;section是告诉编译器划分出一个叫gdt的段
; GDT
;                              段基址,       段界限     ,    属性
LABEL_GDT:	   Descriptor       0,                0, 0           ; 空描述符
LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段(DA_C + DA_32=ATCE32)
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    ;eax*16==段值*16(实模式下不用手工计算,但是这里需要自己计算)
	add	eax, LABEL_SEG_CODE32;加上LABEL_SEG_CODE32偏移,这样eax->LABEL_SEG_CODE32基地址
	mov	word [LABEL_DESC_CODE32 + 2], ax    ;设置基地址1(0-15位)
	shr	eax, 16
	mov	byte [LABEL_DESC_CODE32 + 4], al    ;设置基地址2(16-23位)
	mov	byte [LABEL_DESC_CODE32 + 7], ah    ;设置基地址3(24-31位)

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

	; 加载 GDTR
	lgdt	[GdtPtr]   ;将GdtPtr所指的内容送到GDT寄存器

	; 关中断
	cli

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

	; 准备切换到保护模式
	mov	eax, cr0
	or	eax, 1   ;设置cr0的0位(PE位,PE=1准备进入保护模式)
	mov	cr0, eax ;更新cr0

	; 真正进入保护模式
	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]
我觉得注释挺详细了,但是还是来分析一下吧

(1)常量定义怎么来的?

DA_32		EQU	4000h	; 32 位段
DA_C		EQU	98h	; 存在的只执行代码段属性值


还记得这个图吗?常量就是从这个图中产生的。

4000h=0100000000000000b  --->属性位D=1表示段的上界是4G,所以是32位段

98h   =0000000010011000b   --->p=1表示描述符对地址转换是有效的(存在位),DPL特权级=0,DT=1表示系统段,TYPE=8表示只执行

(2)存储段描述符解释(宏定义)

;下面是存储段描述符的宏定义
; 有三个参数:段界限,段基址,段属性其中宏定义中的%1代表参数1,%2代表参数2,%3代表参数3
%macro Descriptor 3  

	dw	%2 & 0FFFFh				; 段界限1(参数2的低16位)
	dw	%1 & 0FFFFh				; 段基址1(参数1的低16位)
	db	(%1 >> 16) & 0FFh			; 段基址2(参数1的16-23位)
	dw	((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)	; 属性1(高4位) + 段界限2(高4位) + 属性2(低8位)
	db	(%1 >> 24) & 0FFh			; 段基址3(参数1的24-31位)
%endmacro ; 共 8 字节
;段界限共20位,段基地址30位,段属性共16位(含段界限高4位)


段界限共20位,段界限1取其低16位,所以和0ffffh与。

段基地址1同理

段基地址2:16-23位,将段基地址右移16位,得到段基地址高16位,和0ffh与得到低8位(也就是16-23位)。

段基地址3同理

段属性:属性1(高4位) + 段界限2(高4位) + 属性2(低8位)看第一个图,(%2 >> 8) & 0F00h)为属性1,(%3 & 0F0FFh)为段界限2(高4位) + 属性2(低8位),当然也可以这样写((%2 >> 8) & 0F00h) | (%3 & 0F000h)| (%3 & 000FFh)

这样是不是清楚很多了。

[SECTION .gdt]告诉编译器划分出一个叫gdt的段(数据段)

[SECTION .s16],[SECTION .s32]为两个代码段

; GDT
;                              段基址,       段界限     ,    属性
LABEL_GDT:	   Descriptor       0,                0, 0           ; 空描述符
LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段(DA_C + DA_32=ATCE32)
LABEL_DESC_VIDEO:  Descriptor 0B8000h,           0ffffh, DA_DRW	     ; 显存首地址
; GDT 结束
LABEL_GDT(空描述符),LABEL_DESC_CODE32(32位代码段描述符),LABEL_SESC_VIDEO(显示内存描述符)。每个描述符都包含了3个属性,段基址、段界限、段属性。将三个描述符组织到一起构成一个全局段描述符表(GDT)。

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

GDTR示意图:


GdtPtr是不是和GDTR长得一样呀,GdtLen是GDT的长度。GdtPtr为一个数据结构,包含两个元素,第一个元素是2 bytes的GDT界限。第二个元素是4 bytes的GDT的基地址。该数据结构与全局描述符表寄存器(GDTR)的数据结构相同,所以在加载GDTR的时候(源代码55行),就是将该GdtPtr加载到GDTR中。

;                              段基址,       段界限     ,    属性
LABEL_GDT:	   Descriptor       0,                0, 0           ; 空描述符
LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段(DA_C + DA_32=ATCE32)
LABEL_DESC_VIDEO:  Descriptor 0B8000h,           0ffffh, DA_DRW	     ; 显存首地址
由于第一个段LABEL_GDT是空描述符,它仅仅代表该GDT的初始地址,所以该描述符为空描述符,一般情况下,不为它创建选择子。然后该程序建立了两个选择子SelectorCode32和SelectorVideo,分别对应着这两个段LABEL_SESC_CODE32和LABEL_DESC_VIDEO, 一致和非一致后面会解释的。

在保护模式下,首先使用段选择子在段描述符表中查找到相对应的段描述符,找到32位段基址,然后在与32位的偏移量相加,得到线性地址。段基址和段偏移量都是32位的,所以寻址范围大小为4GB。在程序中jmp dword SlectorCode32:0的作用,就是进入保护模式下的寻址方式。其中,在使用某个段时,它的段选择子是存储在段寄存器中的。

剩下的在代码中解释得很清楚了,这样应该清楚了吧


下面总结一下进入保护模式的主要步骤:

1.准备GDT

2.用lgdt加载gdtr

3.打开A20

4.置cr0的PE位

5.跳转,进入保护模式

注:使用在上次建立的软盘镜像,如果新创建,那么必须在结尾的地方加上aa55h标志,我开始就没有意识到,总是失败,后面自己在后面加结束标记但是没有成功,最后还是用的上次创建的镜像。

参考:

《Orange's 一个操作系统的实现》学习笔记--保护模式理论初步(二)

《Orange's 一个操作系统的实现》学习笔记--保护模式理论初步(一)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
orange's个操作系统实现》是一本关于操作系统实现的书籍,其中第六章无法运行可能有以下几个原因。 首先,书中的代码可能存在错误。编写代码时,一些细节的失误可能导致程序无法正确运行。这可能是作者在编写书籍时出现的问题,或者是影响到第六章的代码遗漏或错误。在实际操作中,我们应该检查在书中提供的代码并尝试找到错误。 第二,缺少必要的软件或工具。在开发操作系统时,通常需要使用一些特定的软件和工具,例如汇编器、编译器、链接器等。如果这些软件或工具没有正确安装或配置,可能会导致第六章中的代码无法运行。 第三,硬件环境不符合要求。在实际操作系统的开发中,硬件环境的要求可能较高。如果硬件配置不符合第六章中所述的要求,例如内存容量过低或者缺少某些关键的硬件设备,那么无法保证代码能够正确运行。 最后,操作系统开发环境的设置可能有问题。正确设置开发环境是操作系统开发的关键。如果遗漏了某些设置步骤,例如环境变量的配置或者文件路径的设置等,那么第六章的代码可能无法正常运行。 针对以上可能的原因,我们可以先检查书中代码的正确性,然后逐步检查所需软件和工具的安装与配置,以及硬件环境是否符合要求。如果仍然无法解决问题,我们可以尝试在相关的开发社区或论坛上寻求帮助,与其他开发者交流并寻找解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值