计算机系统结构与操作系统实验三(3)-进入保护模式

📍实验要求

从实模式到保护模式的转变:
在刚进入loader尚在实模式下时,在第2行显示:real-Zhangsan
在变为保护模式后,在第3行显示:protect-Zhangsan
加载gdt、将cr0的PE位置为1

📍实验过程

老规矩,我还是新建一个项目文件,并创建相应文件夹和文件
在这里插入图片描述

📍📍mbr.S

加载loader.bin的函数call rd_disk_m_16的扇区数增加为4个
在这里插入图片描述
根据中断打印原来的内容"1 MBR"
在这里插入图片描述
mbr.S👇

;主引导程序 
;------------------------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00         
   mov ax,cs      
   mov ds,ax
   mov es,ax
   mov ss,ax
   mov fs,ax
   mov sp,0x7c00
   mov ax,0xb800
   mov gs,ax

; 清屏
;利用0x06号功能,上卷全部行,则可清屏。
; -----------------------------------------------------------
;INT 0x10   功能号:0x06	   功能描述:上卷窗口
;------------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值:
   mov     ax, 0600h
   mov     bx, 0700h
   mov     cx, 0                   ; 左上角: (0, 0)
   mov     dx, 184fh		   ; 右下角: (80,25),
				   ; 因为VGA文本模式中,一行只能容纳80个字符,25行。
				   ; 下标从0开始,所以0x18=24,0x4f=79
   int     10h                     ; int 10h

   ; 输出字符串:MBR
   mov byte [gs:0x00],'1'
   mov byte [gs:0x01],0xA4

   mov byte [gs:0x02],' '
   mov byte [gs:0x03],0xA4

   mov byte [gs:0x04],'M'
   mov byte [gs:0x05],0xA4	   ;A表示绿色背景闪烁,4表示前景色为红色

   mov byte [gs:0x06],'B'
   mov byte [gs:0x07],0xA4

   mov byte [gs:0x08],'R'
   mov byte [gs:0x09],0xA4
	 
   mov eax,LOADER_START_SECTOR	 ; 起始扇区lba地址
   mov bx,LOADER_BASE_ADDR       ; 写入的地址
   mov cx,4			 ; 待读入的扇区数
   call rd_disk_m_16		 ; 以下读取程序的起始部分(一个扇区)
  
   jmp LOADER_BASE_ADDR
       
;-------------------------------------------------------------------------------
;功能:读取硬盘n个扇区
rd_disk_m_16:	   
;-------------------------------------------------------------------------------
				       ; eax=LBA扇区号
				       ; ebx=将数据写入的内存地址
				       ; ecx=读入的扇区数
      mov esi,eax	  ;备份eax
      mov di,cx		  ;备份cx
;读写硬盘:
;1步:设置要读取的扇区数
      mov dx,0x1f2
      mov al,cl
      out dx,al            ;读取的扇区数

      mov eax,esi	   ;恢复ax

;2步:将LBA地址存入0x1f3 ~ 0x1f6

      ;LBA地址7~0位写入端口0x1f3
      mov dx,0x1f3                       
      out dx,al                          

      ;LBA地址15~8位写入端口0x1f4
      mov cl,8
      shr eax,cl
      mov dx,0x1f4
      out dx,al

      ;LBA地址23~16位写入端口0x1f5
      shr eax,cl
      mov dx,0x1f5
      out dx,al

      shr eax,cl
      and al,0x0f	   ;lba第24~27or al,0xe0	   ; 设置74位为1110,表示lba模式
      mov dx,0x1f6
      out dx,al

;3步:向0x1f7端口写入读命令,0x20 
      mov dx,0x1f7
      mov al,0x20                        
      out dx,al

;4步:检测硬盘状态
  .not_ready:
      ;同一端口,写时表示写入命令字,读时表示读入硬盘状态
      nop
      in al,dx
      and al,0x88	   ;4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙
      cmp al,0x08
      jnz .not_ready	   ;若未准备好,继续等。

