《30天自制操作系统》学习笔记——第1-3天

这本书作者是日本人,虽然书翻译为中文,但是源代码里注释都是日文,对不懂日语的人来说看起来不够方便,我把书本中给出的注释翻译,以及书本介绍的一些知识,加到了注释里,阅读起来能够方便些。
前3天主要就是写一个ipl程序(initial program loader启动程序加载器),不论是用二进制编辑器直接写机器指令还是用汇编生成二进制程序,最终目的都是得到第一个扇区的512字节的启动程序。

0x10号bios函数用于显示文字

0x13号bios函数提供磁盘的读,写,扇区校验,寻道操作,AH=0x02读盘操作

这两个bios函数调用时以寄存器的值为参数,提供相应操作。


; haribote-ipl
; TAB=4

CYLS  	EQU		10				;
		ORG		0x7c00			;ORG伪指令,编译不生成机器代码,用于给链接器定位用,将程序装载到内存的指定位置
								;0x7c00~0x7dff 512字节放置启动程序

; 标准FAT12格式软盘专用的代码

		JMP		entry			;jmp跳转 至标签entry处;JMP 0x7c50 没问题,JMP跳转到的就是内存地址
		DB		0x90			;DB即data byte 往文件里写入一个字节,DW写一个word,16位,DD写double word,32位
		DB		"HARIBOTE"		;启动区的名称,可以是任意的字符串(8字节)
		DW		512				;每个扇区(sector)的大小(必须为 512字节)
		DB		1				;簇(cluster)的大小(必须为 1 个扇区)
		DW		1				;FAT(File Allocation Table:文件配置表)的起始位置(一般从第一个扇区开始)
		DB		2				;FAT的个数,必须为2 
		DW		224				;根目录的大小(一般设成224项)
		DW		2880			;该磁盘的大小(必须为2880个扇区)
		DB		0xf0			;磁盘的种类(必须为0xf0)
		DW		9				;FAT的长度(必须是9扇区) 
		DW		18				;一个磁道(track)有几个扇区(必须是18)
		DW		2				;磁头数(必须是2)
		DD		0				;不使用分区,必须是0
		DD		2880			;重写一次磁盘大小 
		DB		0,0,0x29		;意义不明,固定
		DD		0xffffffff		;(可能是)卷标号码
		DB		"HARIBOTEOS "	; 磁盘的名称(11字节)
		DB		"FAT12   "		; 磁盘格式名称(8字节)
		RESB	18				; reserve word 从当前地址空出18个字节,nask会把这18个字节填充为0x00

entry:
		MOV		AX,0 			;AX accumulator 	累加寄存器 (16位)把0复制到AX中,初始化AX
		MOV		SS,AX 			;SS stack segment	栈段寄存器 (16位)
		MOV		SP,0x7c00		;SP stack pointer	栈指针寄存器(16位)
		MOV		DS,AX 			;DS data segment	数据段寄存器(16位)

		MOV		AX,0x0820 		;MOV AL,[ES:BX] 代表ES*16+BX的内存地址 
								;0x7c00~0x7dff用于启动区,0x7e00~0xfbff没有特别的用途,操作系统随便用
								;缓冲区地址,将要把软盘上读取的数据放到0x8200之后,内存分布图上0x8000后无人使用
								;0x8000~0x81ff留给启动区,将启动区内容读到这里
		MOV		ES,AX 			;ES extra segment	附加段寄存器(16位)	ES=0x0820,BX=0		
		MOV		CH,0 			;CH	counter high    计数寄存器高位(8位)	柱面0
		MOV		DH,0 			;DH	data high		数据寄存器高位(8位)	磁头0
		MOV		CL,2 			;CL counter low		计数寄存器地位(8位)	扇区2,计数读的扇区标号
readloop:
		MOV		SI,0 			;SI	source index	源变址寄存器(16位)	记录失败
retry:
		MOV		AH,0x02 		;AH	accumulator high 累加寄存器高位(8位) AX=0x02 读盘
		MOV		AL,1 			;AL	accumulator low  累加寄存器低位(8位) AL=1 1个扇区
		MOV		BX,0 			;BX base			 基址寄存器(16位)
		MOV		DL,0x00  		;DL	data low		 数据寄存器低位(8位)	A驱动器
		INT		0x13			;INT interrupt 软件中断指令,暂且当作函数调用 调用磁盘BIOS
		JNC		next			;jump if not carry 	如果进位标志为0,跳转至next	0x13调用有错标志为1,无错为0
		ADD		SI,1 			;SI加1
		CMP		SI,5 			;比较SI和5
		JAE		error 			;jump if above or equal SI>=5时跳转到error
		MOV		AH,0x00 		;
		MOV		DL,0x00 		;A驱动器
		INT		0x13 			;重置驱动器
		JMP		retry 			;无条件 跳转到retry
next:
		MOV		AX,ES 			;把内存地址后移0x200 512字节 512/16=0x20 [ES:BX]
		ADD		AX,0x0020		;
		MOV		ES,AX 			;没有ADD ES,0x20指令
		ADD		CL,1 			;CL+1
		CMP		CL,18 			;比较CL和18(1-18 18个扇区)
		JBE		readloop		;jump if below or equal cl<=18 跳转到readloop 
		MOV		CL,1 			;扇区标号更新为1
		ADD		DH,1 			;磁头数+1,读磁盘反面
		CMP		DH,2 			;比较DH 2
		JB 		readloop 		;jump if below DH<2 时跳转到readloop 
		MOV		DH,0 			;磁头初始化为0
		ADD		CH,1 			;柱面+1
		CMP		CH,CYLS 		;比较CH 和 CYLS=10
		JB 		readloop 		;jump if below  CH<10 跳转到readloop
								;空软盘保存文件时,文件名会写在0x2600以后的地方,文件内容会写在0x4200以后
		MOV		[0x0ff0],CH	 	;把磁盘装载地址的结束写到内存0x0ff0处
		JMP		0xc200 			;程序从启动区开始,把磁盘上的内容装载到内存0x8000号地址,磁盘0x4200处的内容应该位于
								;0x8000+0x4200=0xc200号地址		
error:
		MOV		SI,msg			;msg地址复制到SI
putloop:
		MOV		AL,[SI]			;[]表示内存地址,这句是把内存地址为SI的数据复制到AL中
		ADD		SI,1 			;SI+1
		CMP		AL,0 			;比较AL和0
		JE		fin 			;jump if equal
		MOV		AH,0x0e 		;
		MOV		BX,15 			;
		INT		0x10 			;调用bios 0x10号函数
		JMP		putloop 		;
fin:
		HLT 					;CPU停止动作,进入待机状态,外部发生变化,比如按下键盘,cpu会苏醒过来,继续执行程序
		JMP			fin			;无限循环
msg:
		DB		0x0a,0x0a 		;2个换行
		DB		"load error" 	;DB直接写字符串,汇编语言自动查找编码
		DB		0x0a			;换行
		DB		0 				;标志msg结束

		RESB	0x7dfe-$		;$指示当前行在文件中所处的字节数;在使用ORG指令后

		DB		0x55,0xaa		;软盘的第0x1fe即第510字节开始处必须为55 aa

你可能感兴趣的:(汇编,操作系统,BIOS)