第四章 处理器模式与硬件内存管理(x86_64) - 从零开始开发UEFI引导的64位操作系统内核

声明:此文章为本人在知乎首发的原创文章


与本文同时编写的内核项目现已开源至github


一、x86_64的处理器模式

x86架构处理器模式切换图在这里需要注意的是,实际上处理器处理位数和处理器模式没有关系,只不过在某个处理位数时,处理器被要求处于某个模式下,允许存在某个处理位数其他模式这种中间状态。
处理器在刚刚通电或执行重启操作后,会向自己发送一个Reset信号,收到Reset后,处理器被设置为实地址模式(简称实模式),处理位数被设为16位。在这个模式中,处理器只能访问物理地址的前1MB空间,通过段寄存器左移4位后与一个16位地址相加得到的20位地址访问。

1. 32位模式

开启A20地址线即可开启32位模式,A20地址线通过读、写0xee号io端口来开启、关闭;处理器还提供了A20快速门,即向0x92号io端口写入0x2来开启A20地址线。不开启保护模式的32位模式是不稳定的,处理器只能暂时处于32位实模式的状态,需要开启保护模式才能正常执行32位程序。

2. 保护模式

准备保护模式数据结构后将cr0寄存器的PE标志位置位即可开启。这个“保护模式数据结构”指的是GDT,全局描述符表,表中可以添加段描述符系统描述符。保护模式下的段寄存器通过访问段描述符确定所在的段,而不是左移4位后直接与地址相加;保护模式有许多硬件直接触发的保护功能,系统描述符用于支持这些功能的触发。此外,保护模式中引入了特权级0为最高的特权级,3为最低的特权级,越高的特权级,保护功能越弱,程序越容易控制处理器的状态。内核通常在0特权级运行,普通程序通常在3特权级运行。同时,在这个模式中也引入了分页机制(不是必须开启)。32位的基本分页机制使用一级页表进行寻址,能够映射4GB空间,开启PAE后,在原先的以及页表上增加了两级页表,通过类似树状的数据结构使得相同大小的最高级页表能够映射64PB的空间。PAE开启后使用36位物理地址,使得物理地址寻址能力提高到了64GB

3. 虚拟8086模式

这是一个模拟出来的16位实模式,置位eflags寄存器的VM标志位即可开启。在这个模式中,16位程序在一个切换到此模式前设置好的一个1MB大小的内存空间中运行。

3. IA-32e模式

实模式切换而来的32位保护模式被称为IA-32模式。由于64位模式是在IA-32模式基础上经过功能增强和修改得到的,所以被称为IA-32e模式。经过第二章中的一系列操作,即可开启。这些操作主要开启了这些功能:分页机制长模式地址扩展(LME)64位段描述符长模式地址扩展中为分页机制又增加了一级或两级页表,使用4级或5级页表映射地址空间。同时使用48位物理地址,进一步提高物理地址寻址能力。也因为48位物理地址称为长地址,IA-32e模式又称长模式。由于描述符表中支持32位段描述符64位段描述符同时存在,所以可以通过暂时关闭LME并修改段寄存器索引的段描述符,进入一种支持32位程序运行的IA-32e的子模式,称为兼容模式。虽然所谓的兼容模式只是IA-32e模式的一种支持32位程序运行的状态,但我们依然习惯地称IA-32e的支持64位程序运行的状态IA-32e的支持32位程序运行的状态IA-32e的两个子模式长模式兼容模式


二、各种不同的地址空间

1. 物理地址空间

物理地址空间中的物理地址直接索引内存中每个储存单元的地址。

2. 线性地址空间

分页机制的寻址方式
分页机制的寻址方式在4级页表寻址方式下,线性地址通过如图方式被映射成物理地址。所以由分页机制映射的地址空间就称为线性地址
注意,线性地址空间与物理地址空间并不一定一一对应(可以人为将一部分空间设置为一一对应的空间),且只有部分线性地址对应物理地址,因为线性地址空间能够映射的地址空间大小远大于人类目前制造出的内存大小。

3. 虚拟地址空间

分段机制的寻址方式
分段机制的寻址方式