;5步:从0x1f0端口读数据
      mov ax, di
      mov dx, 256
      mul dx
      mov cx, ax	   ; di为要读取的扇区数,一个扇区有512字节,每次读入一个字,
			   ; 共需di*512/2次,所以di*256
      mov dx, 0x1f0
  .go_on_read:
      in ax,dx
      mov [bx],ax
      add bx,2		  
      loop .go_on_read
      ret

   times 510-($-$$) db 0
   db 0x55,0xaa

📍📍include/boot.inc

boot.inc

;-------------	 loader和kernel   ----------

LOADER_BASE_ADDR equ 0x900 
LOADER_START_SECTOR equ 0x2

;--------------   gdt描述符属性  -------------
DESC_G_4K   equ	  1_00000000000000000000000b   
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

📍📍loader.S

  1. 实模式输出real-luohaojia
    在这里插入图片描述
  2. 设置好在屏幕上输出的位置 和 字符串长度(长度要刚刚好,是多长就多长,比如我这里real-luohaojia就是14个字符)
    在这里插入图片描述
  3. 变为保护模式后,设置输出:protect-luohaojia
    在这里插入图片描述
    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 个描述符的空位 
 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 'real-luohaojia' 

loader_start: 

;------------------------------------------------------------ 
;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, 15 ; CX = 字符串长度 
 mov ax, 0x1301 ; AH = 13, AL = 01h 
 mov bx, 0x001f ; 页号为 0(BH = 0) 蓝底粉红字(BL = 1fh) 
 mov dx, 0x0100 ; ***字符开始位置****
 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 ; 刷新流水线

 [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' 
  mov byte [gs:321],0xB6  ; A==Green B==blue 4==red 6==orange
  mov byte [gs:322], 'r'  
  mov byte [gs:323],0xB6
  mov byte [gs:324], 'o'
  mov byte [gs:325],0xB6
  mov byte [gs:326], 't'
  mov byte [gs:327],0xB6
  mov byte [gs:328], 'e'
  mov byte [gs:329],0xB6 
  mov byte [gs:330], 'c' 
  mov byte [gs:331],0xB6
  mov byte [gs:332], 't'
  mov byte [gs:333],0xB6 
  mov byte [gs:334], '-'
  mov byte [gs:335],0xB6 
  mov byte [gs:336], 'l'
  mov byte [gs:337],0xB6 
  mov byte [gs:338], 'u'
  mov byte [gs:339],0xB6 
  mov byte [gs:340], 'o'
  mov byte [gs:341],0xB6 
  mov byte [gs:342], 'h'
  mov byte [gs:343],0xB6 
  mov byte [gs:344], 'a'
  mov byte [gs:345],0xB6 
  mov byte [gs:346], 'o'
  mov byte [gs:347],0xB6 
  mov byte [gs:348], 'j'
  mov byte [gs:349],0xB6 
  mov byte [gs:350], 'i'
  mov byte [gs:351],0xB6
  mov byte [gs:352], 'a'
  mov byte [gs:353],0xB6 

  jmp $ 

📍📍makefile

写入磁盘,从第2块开始,共4块
在这里插入图片描述
makefile

.PHONY:build burn

mbr_source=boot/mbr.S
mbr_target=boot/mbr.bin
loader_source=boot/loader.S
loader_target=boot/loader.bin
hard_disk=/home/lhj/Public/bochs/bin/hd60M.img

build:
		nasm -I boot/include/ -o $(mbr_target) $(mbr_source)
		nasm -I boot/include/ -o $(loader_target) $(loader_source)
burn:
		dd if=$(mbr_target) of=$(hard_disk) bs=512 count=1 conv=notrunc
		dd if=$(loader_target) of=$(hard_disk) bs=512 count=2 seek=2 conv=notrunc

📍📍run.sh

这里记得改为本实验代码目录
在这里插入图片描述

📍一键运行

在这里插入图片描述
在这里插入图片描述

📍查看gdt表和验证PE是否为1

在这里插入图片描述
本实验所有源码👉👉👉计算机系统结构与操作系统实验三bochs源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值