Skip to content

课设

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. 方式之一:

    ; 打开地址线A20
    in  al, 92h
    or  al, 00000010b
    out 92h, al

寄存器 cr0 的第 0 位是 PE 位,此位为 0 时,CPU 运行于实模式,为 1 时,CPU 运行于保护模式:

    ; 准备切换到保护模式
    mov eax, cr0
    or  eax, 1
    mov cr0, eax

使用 jmp 将代码段 Selector 加载到 cs 真正跳转到 32 位代码段:

    ; 真正进入保护模式
    jmp dword SelectorCode32:0  ; 执行这一句会把 SelectorCode32 装入 cs,
                    ; 并跳转到 Code32Selector:0  处

jmp 指令放在16位的段中,目标地址却是32位的,NASM 中需要在 offset 前加入 dword 将其编译为 32 位指令。

进入保护模式的主要步骤:

  1. 准备 GDT
  2. 用 lgdt 加载 gdtr
  3. 打开 A20
  4. 置 cr0 的 PE 位
  5. 跳转,进入保护模式

数据段:可以被更高特权级的代码访问到,而不需要使用特定的门。

保护模式进阶

不能从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)