《30天自制操作系统》第三课学习笔记

今天作者写了一个真正载入内存的IPL,用来讲磁盘上的数据载入内存当中
载入的程序节选是

		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0			; 柱面0
		MOV		DH,0		    ; 磁头0
		MOV		CL,2			; 扇区2
readloop:
		MOV		SI,0			; 记录失败次数寄存器
retry:
		MOV		AH,0x02			; AH=0x02 : 读入磁盘
		MOV		AL,1			; 1个扇区
		MOV		BX,0
		MOV		DL,0x00			; A驱动器
		INT		0x13			; 调用磁盘BIOS
		JNC		next			; 没出错则跳转到fin
		ADD		SI,1			; 往SI加1
		CMP		SI,5			; 比较SI与5
		JAE		error			; SI >= 5 跳转到error
		MOV		AH,0x00
		MOV		DL,0x00			; A驱动器
		INT		0x13			; 重置驱动器
		JMP		retry
next:
		MOV		AX,ES			; 把内存地址后移0x200512/16十六进制转换)
		ADD		AX,0x0020
		MOV		ES,AX			; ADD ES,0x020因为没有ADD ES,只能通过AX进行
		ADD		CL,1			; 往CL里面加1
		CMP		CL,18			; 比较CL与18
		JBE		readloop		; CL <= 18 跳转到readloop
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readloop		; DH < 2 跳转到readloop
		MOV		DH,0
		ADD		CH,1
		CMP		CH,CYLS
		JB		readloop		; CH < CYLS 跳转到readloop

; 读取完毕,跳转到haribote.sys执行!
		MOV		[0x0ff0],CH		;
		JMP		0xc200

这段程序就就通过读取磁盘上的文件,载入到0x8200往后的地址上面,最后跳转掉0xC200去执行。
上面虽然写的是0x820,这个数据是存在段寄存器上面的,在进行解析的时候是要默认*16,也就是0x8200。在书中有提到要将程序载入到内存0x8000哪里去,但现在的程序确实0x8200,开始满懵逼的,原来仔细看程序它是从第二个扇区开始读取数据,所以地址要写0x8200。如果上面是从第一个扇区读取数据的话,也就是语句MOV CL,2 ; 扇区2改成
MOV CL,1 ; 扇区1,那么MOV AX,0x0820就要改成0x800。
上面的INT 0x13就是调用BIOS的中段函数,他的格式如下:
BIOS中断INT 0x13中,
ah=0x02,即为读磁盘扇区到内存。
al=需要读出的扇区数;
ch=磁道号的低八位;
cl=开始扇区(位0—5),磁道号高二位(位6—7)
dh=磁头号
dl=驱动器号(若是硬盘则要置位7)
es:dx—>指向数据缓冲区
若出错则CF示志置位


上面的程序只是将磁盘载入内存,载入内存之后,执行JMP 0xc200跳转到磁盘里面的程序进行运行,执行asmhead.nas里面的程序

BOTPAK	EQU		0x00280000		; 加载bootpack
DSKCAC	EQU		0x00100000		; 磁盘缓存的位置
DSKCAC0	EQU		0x00008000		; 磁盘缓存的位置(实模式)

; BOOT_INFO相关
CYLS	EQU		0x0ff0			; 引导扇区设置
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 关于颜色的信息
SCRNX	EQU		0x0ff4			; 分辨率X
SCRNY	EQU		0x0ff6			; 分辨率Y
VRAM	EQU		0x0ff8			; 图像缓冲区的起始地址

		ORG		0xc200			;  这个的程序要被装载的内存地址

; 画面モードを設定

		MOV		AL,0x13			; VGA显卡,320x200x8bit
		MOV		AH,0x00
		INT		0x10
		MOV		BYTE [VMODE],8	; 屏幕的模式(参考C语言的引用)
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000

; 通过BIOS获取指示灯状态

		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL

; 防止PIC接受所有中断
;	AT兼容机的规范、PIC初始化
;	然后之前在CLI不做任何事就挂起
;	PIC在同意后初始化

		MOV		AL,0xff
		OUT		0x21,AL
		NOP						; 不断执行OUT指令
		OUT		0xa1,AL

		CLI						; 进一步中断CPU

