课设
bochsrc.txt:
# how much memory the emulated machine will have
megs: 32
# filename of ROM images
romimage: file=/usr/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/share/vgabios/vgabios.bin
# what disk images will be used
floppya: 1_44=freedos.img, status=inserted
floppya: 1_44=pm.img, status=inserted
# choose the boot disk
boot: a
# where do we send log messages?
# log: bochsout.txt
# disable the mouse
mouse: enabled=0
# enable key mapping, using US layout as default.
keyboard: keymap=/usr/share/bochs/keymaps/x11-pc-us.map
使用 DOS 执行:
首先 bochs -f bochsrc.txt 执行并输入 format b: 格式化。
sudo mount -o loop pm.img /mnt/floppy
sudo cp task1.com /mnt/floppy/
sudo cp taskx.com /mnt/floppy/
sudo umount /mnt/floppy
再进入 FreeDos 执行 B:\taskx.com.
认识保护模式¶
实模式:物理地址(Physical Address)=段值(Segment)×16+偏移(Offset)
Descriptor 是 Global Description Table 中的表项

- P位存在(Present)位。P=1表示段在内存中存在;P=0表示段在内存中不存在。
- DPL描述符特权级(Descriptor Privilege Level)。特权级可以是0、1、2或者3。数字越小特权级越大。
- S位指明描述符是数据段/代码段描述符(S=1)还是系统段/门描述符(S=0)。
- TYPE描述符类型。
- G位段界限粒度(Granularity)位。G=0时段界限粒度为字节;G=1时段界限粒度为4KB。
- D/B位这一位比较复杂,分三种情况。
- 在可执行代码段描述符中,这一位叫做D位。D=1时,在默认情况下指令使用32位地址及32位或8位操作数;D=0时,在默认情况下使用16位地址及16位或8位操作数。
- 在向下扩展数据段的描述符中,这一位叫做B位。B=1时,段的上部界限为4GB;B=0时,段的上部界限为64KB。
- 在描述堆栈段(由ss寄存器指向的段)的描述符中,这一位叫做B位。B=1时,隐式的堆栈访问指令(如push、pop和call)使用32位堆栈指针寄存器esp;D=0时,隐式的堆栈访问指令(如push、pop和call)使用16位堆栈指针寄存器sp。
- AVL位保留位,可以被系统软件使用。


- TI = 1: 系统将从当前LDT中寻找相应描述符。

保护模式中断处理机制与实模式不同,准备进入保护模式时需要关中断。
为了兼容只有 20 根地址线的 8086,需要打开 A20 地址线,否则第 20 个地址位将恒为 0. 方式之一:

寄存器 cr0 的第 0 位是 PE 位,此位为 0 时,CPU 运行于实模式,为 1 时,CPU 运行于保护模式:
使用 jmp 将代码段 Selector 加载到 cs 真正跳转到 32 位代码段:
该 jmp 指令放在16位的段中,目标地址却是32位的,NASM 中需要在 offset 前加入 dword 将其编译为 32 位指令。
进入保护模式的主要步骤:
- 准备 GDT
- 用 lgdt 加载 gdtr
- 打开 A20
- 置 cr0 的 PE 位
- 跳转,进入保护模式
数据段:可以被更高特权级的代码访问到,而不需要使用特定的门。

保护模式进阶¶
不能从32位代码段返回实模式,只能从16位代码段中返回。这是因为无法实现从32位代码段返回时cs高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)。方案:新增一个Normal描述符,在返回实模式之前把对应选择子SelectorNormal加载到ds、es和ss.
mov [LABEL_GO_BACK_TO_REAL+3], ax 的作用就是为回到实模式的这个跳转指令指定正确的段地址:LABEL_GO_BACK_TO_REAL+3恰好就是Segment的地址,jmp 0:LABEL_REAL_ENTRY 实际上是 jmp cs_real_mode:LABEL_REAL_ENTRY.


数字越大表示的特权级越小,所以有时为避免混淆,也将高特权级称做内层,而把低特权级称做外层。
- CPL: 当前执行的程序或任务的特权级
- cs和ss的第0位和第1位上
- 等于代码所在的段的特权级。转移到不同特权级的代码段时,处理器将改变CPL。
- 一致代码段: CPL不会被改变
- DPL: 段或者门的特权级
- 段描述符或者门描述符的DPL字段
- 代码段访问段 / 门时:
- 数据段:CPL <= DPL
- 非一致代码段(不使用门):CPL = DPL
- 调用门:CPL <= DPL
- 一致代码段和通过调用门访问的非一致代码段:CPL >= DPL
- TSS: CPL <= DPL
- RPL: 处理器通过检查RPL和CPL来确认一个访问请求是否合法
- 段选择子的第0位和第1位
- CPL 和 RPL 都与 DPL 比较,都需要满足相同要求
- 访问操作系统过程时,会把选择子的 RPL 设成调用者的特权级 CPL 而不是操作系统过程的特权级

门描述符分为4种:
- 调用门(Call gates)
- 中断门(Interrupt gates)
- 陷阱门(Trap gates)
- 任务门(Task gates)