三、平坦内存模型

这是在ia-32e模式中固定使用的分段模型。
平坦内存模型平坦内存模型规定,操作系统只使用一个段,这个段起始地址为线性地址0,无段限长(或者说段限长就是线性地址空间可以映射的地址的上限);但是对于代码段寄存器和其它段寄存器依然使用两个段描述符,两个段描述符的主要区别是代码段只有执行权限,其它段寄存器作为数据段,段描述符只有读写权限。
分页机制出现后,分段机制逐渐显得复杂且混乱,并且分段机制在硬件电路上还有比较大的功耗,但是在ia-32模式中处理器仍然完全支持这种内存管理机制。英特尔和amd也意识到了这个问题,于是在新的ia-32e模式中,采取了平坦内存模型这个方案,使得分段机制的硬件电路大幅缩小,并且内核开发者也能够在恰当设置分段机制后直接忽略它的存在,只考虑分页机制即可。
因此在ia-32e模式中,虚拟地址等价于线性地址,一般称为线性地址。


四、cannonical型地址

cannonical型地址是线性地址的格式规范,IA-32e模式中规定应使用这种地址。
由于线性地址在4级页表和5级页表分页中均没有达到64位,因此剩余的位有严格规定。
英特尔白皮书的原文这样描述cannonical型地址:

在64位模式中,一个从最高有效位到第63位均被设置为0或1的地址被认为是cannonical型的。

对于4级分页的线性地址,一个符合此描述的地址应该处于以下范围:0x0000_0000_0000_0000~0x0000_7fff_ffff_ffff0xffff_8000_0000_0000~0xffff_ffff_ffff_ffff,根据前文,一个4级分页的线性地址最高有效就是47位,因此47到63位应该总是1或0。
这些位为0的地址空间称为低地址,为1的地址空间称为高地址。


五、分页机制

这里我们只讨论4级分页。
简单来说,cr3寄存器储存着PML4(即第4级页表)的首地址;但是实际上其中有些标志位,但是都被设为0:
英特尔白皮书卷3,4.5,表4-12
英特尔白皮书卷3,4.5,表4-12其中地址部分使用4KB对齐,这样可以直接将低12位的标志位清零作为PML4的地址而无需使用位移运算。
PML4以及下一级、下两级等等的页表都有512项,每项8字节,共占用4KB,刚好是一个页的大小。在线性地址中需要9个bit来索引一个页表项。
英特尔白皮书卷3,4.5,图4-11
英特尔白皮书卷3,4.5,图4-11以下是上图各标志位的含义:

  • R/W:置为1时读写权限为读写,为0时读写权限为只读。
  • U/S:置为1时在用户态或内核态访问,为0时只能在内核态访问。
  • A:“访问过”,只有在CPU运行时,使用这个页表项寻址后这个位会置为1。
  • D:“脏页”,在此页写入过之后会置为1。
  • G:“全局页”,此页被置为1时,tlb不会清除此页的映射缓存。
  • Ignored/Ign.:忽略,意为这些位无论是什么都不会造成影响。
  • Reserved/Rsvd.:保留,意为这些位只能为0。

tlb: 会暂时存储线性地址的映射,用来加快分页地址转换的速度的硬件电路。写cr3寄存器会清除tlb中索引它的页表项中G标志位为0的所有地址。

页表的每一个表项都是上图所示的表项的一种,每个表项都类似指针,指向下一级页表或物理页,形成树状结构。

根据cannonical型地址的定义,对于PML4来说,前256项映射的内存空间对应着低地址,后256项映射的内存空间对应着高地址

我们可以用cannonical型地址的高地址和地址来划分内核态和用户态的内存空间;linux内核使用高地址作为内核空间,低地址作为用户空间;本人写的内核用低地址作为内核空间。

地址空间的使用没有任何硬性规定,我的内核使用低地址作为内核空间只是因为链接内核镜像以及切换处理器模式比较方便。


六、内核态与用户态

内核态即处理器正在执行内核代码的状态,用户态即处理器正在执行用户进程的代码的状态。


与本文同时编写的内核项目现已开源至github

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

指向BIOS的野指针

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值