; 让CPU支持1M以上内存、设置A20GATE

		CALL	waitkbdout
		MOV		AL,0xd1
		OUT		0x64,AL
		CALL	waitkbdout
		MOV		AL,0xdf			; enable A20
		OUT		0x60,AL
		CALL	waitkbdout

; 保护模式转换

[INSTRSET "i486p"]				; 说明使用486指令

		LGDT	[GDTR0]			; 设置临时GDT
		MOV		EAX,CR0
		AND		EAX,0x7fffffff	; 使用bit31(禁用分页)
		OR		EAX,0x00000001	; bit0到1转换(保护模式过渡)
		MOV		CR0,EAX
		JMP		pipelineflush
pipelineflush:
		MOV		AX,1*8			;32bit的段
		MOV		DS,AX
		MOV		ES,AX
		MOV		FS,AX
		MOV		GS,AX
		MOV		SS,AX

; bootpack传递

		MOV		ESI,bootpack	; 源
		MOV		EDI,BOTPAK		; 目标
		MOV		ECX,512*1024/4
		CALL	memcpy

; 传输磁盘数据

; 从引导区开始

		MOV		ESI,0x7c00		; 源
		MOV		EDI,DSKCAC		; 目标
		MOV		ECX,512/4
		CALL	memcpy
; 剩余的全部

		MOV		ESI,DSKCAC0+512	; 源
		MOV		EDI,DSKCAC+512	; 目标
		MOV		ECX,0
		MOV		CL,BYTE [CYLS]
		IMUL	ECX,512*18*2/4	; 除以4得到字节数
		SUB		ECX,512/4		; IPL偏移量
		CALL	memcpy

; 由于还需要asmhead才能完成
; 完成其余的bootpack任务

; bootpack启动

		MOV		EBX,BOTPAK
		MOV		ECX,[EBX+16]
		ADD		ECX,3			; ECX += 3;
		SHR		ECX,2			; ECX /= 4;
		JZ		skip			; 传输完成
		MOV		ESI,[EBX+20]	; 源
		ADD		ESI,EBX
		MOV		EDI,[EBX+12]	; 目标
		CALL	memcpy
skip:
		MOV		ESP,[EBX+12]	; 堆栈的初始化
		JMP		DWORD 2*8:0x0000001b

waitkbdout:
		IN		 AL,0x64
		AND		 AL,0x02
		JNZ		waitkbdout		; AND结果不为0跳转到waitkbdout
		RET

memcpy:
		MOV		EAX,[ESI]
		ADD		ESI,4
		MOV		[EDI],EAX
		ADD		EDI,4
		SUB		ECX,1
		JNZ		memcpy			; 运算结果不为0跳转到memcpy
		RET
; memcpy地址前缀大小

		ALIGNB	16
GDT0:
		RESB	8				; 初始值
		DW		0xffff,0x0000,0x9200,0x00cf	;32bit位段寄存器
		DW		0xffff,0x0000,0x9a28,0x0047	; 可执行的文件的32bit寄存器(bootpack用)

		DW		0
GDTR0:
		DW		8*3-1
		DD		GDT0

		ALIGNB	16
bootpack:

INT 0x10
AH = 00H --设置显示的格式
调用参数:
AL = 00H  40 × 25  黑白文本,16级灰度
AL = 01H  40 × 25  16色文本
AL = 02H  80 × 25  黑白文本,16级灰度
AL = 03H  80 × 25  16色文本
AL = 04H  320 × 200 4色图形
AL = 05H  320 × 200 黑白图形,4色灰度
AL = 06H  640 × 200 黑白图形
AL = 07H  80 × 25  黑白文本
AL = 08H  160 × 200 16色图形(MCGA)
AL = 09H  320 × 200 16色图形(MCGA)
AL = 0AH  640 × 200 4色图形(MCGA)
AL = 0DH  320 × 200 16色图形(EGA/VGA)
AL = 0EH  640 × 200 16色图形(EGA/VGA)
AL = 0FH  640 × 350 单色图形(EGA/VGA)
AL = 0DH  320 × 200 16色图形(EGA/VGA)
AL = 0DH  320 × 200 16色图形(EGA/VGA)
AL = 0E  640 × 200 16色图形(EGA/VGA)H
AL = 0F  640 × 350 单色图形(EGA/VGA)H
AL = 11H  640 × 480 单色图形(VGA)
AL = 12H  640 × 480 16色图形(VGA)
AL = 13H  320 × 200 256色图形(VGA)
屏幕的显存地址是0x000a0000


