[Rx86OS-II] 制作IPL

平台

处理器:Inte lCeleron(R) Dual-Core CPU

操作系统:Windows7 专业版 x86

阅读《30天自制操作系统》—川合秀实[2015.03.15 – 03.16],[03.27整理]笔记。

将《30天自制操作系统》简称为“书”。对于书中的工具,可以专门对其笔记。

工具:../toolset/


1 了解IPL

1.1 启动区

软盘的第一个扇区之所以有那么多死板的规定,是因为软盘的第一个扇区有特殊的作用:计算机首先从磁头0面最初一个扇区开始读软盘,然后检查这个扇区最后2个字节的内容。如果这最后2个字节不是55AAH,计算机会认为这张盘上没有所需的启动程序,就会报一个不能启动的错误;如果计算机确认了第一个扇区的最后2个字节正好是55AAH,那它就认为这个扇区的开头是启动程序,并开始执行这个程序。故而软盘的第一个扇区被称为启动区(boot sector)。


计算机(BIOS)只会读软盘的第一个扇区的内容到内存,软盘其它扇区的内容靠执行第一个扇区内的程序载入


1.2 IPL

IPL(Initial program loader,启动程序加载器)是软盘启动区内的程序,这个程序的功能为加载软盘各个扇区的内容到内存中。在“[OS-I]计算机开机从软盘启动显示字符串Hello World”中,第一个扇区内的二进制程序的作用是显示字符串“Hello World”,并没有加载软盘扇区内容到内存的功能。像这样的软盘的第一个扇区可以不叫“启动区”,其内的程序也可不叫“IPL”,分别叫它们“Hello World扇区”和“Hello World程序”比较合适。


2 制作IPL

制作IPL时需要遵循2点:

[1] BIOS 13h对启动区的格式要求(非程序运行所必须的东西);

[2] 在启动区内的代码要有载入其它扇区内容到内存的功能。


2.1 软盘的柱面

磁头0和磁头1所在面的磁道号相同的两个磁道被称为一个柱面。软盘内用于存储二进制信息的(黑色)介质被称为磁盘。


2.2 读取软盘10个柱面的IPL

启动区的内容被加载到内存的0x7c00~ 0x7dff,就让软盘后续区内容跟启动区内容相接,将后续内容拷贝到0x8000~ 0x34dff。

; ipl
; TAB=4
CYLS	EQU		10				;读磁盘10个柱面

		ORG		0x7c00			;后续程序从0x7c00开始装载

;FAT12格式软盘启动区规定内容(非必须)
		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		;启动区的名称,可以是任意8字节的字符串
		DW		512				;每个扇区(sector)的大小(必须为512字节)
		DB		1				;簇(cluster)的大小(必须为1个扇区)
		DW		1				;FAT的起始位置(一般从第一个扇区开始)
		DB		2				;FAT的个数(必须为2)
		DW		224				;根目录的大小(一般设成224)
		DW		2880			;读磁盘(软盘内存数据的介质)的大小(必须是2880扇区)
		DB		0xf0			    ;磁盘的种类(必须是0xf0)
		DW		9				;FAT的长度(必须是9扇区)
		DW		18				;1个磁道(track)有几个扇区(必?是18)
		DW		2				;磁头个数(必是2)
		DD		0				;不使用分区,必是0
		DD		2880			;重写一次磁盘的大小
		DB		0,0,0x29
		DD		0xffffffff	
		DB		"HARIBOTEOS "	;磁盘的名称(11字节)
		DB		"FAT12   "		;磁盘的格式名称(8字节)
		RESB	18				;空出18字节


;程序主体:读磁盘内容到内存
entry:
		MOV		AX,0		;根据程序被加载的地址初始化寄存器
		;MOV		SS,AX
		;MOV		SP,0x7c00
		MOV		DS,AX

;读磁盘内容到内存的程序
		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0		;磁盘的柱面,BIOS 0x13h中断程序参数
		MOV		DH,0		;磁头0,BIOS 0x13h中断程序参数
		MOV		CL,2		;扇区2,BIOS 0x13h中断程序参数
