一个操作系统的设计与实现——第19章 IA32-e模式
19.1 64位段描述符与GDT
在32位操作系统中,我们使用的是平坦模型而非分段模型,从而,段描述符的段基址和段限长均成了摆设。在64位模式下,就连CPU也淘汰了分段模型,转而固定使用平坦模型。
64位代码段描述符如下图所示:

如图所示,由于固定使用平坦模型,段描述符中的段基址、段限长、粒度等位均被忽略或固定为0,此时的段描述符不再提供段基址,只能提供其是否存在、描述符类型、DPL等信息。
段描述符的第53位为L位,在保护模式中,这一位是段描述符中唯一的保留位,其正是为64位模式准备的,作用如下:
- 如果这一位为0,段描述符是32位的
- 否则,如果这一位为1,段描述符是64位的
对于数据段,ds、es、ss均直接被忽略,fs、gs的段基址可由特殊方法设定,其他信息,如段限长等亦被忽略。这里的"特殊方法"将在后续章节中讨论。然而,在实际测试中笔者发现:在bochs中,某些指令,如iretq等,并不会忽略数据段描述符,这可能是bochs的bug。因此,在我们的操作系统中仍然需要定义数据段描述符。
64位模式下的GDT仍然使用16位的表限长,但表的起始地址拓展到64位,也就是说,GDTR现在由一段2 + 8 == 10字节的内存组成。
19.2 三级分页模式
一个页表或页目录表的大小都是一页,其中存放了1024个32位的地址,需要一个10位的二进制数作为其索引值。现在,如果将地址的宽度拓展到64位,表的大小不变,则一个表中能存放的地址数量就减少到512个,只需要一个9位的二进制数作为其索引值。
考察二级分页模式的虚拟地址,其由两个10位的索引值和一个12位的页内偏移量组成。如果使用上述方法将索引值减少到9位,虚拟地址就空出了两位,这两位可以构成第三个索引值,从而将分页层级扩展到三级。这种分页模式,就称为PAE(Physical-Address Extension,物理地址扩展)模式,或通俗的称为三级分页模式。
三级分页模式的第三个索引值只有两位,只能用于一个长度为4的表,这个表就称为页目录指针表(Page Directory Pointer Table,PDPT),其中的表项就称为页目录指针项(Page Directory Pointer Table Entry,PDPTE)。PDPT是三级分页模式的起点,其物理地址需要安装到cr3中。PDPTE的存在位、权限位等与PDE/PTE相同。
三级分页模式是32位虚拟地址到64位物理地址的映射,因此,虽然虚拟地址还是32位的,只能表示4G内存,但通过反复切换cr3中的PDPT,(理论上)就能访问到整个64位物理地址空间了。
19.3 四级与五级分页模式
三级分页模式明显是个很别扭的过渡产物,在64位CPU中,虚拟地址也拓展到了64位,此时,可以将虚拟地址拆成12 + 9 + 9 + 9 + 9 + 9 + 7 == 64位,从而构造出六级分页模式。然而,这样的地址实在是太大了,远远超过了目前物理内存的实际大小,因此,出于成本和运行效率考虑,目前的CPU只支持四级或五级分页模式。
四级与五级分页模式中新增的表不再沿用PDPTE这样别扭的名称,而是简单的称为四级页表(Page Map Level 4,PML4)与五级页表(Page Map Level 5,PML5),其中的表项就称为四级页表项(Page Map Level 4 Entry,PML4E)与五级页表项(Page Map Level 5 Entry,PML5E)。PML4E、PML5E的存在位、权限位等与PDE/PTE相同。
IA32-e模式必须使用四级或五级分页模式,因此,我们的操作系统使用四级分页模式。PML4作为四级分页模式的起点,其物理地址需要安装到cr3中。
四级分页模式只使用12 + 9 + 9 + 9 + 9 == 48位虚拟地址,对于剩余的高位,CPU要求:虚拟地址的高16位必须与第47位一致,满足此要求的地址被称为规范地址(Canonical Address)。如果使用不规范的地址,CPU会抛出异常。
考察规范地址,可以发现其由以下两部分组成:
0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff0xffff_8000_0000_0000 ~ 0xffff_ffff_ffff_ffff
这两段地址的范围一样,并且都很大,因此,自然的适用于划分内核地址空间与任务地址空间,我们的操作系统正是这么做的。
在四级或五级分页模式下,如果将PDE的第7位置1,则可打开2M大页模式。此时,PDE不再指向页表,而是直接指向一个2M大页的起始地址,由虚拟地址中剩余的12 + 9 == 21位构成页内偏移量。在我们的操作系统中,这个功能被多次使用。
19.4 进入IA32-e模式
硬件需要保持兼容性,因此,即使是64位的CPU,也要和以前一样,从实模式开始,先进入保护模式,再进入64位模式。
64位模式是个统称,其有两个子模式:兼容模式与IA32-e模式。兼容模式可在不回退到保护模式的前提下执行保护模式的代码,其也用于保护模式到IA32-e模式的过渡;IA32-e模式即为真正的64位模式。
想要进入IA32-e模式,就需要先进入保护模式,但无需打开二级分页模式。然后,通过以下步骤进入IA32-e模式:
- 安装四级分页模式所需的所有表,并将PML4的物理地址安装到
cr3 - 将
cr4的第5位置1,这一步用于打开PAE模式,从而将页表中的地址视为64位的 - 将
IA32_EFER的第8位置1,这一步用于打开IA32-e模式。这一步的实现细节将在下文中讨论 - 将
cr0的第31位置1,打开四级分页模式 - 跳转到64位代码段
请看本章代码19/Mbr.s:
第1~24行,进入保护模式。
第26~33行,将[0x100000, 0x200000)和[0x90000, 0x92000)这两段内存清零。这些内存的用途如下表所示:
| 地址 | 作用 |
|---|---|
[0x100000, 0x101000) |
PML4 |
[0x101000, 0x200000) |
内核地址空间的255个PDPT |
[0x90000, 0x91000) |
低端2M内存使用的页目录表 |
[0x91000, 0x92000) |
保留给后续章节使用的页目录表 |
第35行,安装第一个PML4E,其用于过渡到分页模式,不与其他任务共享。
第37~46行,安装内核地址空间的255个PML4E。内核地址空间平分了一半的虚拟地址,因此本应有256个PML4E,但最后一个PML4E指向PML4本身,因此不参与循环。预先安装255个PML4E的目的是共享内核,其原理与二级页表一致,这里不再赘述。
第48行,安装最后一个PML4E,其指向PML4本身。这样做的目的是为内存管理做准备,其原理与二级页表一致,这里不再赘述。
第49行,在内核地址空间的第一个PDPT中安装第一个PDPTE,其指向0x90000处的页目录表。
第50行,在0x90000处的页目录表中安装第一个PDE,其指向起始地址为0的2M大页。我们的操作系统只使用2M物理内存,刚好可以被一个2M大页覆盖。
第52~53行,将PML4的物理地址安装到cr3中。
第55~57行,将cr4的第5位置1,打开PAE模式。
第59~62行,将IA32_EFER的第8位置1,打开IA32-e模式。
IA32_EFER是一个型号特定寄存器(Model-Specific Register,MSR),这里的EFER即扩展功能启用寄存器(Extended Feature Enable Register)。型号特定指的是仅在部分型号的CPU上才有,例如IA32_EFER在不支持IA32-e模式的CPU上可能就是没有的。MSR有很多个,以至于难以对其进行命名。因此,诸如IA32_EFER这样的名字只是方便书面记录,不能用在代码中,代码中实际使用的是MSR的编号,并使用rdmsr/wrmsr指令对其进行读写。具体来说:
rdmsr/wrmsr固定使用ecx设定MSR的编号- 每个MSR都是64位的,
rdmsr/wrmsr固定使用edx:eax组合描述它 IA32_EFER的编号是0xc0000080
第64~66行,打开分页模式。
第68行,跳转到64位代码段。
第70行,将后续代码以64位模式编译。
第74行,重新加载GDTR。在实模式下,lgdt会读取6字节的内存,而在64位模式下,lgdt指令会读取10字节的内存,因此,重新加载GDTR可将GDT抬升到高地址。
第76行,将rsp抬升到高地址。
第78行,挂起CPU。
第80~87行,定义GDT。0号表项为空表项,这是GDT的要求;1~2号表项分别为保护模式下的0特权级代码段与数据段;3~4号表项分别为64位0特权级代码段与数据段;5~6号表项分别为64位3特权级数据段与代码段。4~6号表项在本章中未使用,保留给后续章节使用。细心的读者会发现:3~4号表项是先代码段,后数据段;但5~6号表项是先数据段,后代码段,这种别扭的写法是有意而为之的,将在后续章节中讨论。
第89~92行,定义GDTR。GDTR会被加载两次,第一次只使用前6字节,第二次则会使用完整的10字节。
第94~96行,填充MBR并设定MBR魔数。
19.5 编译与测试
请看本章代码19/Makefile。
第2行,使用dd命令创建一个虚拟硬盘,这比使用bximage命令更方便。
第3~4行,编译MBR,并将其写入虚拟硬盘的0号扇区。
启动bochs,可以观察到操作系统已经进入无限循环状态。
至此,我们已经进入IA32-e模式,接下来,就可以加载内核了。
一个操作系统的设计与实现——第19章 IA32-e模式的更多相关文章
- 设计模式之第19章-中介者模式(Java实现)
设计模式之第19章-中介者模式(Java实现) “测试妹纸找你,你的代码出问题了.”“美工妹纸让你看看界面怎么样.”身为程序员总要和各种人打交道,但是如果再分为前端.后端工程师的话,那么关系就会错综复 ...
- iOS编程Cookbook第19章最后一个例子不能正常工作的解决办法
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在Cookbook的第19章的11节中所要解决的是在App中显 ...
- Linux就这个范儿 第19章 团结就是力量 LSB是Linux标准化基地(Linux Standards Base)的简称
Linux就这个范儿 第19章 团结就是力量 LSB是Linux标准化基地(Linux Standards Base)的简称 这个图片好可爱,它是LSB组织的图标.你肯定会问:“图标这么设计一定有说 ...
- 【C#4.0图解教程】笔记(第19章~第25章)
第19章 泛型 1.泛型概念 泛型提供了一种更准确地使用有一种以上的类型的代码的方式. 泛型允许我们声明类型参数化的代码,我们可以用不同的类型进行实例化. 泛型不是类型,而是类型的模板. 2.声明 ...
- CHAPTER 19 Ordering the World 第19章 分类世界
CHAPTER 19 Ordering the World 第19章 分类世界 Our planet is home to a bewildering variety of plants and an ...
- 【Android】19.0 第19章 前面章节的代码优化及本章示例主界面
分类:C#.Android.VS2015: 创建日期:2016-03-05 一.简介 这一章我们介绍"共享存储和内容提供程序"的基本用法. 二.先优化一下前面章节例子的代码 在前面 ...
- linux及安全《Linux内核设计与实现》第一章——20135227黄晓妍
<linux内核设计与实现>第一章 第一章Linux内核简介: 1.3操作系统和内核简介 操作系统:系统包含了操作系统和所有运行在它之上的应用程序.操作系统是指整个在系统中负责完成最基本功 ...
- 【STM32H7教程】第19章 STM32H7的GPIO应用之按键FIFO
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第19章 STM32H7的GPIO应用之按键FIF ...
- 第19章 集合框架(3)-Map接口
第19章 集合框架(3)-Map接口 1.Map接口概述 Map是一种映射关系,那么什么是映射关系呢? 映射的数学解释 设A,B是两个非空集合,如果存在一个法则,使得对A中的每一个元素a,按法则f,在 ...
- 《TCP/IP详解卷1:协议》第19章 TCP的交互数据流-读书笔记
章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...
随机推荐
- 单芯片国产ARM+FPGA,复旦微FMQL20SM工业核心板正式发布!
- 量子位(qubit)发微
上一篇文章我们讲了量子计算机的一些概念,文章不短,但是信息量很少.这里继续深入量子机来揭开qubit的神秘面纱. 这篇文章会有一些数学概念,不过很简单 量子叠加 量子叠加非常重要,因为qubit就是利 ...
- LVGL一键打包图片工具,全部图片打包成一个bin文件,支持nor flash XIP模式下直接访问数据显示
最近做工程项目,需要用到LVGL,但是搜了很长时间没有看到合适的图片打包工具,大多都是生成数组或者单个的bin文件,这样烧录到nor flash很麻烦 后来看到一篇博客,博主的想法与我类似,不过他后面 ...
- vue项目坑记录:vue项目运行卡在百分之几几几
今天晚上打着游戏,同事突然叫我拉项目下来运行,我打完就去拉代码了,结果vue项目运行卡在66%不动了,我也是百度一下分享别人怎么解决的文章给他,继续我的游戏! 结果呢? 游戏结束后,我拉代码,还是这个 ...
- 推荐几款.NET开源且功能强大的实用工具,助你提高工作开发效率!
前言 俗话说得好"工欲善其事,必先利其器",今天大姚给大家推荐8款.NET开源且功能强大的实用工具,助你提高工作开发效率! DevToys 一款基于C#开源(MIT License ...
- ADB:移动端专项测试必备神器!!
01 Android调试桥 (adb) Android调试桥 (adb) 是一种功能多样的命令行工具,可让您与设备进行通信. adb命令可用于执行各种设备操作(例如安装和调试应用),并提供对Unix ...
- 一款基于Fluent设计风格、现代化的WPF UI控件库
前言 今天大姚给大家分享一款基于Fluent设计风格.开源(MIT License).现代化的WPF UI控件库,它提供直观的设计.主题.导航和全新的沉浸式控件,全部都是原生且无缝地集成在一起:WPF ...
- 如何在Linux云服务器上通过Docker Compose部署安装Halo,搭建个人博客网站?
目录 前置步骤 环境搭建 创建容器组 在系统任意位置创建一个文件夹 创建docker-compose.yaml 启动 Halo 服务 配置反向代理以及域名解析 Halo初始化页面. 更新新版本的hal ...
- 平衡树之Splay树详解
认识 Splay树,BST(二叉搜索树)的一种,整体效率很高,平摊操作次数为\(O(log_2n)\),也就是说,在一棵有n个节点的BST上做M次Splay操作,时间复杂度为\(O(Mlog_2n)\ ...
- 【Linux】Re01
一.三种网络模式 https://www.bilibili.com/video/BV1Sv411r7vd?p=7 1.桥接模式 该虚拟机和宿主机同一网段,和外部网络相通,但是占用网段地址资源,IP分配 ...