进入保护模式

前言

本博客记录《操作系统真象还原》第四章实验操作~

实验环境: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加载器)一致。

参考资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值