readloop:
		MOV		SI,0			;读扇区失败的次数
retry:
		MOV		AH,0x02		; AH=0x02:读磁盘;BIOS 0x13h中断程序参数
		MOV		AL,1		;一个扇区;BIOS 0x13h中断程序参数
		MOV		BX,0		;将磁盘内容读到ES:BX 处
		MOV		DL,0x00		; A驱动器
		INT		0x13			;调用BIOS 0x13h中断程序
		JNC		next			    ;无出错就跳转到next处
		ADD		SI,1			;记录操作磁盘失败的次数
		CMP		SI,5	
		JAE		error			    ;如果SI >= 5就跳到error处
		MOV		AH,0x00
		MOV		DL,0x00
		INT		0x13
		JMP		retry
next:
		MOV		AX,ES
		ADD		AX,0x0020
		MOV		ES,AX		;把内存地址后移0x200(512)
		ADD		CL,1		;下一个扇区
		CMP		CL,18
		JBE		readloop		    ; CL <= 18 就继续读下一个扇区
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readloop		 ; DH < 2(分别读磁盘两个面的CH柱面的1 ~ 18扇区)
		MOV		DH,0
		ADD		CH,1
		CMP		CH,CYLS
		JB		readloop		 ; CH < CYLS 磁盘每个面都读CYLS个柱面

;加载磁盘内容后、CPU执行完新任务后进入休眠状态
fin:
		HLT						
		JMP		fin				

error:
		MOV		SI,msg		;用si访问字符串
putloop:
		MOV		AL,[SI]
		ADD		SI,1			
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e		;0x0e表示显示一个字符;BISO 0x10中断程序参数
		MOV		BX,15		;显示字符的属性;BISO 0x10中断程序参数
		INT		0x10			;调用BIOS 0x10号中断程序
		JMP		putloop
msg:
		DB		0x0a, 0x0a		;换行
		DB		"load error"
		DB		0x0a	
		DB		0

		RESB	0x7dfe-$		    ;再填0直到0x7de - 1处

		DB		0x55, 0xaa		;表明需要执行启动程序IPL