对上面程序的小笔记

1)PIC:可编程中断控制器,是微处器与外设之间的中断处理的桥梁,用于处理由外设发出的中断请求。一般用的是8259芯片

在这里插入图片描述
在这里插入图片描述
初始化的时候为了防止芯片处理中断函数,所以要先屏蔽掉中断。

2)GDT:
关于GDT和IDT这里写的很好
http://www.techbulo.com/708.html

3)设置A20GATE
又是实模式下,芯片寻址只有20根,也就是1M的寻址能力,如果要想超过1M那就需要时能第21根地址先,也就是A20
MOV AL,0xdf ; enable A20
OUT 0x60,AL
这两个语句就是用来使能A20的

4)要进入保护模式,只要设置CR0寄存器的最高位为0,最低位为1,则可以进入保护模式。

5)作者将引导程序赋值到了0X10000的地址上面去了

; 从引导区开始

		MOV		ESI,0x7c00		; 源
		MOV		EDI,DSKCAC		; 目标
		MOV		ECX,512/4
		CALL	memcpy
; 剩余的全部

		MOV		ESI,DSKCAC0+512	; 源
		MOV		EDI,DSKCAC+512	; 目标
		MOV		ECX,0
		MOV		CL,BYTE [CYLS]
		IMUL	ECX,512*18*2/4	; 除以4得到字节数
		SUB		ECX,512/4		; IPL偏移量
		CALL	memcpy

6)对于bootpac.c的复制

    MOV		ESI,bootpack	; 源
	MOV		EDI,BOTPAK		; 目标
	MOV		ECX,512*1024/4
	CALL	memcpy

这里作者将这个.c文件生成的程序复制到了0x280000哪里去了。

这个bootpack是在末尾哪里定义的符号,它就是在asmhead.nas最后面定义的。而在makefile里面我们看到

bootpack.hrb : bootpack.bim Makefile
	$(BIM2HRB) bootpack.bim bootpack.hrb 0

haribote.sys : asmhead.bin bootpack.hrb Makefile
	copy /B asmhead.bin+bootpack.hrb haribote.sys

bootpack.hrb就是挨着asmhead.bin进行连接的,所以在asmhead.nas中定义的符号bootpack就是指向bootpack.hrb

7)程序最后跳转到 JMP DWORD 28:0x0000001b去执行程序了。
为什么跳转到这个地址,刚开始我也不解,看了好久才有点明白,上面的2
8其实就是选择GDT的第二个引索。

GDT0:
		RESB	8				; 这个是0个GDT引索
		DW		0xffff,0x0000,0x9200,0x00cf	; 这个是第1个
		DW		0xffff,0x0000,0x9a28,0x0047	; 这个是2个
		DW		0
GDTR0:
		DW		8*3-1   
		DD		GDT0
		ALIGNB	16

现在来看看GDT的64位段信息,并将第二段信息带入
0~15 --限制长度的低16位 --0xffff
16~31 --基地址低16位 --0000
32~39 -基地址中间8位 --28(因为是小端存储,所以28在前面)
40~47 --权限 --9a
48~55 --限制长度高8位 --cf
56~63 --基地址最高8位 --00

根据上面所得,基地址是0x280000,限制长度是0xcfffff,权限是9a,查资料是可执行的意思
至于为什么要跳转到0x1b的话,得看二进制文件可得
在这里插入图片描述
这样系统就进入bootpac.c程序里面去跑了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值