《Orange’S:一个操作系统的实现》第三章——保护模式
实验内容:认识保护模式,实现从实模式到保护模式的转换,GDT描述符;实现实模式大于1MB内存的寻址能力,并接着上一次实验,从保护模式返回到实模式,重新设置各个段寄存器的值;LDT描述符;学会使用挂载指令和运行程序。
3.1 认识保护模式
认识保护模式,实现从实模式到保护模式的转换,GDT描述符
实验步骤:
①根据书中汇编代码创建pmtest1.asm
文件并编译为pmtest1.bin
touch pmtest1.asm
# 这里省略编辑pmtest1.asm内容的操作
nasm pmtest1.asm -o pmtest1.bin
②复制第二章的软盘映像文件a.img
和配置文件bochsrc
!注意,若此处报错“No bootable device",参考附录解决办法
③使用dd
指令将pmtest1.bin
文件写入a.img
的引导扇区
dd if=pmtest1.bin of=a.img bs=512 count=1 conv=notrunc
④运行Bochs
出现红色字母P
至此,我们已经实现了从实模式到保护模式的转换
直观改变:
- 定义了一个叫GDT的数据结构
- 16位代码进行了一些与GDT有关的操作
- 最后程序跳转到32位代码进行了一些现存操作
上述问题将在下面详解
3.1.1 保护模式的运行环境
执行步骤:
①下载freedos.img
,将解压后的a.img
复制到目录,并重命名为freedos.img
②使用bximage
生成pm.img
③修改bochsrc配置文件,确保其中有以下三行:
floppya: 1_44=freedos.img, status=inserted
floppyb: 1_44=pm.img, status=insertedboot: a
④执行bochs -f bochsrc
启动Bochs,格式化B盘
⑤编译pmtest1.asm
为pmtest1.com
nasm pmtest1.asm -o pmtest1.com
⑥将pmtest1.com
复制到虚拟软盘pm.img
上
sudo mount -o loop pm.img /mnt/floppy
sudo cp pmtest1.com /mnt/floppy/
sudo umount /mnt/floppy
⑦到FreeDos中执行下述指令
b:
pmtest1.com
解释:更改配置文件bochsrc
之后,Bochs将从freedos.img
的引导扇区启动,并能够执行一系列DOS指令。上述操作为切换到B盘,执行pmtest1.com
文件
3.1.2 GDT
实模式和保护模式的内存管理机制不同,实模式下可以直接使用物理地址进行访问,而保护模式需要使用GDT和段描述符来进行管理和保护。
GDT是全局描述符表(Global Descriptor Table)的缩写,是在保护模式下使用的一种数据结构,用于描述内存段的属性和访问权限。每个内存段都由一个或多个GDT表项描述。
GDT表项是一个8字节的数据结构,包含了内存段的基地址、大小、访问权限、特权级别等信息。在GDT中,每个表项都有一个唯一的段选择器(segment selector)与之对应。使用GDT可以提供更为安全和可靠的内存管理,可以确保不同程序之间的内存空间相互隔离,防止程序访问非法内存,从而提高系统的稳定性和安全性。
3.1.3 实模式到保护模式
跳转步骤如下:
①准备GDT:初始化GDT表,将GDT表中的每个表项设置为合适的值,包括内存段的基地址、大小、访问权限、特权级别等信息。
②用lgdt
加载gdtr
:lgdt
指令的作用是将GDT表的起始地址和大小保存到gdtr
寄存器中的相应字段中,gdtr
包含了GDT表的起始地址和大小,以及一些其他的控制信息。
③打开A20
:实模式寻址能力为1MB,用不到第20个(从零开始)地址位,超出回滚,故实模式下A20
始终为0;进入保护模式后获得更大的寻址能力,因此需要打开A20
地址线。
④置cr0的PE位为1:打开开关
⑤跳转
3.2 保护模式进阶
3.2.1 实现大于1MB的内存寻址能力
上文提到,在保护模式之下寻址空间可以达到4GB,下面试验读写大地址内存(以5MB为例)。
一句话:实际上在GDT中增加一个表项即可,该描述符的段基址为0500000h
,段界限和属性等略
实验步骤:
①复制文章pmtest2.asm
代码,编译为pmtest2.com
②执行下述指令,将pmtest2.com
写入虚拟软盘pm.img
:
sudo mount -o loop pm.img /mnt/floppy
sudo cp pmtest2.com /mnt/floppy/
sudo umount /mnt/floppy
③执行bochs -f bochsrc
开启Bochs虚拟机,并在虚拟机中切换到B盘,执行pmtest2.com
,得到如下图所示结果:
3.2.2 LDT
在选择子(Selector)的高13位中,T1(Table Indicator)位表示GDT(全局描述符表)或LDT(局部描述符表)的标识符。当T1位为0时,选择子表示GDT表中的一个描述符;当T1位为1时,选择子表示LDT表中的一个描述符。
附录:Bug
1. No bootable device
问题描述
在3.1中,若新建一个a.img
软盘映像文件,然后将pmtest1.bin
写入软盘的第一个扇区,再运行Bochs时会产生如下错误
原因分析
根据上一篇博客内容【OS课设日志】《Orange‘S:一个操作系统的实现》Ch1/2
(如果是从软盘启动)计算机会自动检查0面0磁道1扇区(即第一个扇区),如果该扇区以0xAA55结束,则BIOS认为它是一个引导扇区。
我们观察第二章中.asm
文件最后两行代码
times 510 - ($ - $$)
dw 0xaa55
上述代码使a.img
已经被填充为512字节并且以0xaa55
结束,所以BISO就认为它是一个引导区,就去加载它。若第三章中新建文件,则该文件第一个扇区没有以0xaa55
结束,BIOS无法识别,因此出现No bootable device
错误
解决办法
按书中要求,复制第二章中的a.img
,重新写入pmtest1.bin
2. mount: /mnt/floppy: mount point does not exist.
问题描述
将pmtest1.com
复制到细腻软盘pm.img
上时需要执行下面指令:
sudo mount -o loop pm.img /mnt/floppy
sudo cp pmtest1.com /mnt/floppy/
sudo umount /mnt/floppy
执行第一条时报错
mount: /mnt/floppy: mount point does not exist.
错误原因
挂载点目录不存在:在执行mount
命令时,指定的挂载点目录可能尚未创建或已经被删除。需要确保挂载点目录存在,可以使用mkdir
命令创建挂载点目录。
解决办法
执行指令sudo mkdir /mnt/floppy
创建挂载点,而后运行不报错