[1] ipl10.nas功能:将软盘前10个柱面(没有读启动区)的内容装载到内存地址空间0x08200~ 0x34fff中(从0x8000处开始装载不能被正确执行,估计是因为0x8000处有F0H FFH FFH 3字节内容)。([实模式]内存地址空间分布 CPU合成内存地址的方式 程序中段的加载

[2] “读磁盘内容到内存”部分以磁盘的“磁头”、“柱面”、“扇区”作为“最外层”、“次外层”、“内层”循环的条件,在读完磁头0上柱面的一面时就切换到磁头1读柱面的另一面

[3] ipl10.nas用si寄存器来记录读一个扇区不成功的次数,如果读一个扇区读5次都读不成功则放弃这次的程序加载操作。


2.3 准备其它扇区的内容

如果此时将ipl10.nas下载到软盘中并运行,IPL会将软盘前10个柱面的内容拷贝到内存地址空间0x08200~ 0x34fff中。虽然如果拷贝其它扇区内容不成功时会有“load error”的错误提示,但笔记还想执行一下IPL拷贝的程序。


需要保证源程序中的各偏移值跟程序在内存中的各偏移值一致,否则需要在用ORG伪指令。见“[实模式] 内存地址空间分布 CPU合成内存地址的方式 程序中段的加载”的ORG部分。

org 0x8200    ;让本程序中jmp指令的参数以0x8200位起始偏移计算,
             ;因为以下这段程序将会被加载到0x8200处
;后续扇区内容,从偏移0x8200开始
oth_sec:
	MOV		SI,ho_str
showloop:
	MOV		AL,[SI]
	ADD		SI,1		;下一个字符
	CMP		AL,0
	JE		sleep
	MOV		AH,0x0e		;BIOS 10h程序的功能号参数,eh表示显示字符功能
	MOV		BX,15		;AH = EH时,BL表字符前景色,AL表要显示的字符
	INT		0x10		;调用BIOS 10h号中断程序
	JMP		showloop
sleep:
	HLT				;省电:让CPU进入休眠状态,当复位信号或者中断来临时,
	JMP		sleep		;CPU再执行HLT的下一条指令,或者转去执行中断程序,
					;当中断处理完后又执行一次HLT,CPU将再次进入休眠状态

ho_str:
	DB		0x0a, 0x0a	;0x0a表示换行
	DB		"hello, world"
	DB		0x0a		
	DB		0

RESB	1474560 + 0x7c00 - $

只要IPL正确的将软盘10个柱面的内容加载到内存0x08200~ 0x34fff后,就应该跳到0x08200处执行拷贝的代码,最后让CPU进入休眠。如果IPL拷贝失败,则显示load error并让CPU休眠。


将这段程序和ipl10.nas结合在一起:

ipl
; TAB=4
CYLS	EQU		10				;读磁盘10个柱面

		ORG		0x7c00			;后续程序从0x7c00开始装载

;FAT12格式软盘启动区规定内容(非必须)
		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		;启动区的名称,可以是任意8字节的字符串
		DW		512				;每个扇区(sector)的大小(必须为512字节)
		DB		1				;簇(cluster)的大小(必须为1个扇区)
		DW		1				;FAT的起始位置(一般从第一个扇区开始)
		DB		2				;FAT的个数(必须为2)
		DW		224				;根目录的大小(一般设成224)
		DW		2880			;读磁盘(软盘内存数据的介质)的大小(必须是2880扇区)
		DB		0xf0			    ;磁盘的种类(必须是0xf0)
		DW		9				;FAT的长度(必须是9扇区)
		DW		18				;1个磁道(track)有几个扇区(必?是18)
		DW		2				;磁头个数(必是2)
		DD		0				;不使用分区,必是0
		DD		2880			;重写一次磁盘的大小
		DB		0,0,0x29
		DD		0xffffffff	
		DB		"HARIBOTEOS "	;磁盘的名称(11字节)
		DB		"FAT12   "		;磁盘的格式名称(8字节)
		RESB	18				;空出18字节


;程序主体:读磁盘内容到内存
entry:
		MOV		AX,0		;根据程序被加载的地址初始化寄存器
		;MOV		SS,AX
		;MOV		SP,0x7c00
		MOV		DS,AX

;读磁盘内容到内存的程序
		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0		;磁盘的柱面,BIOS 0x13h中断程序参数
		MOV		DH,0		;磁头0,BIOS 0x13h中断程序参数
		MOV		CL,2		;扇区2,BIOS 0x13h中断程序参数
readloop:
		MOV		SI,0			;读扇区失败的次数
retry:
		MOV		AH,0x02		; AH=0x02:读磁盘;BIOS 0x13h中断程序参数
		MOV		AL,1		;一个扇区;BIOS 0x13h中断程序参数
		MOV		BX,0		;将磁盘内容读到ES:BX 处
		MOV		DL,0x00		; A驱动器
		INT		0x13			;调用BIOS 0x13h中断程序
		JNC		next			    ;无出错就跳转到next处
		ADD		SI,1			;记录操作磁盘失败的次数
		CMP		SI,5	
		JAE		error			    ;如果SI >= 5就跳到error处
		MOV		AH,0x00
		MOV		DL,0x00
		INT		0x13
		JMP		retry
next:
		MOV		AX,ES
		ADD		AX,0x0020
		MOV		ES,AX		;把内存地址后移0x200(512)
		ADD		CL,1		;下一个扇区
		CMP		CL,18
		JBE		readloop		    ; CL <= 18 就继续读下一个扇区
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readloop		 ; DH < 2(分别读磁盘两个面的CH柱面的1 ~ 18扇区)
		MOV		DH,0
		ADD		CH,1
		CMP		CH,CYLS
		JB		readloop		 ; CH < CYLS 磁盘每个面都读CYLS个柱面
        
        jmp     oth_sec
;加载磁盘内容后、CPU执行完新任务后进入休眠状态
fin:
		HLT						
		JMP		fin				

error:
		MOV		SI,msg		;用si访问字符串
putloop:
		MOV		AL,[SI]
		ADD		SI,1			
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e		;0x0e表示显示一个字符;BISO 0x10中断程序参数
		MOV		BX,15		;显示字符的属性;BISO 0x10中断程序参数
		INT		0x10			;调用BIOS 0x10号中断程序
		JMP		putloop
msg:
		DB		0x0a, 0x0a		;换行
		DB		"load error"
		DB		0x0a	
		DB		0

		RESB	0x7dfe-$		    ;再填0直到0x7de - 1处

		DB		0x55, 0xaa		;表明需要执行启动程序IPL

org 0x8200    ;让本程序中jmp指令的参数以0x8200位起始偏移计算,
             ;因为以下这段程序将会被加载到0x8200处
;后续扇区内容,从偏移0x8200开始
oth_sec:
	MOV		SI,ho_str
showloop:
	MOV		AL,[SI]
	ADD		SI,1		;下一个字符
	CMP		AL,0
	JE		sleep
	MOV		AH,0x0e		;BIOS 10h程序的功能号参数,eh表示显示字符功能
	MOV		BX,15		;AH = EH时,BL表字符前景色,AL表要显示的字符
	INT		0x10		;调用BIOS 10h号中断程序
	JMP		showloop
sleep:
	HLT				;省电:让CPU进入休眠状态,当复位信号或者中断来临时,
	JMP		sleep		;CPU再执行HLT的下一条指令,或者转去执行中断程序,
					;当中断处理完后又执行一次HLT,CPU将再次进入休眠状态

ho_str:
	DB		0x0a, 0x0a	;0x0a表示换行
	DB		"hello, world"
	DB		0x0a		
	DB		0

RESB	1474560 + 0x7c00 - $

2.4 执行

打开“!cons_ne.bat”,用nask.exe依据2.3中结合的程序输出helloos.img,再运行“install.bat”命令将helloos.img下载到软盘上。再将软盘插入另一台相同计算机中,以软盘方式启动,得到如下结果:

Figure1. IPL加载其他扇区程序后再执行其它扇区内容的结果

计算机首先根据IPL的最后2个字节55AA执行IPL程序,IPL将前10个柱面的内容加载到了内存0x08200 ~ 0x34fff处后执行jmp 0x8200,CPU就执行0x08200的代码,最后执行HLT指令,进入休眠。


@ hutao1101175783

我重新运行了一遍,可以显示“hello world”。


我的操作是这样的,目录ipl下的文件(ipl的上一级目录有z_tools文件):

        !cons_nt.bat

        install.bat

        ipl10.nas

        nask.exe

        run.bat
在ipl目录下打开 !cons_nt.bat,运行“nask.exe ipl10.nas helloos.img"命令生成helloos.img文件;运行”install.bat“命令将helloos.img下载到软盘上;运行”run.bat“命令将helloos.img载入QEMU中运行。在真机和QEMU上都成功的显示了"hello world"字符串(但不知道此笔记中有无拼写错误,不必太纠结结果哈)。


用nask.exe编译ipl10.nas时无报错。RESB 1474560 + 0x7c00 - $是将软盘(1474560字节)后续内容都设为了0,是对应的整个helloos.img文件(保证helloos.img文件大小为1.44M),不是对应所读的柱面。



总结

[1] 计算机(BIOS)将软盘启动区程序读到0x7c00~ 0x7dff,为了保证内存中的指令参数和编译器编译后的指令参数一直,需要在汇编程序中使用ORG0x7c00语句;IPL将启动区的程序加载到0x8000~ 0x81ff;IPL读启动区后一个扇区的内容到内存0x8200~0x83ff;以此类推… (装载启动区程序到内存地址空间0x7c00~ 0x7dff是计算机(BIOS)规定;从0x8000 内存地址空间存软盘程序是开发操作系统人的规定,因为这段内存没有被其它程序占用)。


[2] 从计算机开机到操作系统的启动,CPU的控制权的操纵者为:FFFF0H(实模式)-->BIOS(实模式)-->(操作系统)程序。


[x86OS] Note Over.

[2015.04.01]

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值