操作系统开发之——进入保护模式

依然直接贴代码:

%macro Descriptor 3
	dw	%2 & 0FFFFh				; 段界限 1				(2 字节)
	dw	%1 & 0FFFFh				; 段基址 1				(2 字节)
	db	(%1 >> 16) & 0FFh			; 段基址 2				(1 字节)
	dw	((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)	; 属性 1 + 段界限 2 + 属性 2		(2 字节)
	db	(%1 >> 24) & 0FFh			; 段基址 3				(1 字节)
%endmacro ; 共 8 字节
SA_RPL0		EQU	0	; ┓
SA_RPL1		EQU	1	; ┣ RPL
SA_RPL2		EQU	2	; ┃
SA_RPL3		EQU	3	; ┛

DA_32		EQU	4000h	; 32 位段
DA_LIMIT_4K	EQU	8000h	; 段界限粒度为 4K 字节

DA_DPL0		EQU	  00h	; DPL = 0
DA_DPL1		EQU	  20h	; DPL = 1
DA_DPL2		EQU	  40h	; DPL = 2
DA_DPL3		EQU	  60h	; DPL = 3

DA_DR		EQU	90h	; 存在的只读数据段类型值
DA_DRW		EQU	92h	; 存在的可读写数据段属性值
DA_DRWA		EQU	93h	; 存在的已访问可读写数据段类型值
DA_C		EQU	98h	; 存在的只执行代码段属性值
DA_CR		EQU	9Ah	; 存在的可执行可读代码段属性值
DA_CCO		EQU	9Ch	; 存在的只执行一致代码段属性值
DA_CCOR		EQU	9Eh	; 存在的可执行可读一致代码段属性值
; 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:		Descriptor               0,          0fffffh,  DA_DRW | DA_32 | DA_LIMIT_4K			; 0 ~ 4G
LABEL_DESC_VIDEO:		Descriptor	             0B8000h,          0ffffh,   DA_DRW | DA_DPL3	; 显存首地址
; GDT ----------------------------------------------------------------------------------------------------------------------------------------------------

GdtLen		EQU	$ - LABEL_GDT
GdtPtr		DW	GdtLen - 1				; 段界限
		DD	0x80000 + LABEL_GDT
; GDT 选择子 ----------------------------------------------------------------------------------
SelectorFlatC		EQU	LABEL_DESC_FLAT_C	- LABEL_GDT
SelectorFlatRW		EQU	LABEL_DESC_FLAT_RW	- LABEL_GDT
SelectorVideo		EQU	LABEL_DESC_VIDEO	- LABEL_GDT + SA_RPL3
; GDT 选择子 ----------------------------------------------------------------------------------
;准备切换到保护模式
	MOV	EAX,CR0 ;获取CR0配置
	OR	EAX,1 ;修改CR0的第0位(PE位),进入保护模式
	MOV <span style="white-space:pre">	</span>CR0,EAX ;将修改过的配置送回CR0

	JMP dword SelectorFlatC:(0x80000 + Protect_Mode)
[bits 32]
Protect_Mode:
	MOV AX,SelectorFlatRW
	MOV DS,AX
	MOV SS,AX
	MOV ES,AX
	MOV FS,AX
	MOV AX,SelectorVideo
	MOV GS,AX
         JMP $

嗯哼,读者朋友一定会问:前面那一大段干虾米的?

答:那可是著名的段选择子,那可是要加载到各个段里面的,在这里不细说,我们将在下一篇文章来讨论段选择子,当然,前面还有一个数据结构,类似于C语言中的struct,这是为了简化程序,用最简便的方法来完成传递参数。

废话不多说,直接进入正题,在这里介绍一下CR0

CR0,用于控制和确定处理器的操作模式以及当前执行任务的特性,(其实CR0——CR3都是),我们在这里不介绍其他位,只介绍PE位(保护模式位)。

我们先取出CR0的配置,然后用OR运算符把PE位(第0位)置1,接着把CR0的配置送回。

(完了?)当然没有。我们还有一个历史性的JMP。

在这里笔者建议读者朋友看《X86汇编语言:从实模式到保护模式》(如果没有学习过长跳转)。为什么要看呢?因为接下来讲的可能读者朋友有些吸收不了。

JMP dword SelectorFlatC:(0x80000 + Protect_Mode)

现在我列出几个读者可能会问的问题。

一:为什么要加上那个0x80000:

答:因为Nasm和C语言的标识符默认没有加上当前的物理地址,(即把当前程序的开始地址当做0)

二:为什么要加上一个dword

答:我们先做一个实验,”JMP 8:0x12345678“,这一句没有加dword把,但是他运行出来的结果是”JMP 8:0x5678“,现在能明白为什么要加上dword了吧。

三:为什么前面有SelectorFlatC标识符呢?

答:我们在后面会讲到,这是个段选择子。

四:为什么一定要有这个JMP呢?

答:因为这个JMP(事关重大太严重了,嘻嘻)一要更新CS,二要跳转到32位段,三。。。。

就这么简单。

如果还有问题可以联系我:Email:[email protected]

如果读者朋友也有开发操作系统的想法,可以联系我。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-30 13:43:27

操作系统开发之——进入保护模式的相关文章

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

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

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

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

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

0.11之路(四):从实模式到保护模式

(一)关中断并将system移动到内存地址起始位置 0x00000 将CPU的标志寄存器(EFLAGS)中的中断允许标志(IF)置0.这样系统不会再响应中断,直到main函数中能够适应保护模式的中断服务体系重建完毕才会打开,那时候响应中断的服务程序将不再是BIOS提供的中断服务程序,而是系统自身提供的. 就是要完成实模式下的中断向量表和保护模式下的中断描述符表(IDT)的交接工作.借助关中断(cli)和开中断(sti)完成这个过程的创建,即在创建过程中不能去响应中断,否则没有对应的中断程序,系统

程序的加载和执行(六)——《x86汇编语言:从实模式到保护模式》读书笔记26

程序的加载和执行(六)--<x86汇编语言:从实模式到保护模式>读书笔记26 通过本文能学到什么? NASM的条件汇编 用NASM编译的时候,通过命令行选项定义宏 Makefile的条件语句 在make命令行中覆盖Makefile中的变量值 第13章习题解答 复习如何构造栈段描述符 我们接着上篇博文说. 在我修改后的文件中,用到了条件汇编. 比如: %ifdef DEBUG put_core_salt: ;打印内核的符号 ... ... put_usr_salt: ;打印用户的符号 ... .

CPU 实模式 保护模式 和虚拟8086模式

从80386开始,CPU有三种工作方式:实模式,保护模式和虚拟8086模式.只有在刚刚启动的时候是real-mode,等到操作系统运行起来以后就切换到protected-mode.实模式只能访问地址在1M以下的内存称为常规内存,我们把地址在1M 以上的内存称为扩展内存.在保护模式下,全部32条地址线有效,可寻址高达4G字节的物理地址空间; 扩充的存储器分段管理机制和可选的存储器分页管理机制,不仅为存储器共享和保护提供了硬件支持,而且为实现虚拟存储器提供了硬件支持; 支持多任务,能够快速地进行任务

80x86保护模式下IDT和中断调用过程分析

1.中断描述符表(IDT),将每个异常或中断向量分别与它们的处理过程联系起来.与GDT和LDT类似,IDT也是由8字节长度的描述符组成.IDT空描述符的存在标志位必须是0.IDT表可以驻留在线性地址空间的任何地方,处理器使用IDTR寄存器来定位IDT表的位置. LIDT指令可以把内存中的限长值和基地址操作数加载到IDTR寄存器中,该指令仅能由当前特权级CPL是0的代码执行,通常被用于创建IDT时的操作系统初始化代码中.SIDT作用相反,但可以在任何特权级执行. 2.IDT描述符 IDT表中可以存

80X86保护模式及其编程(一)

80x86系统寄存器和系统指令 1.标志寄存器(EFLAGS) 标志寄存器EFLAGS的标志位含义如下图: TF 位8是跟踪标志(Trace flag),当设置该位时可为调试操作启动单步执行方式.复位时则禁止单步执行.在单步执行方式下,处理器会在每个指令执行后产生一个调试异常,这样我们可以观察执行程序在每条指令执行后的状态. IOPL 位13-12时I/O特权级(I/O Privilege Level)字段.该字段指明当前运行程序或任务的I/O特权级别IOPL.当前任务或程序的CPL必须小于这个

CPU保护模式深入探秘

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