操作系统开发系列—2.进入32位保护模式
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
; ==========================================
; pm.asm
; 编译方法:nasm pm.asm -o pm.bin
; ==========================================
%include "pm.inc" ; 常量, 宏, 以及一些说明
org 07c00h
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,
; 并跳转到 SelectorCode32:0 处
; END of [SECTION .s16]
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS 32]
LABEL_SEG_CODE32:
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子(目的)
mov ecx, 28
mov edi, 0
mov bx, BootMessage
.show:
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov al, [bx]
mov [gs:edi], ax
inc edi
inc edi
inc bx
loop .show
; 到此停止
jmp $
BootMessage: db "Joey, I'm in protected mode!"
SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]
|
运行结果如下:
源码解析:
1.首先程序跳转至LABEL_BEGIN处,jmp LABEL_BEGIN。将ds、es、ss段寄存器全部初始化为当前代码段。
2.初始化32位代码段描述符
在实模式下,也就是8086的16位的CPU的寻址方式是段x16+偏移,而在保护模式下,段寄存器值变成了一个索引,这个索引指向段描述符,也就是GDT中对应的那个描述符,描述符中包含了最终的基地址。
38-41行表示将当前程序代码段左移4位也就是x16,再加上LABEL_SEG_CODE32的偏移地址,最终形成LABEL_SEG_CODE32的物理地址,42-45表示把此物理地址加载到段描述符对应的段基址位置,段描述符格式如下图所示
段基地址0-15位也就是LABEL_DESC_CODE32 + 2地址处,将16位的ax传入,第43行向右移动16位表示已经传入的16位消除,然后将剩余的两个8位高低寄存器值传入对应的段基地址处。
Descriptor是在pm.inc中定义的宏,如下图所示,表示的就是段描述符的格式:
3.加载GDTR,GDRT的结构图如下所示
GDTR是唯一的一个指向段描述符表的寄存器,48-55行就是把段描述符表的基地址加载到GDTR寄存器当中。48行清除eax值,49-52是把LABEL_GDT的物理地址加载到20行的GdtPtr的双字处,也就是GDT基地址。55行把GdtPtr地址的内容加载到GDTR,双字节dw对应的是16位界限,双字dd对应的是32位基地址。
4.关中断和打开A20
保护模式下中断处理机制和实模式不同,所以先关闭中断,指令为cli。打开A20为历史原因防止偏移超出最大值时回滚。58-63行
5.切换到保护模式
只要把寄存器cr0的第0位置为1就行了。66-68行
6.真正进入保护模式的代码段
jmp dword SelectorCode32:0,这一行是真正进入保护模式的代码,SelectorCode32是个段选择子,段选择子的作用是找到对应的段描述符从而找到对应的段基地址。段选择子的格式如下图所示
从位3开始表示为段描述符表的索引,这句代码执行完之后就会把描述符LABEL_DESC_CODE32中的段基址也就是LABEL_SEG_CODE32加载到cs。
dword的作用是因为当前还是16位的代码,如果没有dword,SelectorCode32:0的偏移地址如果超出16位那么只会截取16位。
到此已经完全进入32位保护模式的代码了。
7.显示字符
接下来就会跳转到LABEL_SEG_CODE32处运行指令了,80-81行把段选择子SelectorVideo传入段寄存器gs中,也就是描述符LABEL_DESC_VIDEO的段基地址0B8000h,这就是显存的基地址。84行edi是显存的偏移地址,87-88行是字符及字符属性,89行为最终显示字符。
8.描述符属性
代码段的属性是DA_C + DA_32,根据pm.inc中的定义,DA_C是98h
对应的二进制为10011000。根据第2条的格式,DA_C其实是上面的第8-15位,第15位P是1表明这个段在内存中存在,S位是1表明这个段是代码段或数据段,TYPE为1000也就是8表明这个段是只执行的代码段,TYPE格式如下图所示
DA_32是4000h,
4000h为100000000000000,表明是从上面的位8开始计算的后面15位也就是D/B位为1,表明这个段是32位的代码段。
操作系统开发系列—2.进入32位保护模式相关推荐
- x86汇编语言从实模式百度云_Intel x86 CPU 32位保护模式杂谈之任务切换 上
目录: 什么是任务 任务由什么组成 任务门描述符是什么东东?有了TSS描述符为什么要有任务门描述符? 参考文献 什么是任务 任务(task)是处理器可以分配.执行.挂起的工作单位,笔者认为和我们操作系 ...
- 《操作系统真象还原》第4章 保护模式入门 ing... 持续更新
目录 文章目录 目录 概述 初见保护模式 代码 32push.S 全局描述符表 段描述符 GDT.LDT及选择子 GDT 选择子正式介绍 LDT 打开A20地址线 保护模式的开关,CR0寄存器的 PE ...
- 文末赠书《GD32 MCU原理及固件库开发指南》5本 | 国产MCU中GD32系列有望成为未来32位MCU的主流
学习优秀博文([guo产MCU移植]手把手教你使用RT-Thread制作GD32系列BSP)有感 一篇优秀的博文是什么样的?它有什么规律可循吗?优秀的guo产32位单片机处理器是否真的能成功替换掉st ...
- 软硬件兼容STM32F103系列的国产32位MCU
介绍一款软硬件兼容STM32F103系列的国产32位MCU,此款32位MCU采用高性能ARM®Cortex®-M3 32位RISC内核,216兆赫兹频率运行,内置256KB的闪存和高达96KB的SRA ...
- 30天自制操作系统:第三天 进入32位模式并导入C语言
今天的内容稍稍有点多,一起看看吧 1.制作真正的IPL 到昨天为止,讲到的启动区虽然也称为IPL(Initial Program Loader,启动程序装载器),但它实质上并没有装载任何程序. 小节中 ...
- 32位java 最大内存_【答疑系列】为什么32位系统只支持最大4G内存?
这个问题一直都有同学问到,算是提问次数最多的问题之一了. 32位是什么 现在主流的操作系统都是64位的,早期存在32位操作系统,相信大家也都有所听闻,其实,在更早之前,还有16位.8位的,这里就不展开 ...
- BPI-Bit 开发板带有Xtensa 32位LX6双核处理器的嵌入式系统的ESP 32
BPI:bit(也称为BPI-bit,作为webduino:bit)是一个带有Xtensa 32位LX6双核处理器的嵌入式系统的ESP 32.支持Webduino.Arduino.微python以及S ...
- 操作系统真象还原第5章:保护模式进阶,向内核进阶
前言 由于涉及到马上要搞实习的事情,搞得我十分的浮躁,自己也是频繁失眠,想来还是自己太过懒了,没控制住自己,自己也在这一个多月没搞好,尤其是本来想花几天时间来写一个高性能服务器,也把游双大佬的linu ...
- 操作系统真象还原——第5章 从保护模式到内核
目录 前言 5.1 获取物理内存容量 5.1.1 学习Linux获取内存的方法 5.1.2 实战内存容量检测 5.2 内存分页 为什么需要分页? 一级页表 二级页表 如何设计一个页表 分页机制的代码实 ...
最新文章
- 【剑指offer-Java版】40数组中只出现一次的数字
- Linux wget 命令详解
- IBatis.net动态SQL语句
- vue进行判断使用class_vue如何判断dom的class
- linux下安装树梅派系统,优麒麟树莓派系统(优麒麟 for Raspberry Pi)的安装方法...
- 软件公司管理基本原则
- Flask爱家租房--订单支付(支付过程)
- 电脑很卡~~~~为什么???
- Visual Studio Code预览版Ver 0.3.0试用体验
- window java 环境_Windows配置java环境
- atitit 文件搜索 映象文件夹结构模式.docxAtitit 百度网盘 文件 与跨机器 文件 搜索 查询 检索 解决方案 最小化索引法 映象文件夹结构模式. 1. 生成文件夹 结构信息	1
- Java 序列化与反序列化详解
- Python中inplace参数
- overflow属性的用法
- c语言 字符串转换中文乱码,怎么将unicode转中文字符编码存在文本中
- 不管你学的是什么专业,你都应该多少懂些管理学的东西之【鳄鱼法则】【鲇鱼效应】...
- 基于STM32和hs1527、ev1527、rt1527、fp1527的无线接收解码程序
- windows使用cmd删除目录和文件(详细)
- 日本轮胎制造商纷纷提高轮胎价格
- 基于springboot+vue的幼儿园管理系统 elementui
热门文章
- Python第四章-字典
- 栈 - 关于出栈序列,判断合法的出栈序列
- 【Linux 内核 内存管理】RCU 机制 ④ ( RCU 模式下更新链表项 list_replace_rcu 函数 | 链表操作时使用 smp_wmb() 函数保证代码执行顺序 )
- 【开发环境】安装 Visual Studio Community 2013 开发环境 ( 下载 Visual Studio Community 2013 with Update 5 版本的安装包 )
- 【Google Play】管理目标受众群体 ( 加入“亲子同乐计划“ 由于政策原因 “更新被拒“ 后的处理 )
- 【OpenGL】二十二、OpenGL 光照效果 ( 模型准备 | 光照设置 | 启用光照 | 启用光源 | 设置光源位置 | 设置光照参数 | 设置环境光 | 设置反射材质 | 设置法线 )
- 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 将系统的 dexElements 与 应用的 dexElements 合并 | 替换操作 )
- php中static和self的区别
- 对象及变量的并发访问一
- android中可以使用bitmap的平铺,镜像平铺等减小图片带来的apk过大的问题