操作系统真象还原:第四章 保护模式入门

1、mbr主引导程序代码

其中mbr程序中,需要将读取内核加载器代码的地方修改一下,因为我们的loader已经超过一个扇区了,mov cx,4        call rd_disk_m_16

;主引导程序
;-------------------------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00
	mov ax,cs	
	mov ss,ax
	mov es,ax
	mov ss,ax
	mov fs,ax
	mov sp,0x7c00
	mov ax,0xb800
	mov gs,ax	
 ;利用0x06号功能,上卷全部行,则可清屏
	mov ax,0x0600
	mov bx,0x0700	;BH是设置缺省属性,属性是指背景色,前景色,是否闪烁等,例如07H表示黑底白字,70H表示灰底黑字等等。
	mov cx,0x0000
	mov dx,0x184f	
	int 0x10

	;输出背景绿色,前景色红色,并且跳动的字符串"1 MBR"
	mov byte [gs:0x00],'1'	
	mov byte [gs:0x01],0xA4	;A表示绿色背景闪烁1010 0100b
	
	mov byte [gs:0x02],' '	
	mov byte [gs:0x03],0xA4
		
	mov byte [gs:0x04],'M'	
	mov byte [gs:0x05],0xA4

	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
	mov bx,LOADER_BASE_ADDR
	mov cx,4
	call rd_disk_m_16
	
	jmp LOADER_BASE_ADDR
;--------------------------------------------------
;功能为读取硬盘n个扇区
rd_disk_m_16:
;--------------------------------------------------
	mov esi,eax
	mov di,cx
	;设置要读取的扇区数
	mov dx,0x1f2
	mov al,cl
	out dx,al

	mov eax,esi

	;将LBA地址存入0x1f3-0x1f6
	;LBA地址7-0位
	mov dx,0x1f3
	out dx,al
	;LBA地址15-8位
	mov cl,8
	shr eax,cl
	mov dx,0x1f4
	out dx,al
	;LBA地址23-16位
	shr eax,cl
	mov dx,0x1f5
	out dx,al
	;LBA地址24-27位
	shr eax,cl
	and al,0x0f
	or al,0xe0	;设置7-4位为1110,表示lba模式
	mov dx,0x1f6
	out dx,al

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

.not_ready:
	nop
	in al,dx
	and al,0x88

	cmp al,0x08
	jnz .not_ready

	;读数据
	mov ax,di
	mov dx,256
	mul dx
	mov cx,ax	;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

 2、内核加载器代码

%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
			dd	DESC_VIDEO_HIGH4
			
GDT_SIZE equ $ - GDT_BASE	
GDT_LIMIT equ GDT_SIZE - 1
times 60 dq 0

SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0
SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0
SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0

gdt_ptr dw GDT_LIMIT
		dd GDT_BASE
loadermsg db '2 loader in real.'

loader_start:
	;int 0x10 功能号 0x13 打印字符串
	mov sp,LOADER_BASE_ADDR
	mov bp,loadermsg	;es:bp 字符串地址 
	mov cx,17	;字符串长度 
	mov ax,0x1301	;ah=13h,al=01h
	mov bx,0x001f	;bh=0页号bl=1fh蓝底粉红字 
	mov dx,0x1800
	int 0x10 
	
;-------------------------准备进入保护模式-----------------------
;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:160],'P'
	
	jmp $ 


3、 加载器和将来内核需要的配置项

主要是段描述符定义和段选择子的定义

注意:DESC_VIDEO_HIGH4,关于书中显存段的定义中有误,高四字节中的最后一字节是显存段的段基址的23~16位,我们显存段目前使用:0xb8000-0xbffff,段界限limit=(0xbffff-0xb8000)/4k=7,也即低四字节为0x80000007,高四字节中的最后一字节段基址是0xb8000-0x8000=0xb

;--------------------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
DESC_AVL  equ    0_00000000000000000000b
				  
DESC_LIMIT_CODE2 equ 1111_0000000000000000b
DESC_LIMIT_DATA2 equ DESC_LIMIT_CODE2
DESC_LIMIT_VIDEO2 equ 0000_0000000000000000b

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
DESC_TYPE_DATA equ 0010_00000000b

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

 4、调试运行

nasm -I include/ -o mbr.bin mbr.S
dd if=./mbr.bin of=/*/*/bochs/hd60M.img bs=512 count=1 conv=notrunc

nasm -I include/ -o loader.bin loader.S
dd if=./loader.bin of=/*/*/bochs/hd60M.img bs=512 count=4 seek=2 conv=notrunc

进行到指令lgdt后,通过info gdt,观察gdt表加载的情况看是否和定义一致

进入保护模式后,通过creg指令,观察cr0控制寄存器的pe位是否置1(若为大写PE,则表示为1,开启保护模式)

控制台按c键,继续执行,观察显存的输出

 

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值