文章目录
- 前言
- 前置知识
- 代码说明
- 实验操作
前言
本博客记录《操作系统真象还原》第四章实验操作~
实验环境:ubuntu18.04+VMware , Bochs下载安装
实验内容:实现从MBR到LOADER,由LOADER实现进入保护模式
实验原理:计算机通电开机后,CPU的cs:ip寄存器,被硬件强制初始化为0xF000:0XFFF0 ,该位置存储着跳转指令,跳转向BIOS。这样首先运行BIOS软件(计算机系统的控制权 [CPU的使用权] 交接的第一棒就是BIOS啦!),BIOS会检查各种设备的情况,并且建立中断向量表。然后MBR找机会想把处理器使用权交出去。下一个接棒选手就是 主引导记录(MBR,Master Boot Record),BIOS知道MBR在0盘0道1扇区,因此它会将0盘0道1扇区中的MBR引导程序加载到物理地址0x7c00,然后继而跳去执行。这样BIOS就将处理器的使用权交给MBR。紧接着,MBR的接力棒就来到了Loader,Loader构建并且初始化GDT,然后用LGDT指令把GDT表的位置放了进去,并且初始化了三个段描述符(段描述符 代码段 数据段) 。从此,从16位实模式到了32位保护模式。
前置知识
前置知识可以食用 全局描述符表
代码说明
include/boot.inc
更新boot.inc文件:关于加载器的配置信息
;------------- loader和kernel ----------
LOADER_BASE_ADDR equ 0x900
LOADER_START_SECTOR equ 0x2
;-------------- gdt描述符属性 -------------
DESC_G_4K equ 1_00000000000000000000000b ;描述符中G的位次,其中结尾的b表示2机制。
DESC_D_32 equ 1_0000000000000000000000b
DESC_L equ 0_000000000000000000000b ; 64位代码标记,此处标记为0便可。
DESC_AVL equ 0_00000000000000000000b ; cpu不用此位,暂置为0
DESC_LIMIT_CODE2 equ 1111_0000000000000000b
DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2
DESC_LIMIT_VIDEO2 equ 0000_000000000000000b
DESC_P equ 1_000000000000000b
DESC_DPL_0 equ 00_0000000000000b
DESC_DPL_1 equ 01_0000000000000b
DESC_DPL_2 equ 10_0000000000000b
DESC_DPL_3 equ 11_0000000000000b
DESC_S_CODE equ 1_000000000000b
DESC_S_DATA equ DESC_S_CODE
DESC_S_sys equ 0_000000000000b
DESC_TYPE_CODE equ 1000_00000000b ;x=1,c=0,r=0,a=0 代码段是可执行的,非依从的,不可读的,已访问位a清0.
DESC_TYPE_DATA equ 0010_00000000b ;x=0,e=0,w=1,a=0 数据段是不可执行的,向上扩展的,可写的,已访问位a清0.
DESC_CODE_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_CODE2 + DESC_P + DESC_DPL_0 + DESC_S_CODE + DESC_TYPE_CODE + 0x00
DESC_DATA_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_DATA2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x00
DESC_VIDEO_HIGH4 equ (0x00 << 24) + DESC_G_4K + DESC_D_32 + DESC_L + DESC_AVL + DESC_LIMIT_VIDEO2 + DESC_P + DESC_DPL_0 + DESC_S_DATA + DESC_TYPE_DATA + 0x0b
;-------------- 选择子属性 ---------------
RPL0 equ 00b
RPL1 equ 01b
RPL2 equ 10b
RPL3 equ 11b
TI_GDT equ 000b
TI_LDT equ 100b
代码说明
第 6 ~ 27 行是定义段描述符的属性。
第 29 ~ 35 行是定义选择子属性。
loader.S
%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR
LOADER_STACK_TOP equ LOADER_BASE_ADDR
jmp loader_start ; 此处的物理地址是:
;构建gdt及其内部的描述符
GDT_BASE: dd 0x00000000
dd 0x00000000
CODE_DESC: dd 0x0000FFFF
dd DESC_CODE_HIGH4
DATA_STACK_DESC: dd 0x0000FFFF
dd DESC_DATA_HIGH4
VIDEO_DESC: dd 0x80000007 ;limit=(0xbffff-0xb8000)/4k=0x7
dd DESC_VIDEO_HIGH4 ; 此时dpl已改为0
GDT_SIZE equ $ - GDT_BASE
GDT_LIMIT equ GDT_SIZE - 1
times 60 dq 0 ; 此处预留60个描述符的slot
SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0 ; 相当于(CODE_DESC - GDT_BASE)/8 + TI_GDT + RPL0
SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0 ; 同上
SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0 ; 同上
;以下是定义gdt的指针,前2字节是gdt界限,后4字节是gdt起始地址
gdt_ptr dw GDT_LIMIT
dd GDT_BASE
loadermsg db '2 loader in real.'
loader_start:
;打印字符,"2 LOADER"说明loader已经成功加载
; 输出背景色绿色,前景色红色,并且跳动的字符串"1 MBR"
mov byte [gs:160],'2'
mov byte [gs:161],0xA4 ; A表示绿色背景闪烁,4表示前景色为红色
mov byte [gs:162],' '
mov byte [gs:163],0xA4
mov byte [gs:164],'L'
mov byte [gs:165],0xA4
mov byte [gs:166],'O'
mov byte [gs:167],0xA4
mov byte [gs:168],'A'
mov byte [gs:169],0xA4
mov byte [gs:170],'D'
mov byte [gs:171],0xA4
mov byte [gs:172],'E'
mov byte [gs:173],0xA4
mov byte [gs:174],'R'
mov byte [gs:175],0xA4
;------------------------------------------------------------
;INT 0x10 功能号:0x13 功能描述:打印字符串
;------------------------------------------------------------
;输入:
;AH 子功能号=13H
;BH = 页码
;BL = 属性(若AL=00H或01H)
;CX=字符串长度
;(DH、DL)=坐标(行、列)
;ES:BP=字符串地址
;AL=显示输出方式
; 0——字符串中只含显示字符,其显示属性在BL中。显示后,光标位置不变
; 1——字符串中只含显示字符,其显示属性在BL中。显示后,光标位置改变
; 2——字符串中含显示字符和显示属性。显示后,光标位置不变
; 3——字符串中含显示字符和显示属性。显示后,光标位置改变
;无返回值
mov sp, LOADER_BASE_ADDR
mov bp, loadermsg ; ES:BP = 字符串地址
mov cx, 17 ; CX = 字符串长度
mov ax, 0x1301 ; AH = 13, AL = 01h
mov bx, 0x001f ; 页号为0(BH = 0) 蓝底粉红字(BL = 1fh)
mov dx, 0x1800 ;
int 0x10 ; 10h 号中断
;---------------------------------------- 准备进入保护模式 ------------------------------------------
;1 打开A20
;2 加载gdt
;3 将cr0的pe位置1
;----------------- 打开A20 ----------------
in al,0x92
or al,0000_0010B
out 0x92,al
;----------------- 加载GDT ----------------
lgdt [gdt_ptr]
;----------------- cr0第0位置1 ----------------
mov eax, cr0
or eax, 0x00000001
mov cr0, eax
;jmp dword SELECTOR_CODE:p_mode_start ; 刷新流水线,避免分支预测的影响,这种cpu优化策略,最怕jmp跳转,
jmp SELECTOR_CODE:p_mode_start ; 刷新流水线,避免分支预测的影响,这种cpu优化策略,最怕jmp跳转,
; 这将导致之前做的预测失效,从而起到了刷新的作用。
[bits 32]
p_mode_start:
mov ax, SELECTOR_DATA
mov ds, ax
mov es, ax
mov ss, ax
mov esp,LOADER_STACK_TOP
mov ax, SELECTOR_VIDEO
mov gs, ax
mov byte [gs:320], 'P'
jmp $
【这部分详细解读请看原书】
mbr.S
/boot/mbr.S
由于 loader.bin 超过了 512 字节,所以我们要把 mbr.S 中加载 loader.bin 的读入扇区数增大
实验操作
创建相应文件
(base) user@ubuntu:/home/cooiboi/bochs/include$ sudo vim boot.inc
(base) user@ubuntu:/home/cooiboi/bochs/boot$ sudo vim mbr.S
(base) user@ubuntu:/home/cooiboi/bochs/boot$ sudo vim loader.S
编译mbr.S和loader.S
sudo nasm -I include/ -o boot/mbr.bin boot/mbr.S
sudo nasm -I include/ -o boot/loader.bin boot/loader.S
(base) user@ubuntu:/home/cooiboi/bochs$ sudo nasm -I include/ -o boot/mbr.bin boot/mbr.S
(base) user@ubuntu:/home/cooiboi/bochs$ sudo nasm -I include/ -o boot/loader.bin boot/loader.S
将mbr和load分别写入磁盘中
sudo dd if=/home/cooiboi/bochs/boot/mbr.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=1 conv=notrunc
sudo dd if=/home/cooiboi/bochs/boot/loader.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=2 seek=2 conv=notrunc
(base) user@ubuntu:/home/cooiboi/bochs/boot$ sudo dd if=/home/cooiboi/bochs/boot/mbr.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 0.000242967 s, 2.1 MB/s
(base) user@ubuntu:/home/cooiboi/bochs/boot$ sudo dd if=/home/cooiboi/bochs/boot/loader.bin of=/home/cooiboi/bochs/boot/hd60M.img bs=512 count=2 seek=2 conv=notrunc
1+1 records in
1+1 records out
711 bytes copied, 0.000136065 s, 5.2 MB/s
启动Bochs
(base) user@ubuntu:/home/cooiboi/bochs$ sudo bin/bochs -f boot/bochsrc.disk
输出结果如下,左下角的字符串“2 loader in real”是在实模式下用 BIOS 中断 0x10 打印的。左上角第 3行的字符’P’,这是咱们在保护模式下输出的。一个程序历经两种模式,各模式下都打印了字符,为了区别实模式下的打印,所以字符串中含有“ inreal ” 。
这篇的文件目录与之前的博客再次改进MBR(从磁盘读入Loader加载器)一致。
参考资料
- 《操作系统真象还原》
- 《操作系统真象还原》第四章 ---- 剑指Loader 刃刺GDT 开启新纪元保护模式 解放32位