依旧直接贴代码:
%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:2608184397@qq.com
假设读者朋友也有开发操作系统的想法,能够联系我。