30天自制操作系统——第3天实验总结

实验日期实验项目
2020.10.15第3天 进入32位模式并导入C语言

一、实验主要内容

1、 内容1 制作真正的IPL

(1).内容概要

  • 实验内容:认识软盘的结构,并使用IPL来装载程序;优化Makefile内容,使用变量定义去简化Makefile的写法。
  • 实验重点:能够使用汇编去读取磁盘,清楚调用0x13号BIOS的相关值的设置。使用IPL来装载程序。

软盘的结构:软盘为多层环状磁条组成。一共有80个柱面(0-79号),每个柱面有18个扇区(1-18号),读取时区分正反面,其中正面为磁头0,反面为磁头1。描述磁盘的某个位置时 可以用Cx-Hy-Sz表示,例如本次实验中含有IPL的启动区就位于C0-H0-S1(柱面0,磁头0,扇区1)磁盘结构示意图如下所示:
在这里插入图片描述
Makefile文件中的变量表示:在Makefile文件中将一些经常用到的路径或者命令设置为变量,定义在文件开头,当编写命令时,用到这些变量时,只需要将变量名外加上括号和$即可。简化了Makefile的书写。

内存地址的装载:启动区在内存地址0x7c00 ~ 0x7dff,用于启动引导程序,软盘的启动区在0x8000~0x81ff,软盘的数据从0x8200开始装载,即第2扇区开始,每个扇区所占空间为512个字节

(2).关键代码分析

;读取磁盘
MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0			; 柱面0
		MOV		DH,0			; 磁头0
		MOV		CL,2			; 扇区2
		MOV		AH,0x02			; AH=0x02 : 表示读取磁盘操作
		MOV		AL,1			; 1个磁盘
		MOV		BX,0
		MOV		DL,0x00			; A驱动器
		INT		0x13			;调用磁盘BIOS
		JC		error           ;jump if carry  如果进位值为1,说明出现了错误跳转到error输出错误信息

这部分代码是在第2天内容的基础上新增的读取磁盘的操作,读取磁盘相关的寄存器的设置根据笔者的书总结如下:

寄存器设置的值表示的含义
AH0x02读取磁盘
AH0x03写入磁盘
AH0x04校验
AH0x0c寻道
ALxx表示处理的扇区数,这里只能是连续的扇区
CH柱面号&0xff软盘的柱面号
CL扇区号(0-5位)(柱面号&0x300)>>2
DH0或1表示软盘的磁头的正面或者反面
DL驱动器号驱动器号
ES:BX缓冲地址表示的实际地址为ES*16+BX

上述寄存器的值在每次读取磁盘时都需要进行相应的设置。另外,返回值在这里是用来检测是否有错误的,如果FLAGS.CF为1说明有错误,错误号码存入AH内,否则AH=0。

其余代码部分和第2天的代码一致。

2、 内容2 试错

(1).内容概要

  • 实验内容:软盘在读取过程中可能会出现一些意料之外的错误,本次实验将重复读取磁盘多次,避免偶尔磁盘出错带来的影响。

(2).关键代码分析

;读取磁盘
		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0			; 柱面0
		MOV		DH,0			; 磁头0
		MOV		CL,2			; 扇区2
		MOV		SI,0			; 记录读取失败的次数,如果次数超过5次,则输出错误信息
retry:
		MOV		AH,0x02			; AH=0x02 : 读入磁盘
		MOV		AL,1			; 1个扇区
		MOV		BX,0
		MOV		DL,0x00			; A驱动器
		INT		0x13			; 调用磁盘BIOS
		JNC		fin				; 没有出错则跳转到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           ;继续尝试

这部分代码设置了多次读取磁盘的操作,如果没有读取成功,则一直重复retry部分的代码。JNC指令表示进位标志位是0就跳转;JAE表示大于或等于时跳转。在重新读取磁盘前,需要进行系统复位,即“AH=0x00,DL=0x00,INT 0x13”

3、 内容3 读到18扇区和读入10个柱面

(1).内容概要

  • 实验内容: 学会读入18个扇区和10个柱面的方法。

指定处理的扇区数,范围在0x01~0xff(指定0x02以上数值时,需要特别注意能够处理多个扇区的条件。如果是FD的话,就不能跨越多个磁道,也不能超过64KB的界限。

(2).关键代码分析

  • readloop部分和retry部分
readloop:
		MOV SI ,0              ; 记录失败次数
retry:
		MOV AH,0x02
		MOV Al ,1              ;一个扇区,这里是一个扇区一个扇区读取
		MOV BX,0
		MOV DL,0x00           ;驱动器A
		INT 0x13              ;调用BIOS
		JNC next              ;没有出错就跳转到next,next是读取磁盘
		ADD SI ,1             ;SI 1,记录失败次数
		CMP SI ,5             ;和试错允许次数5比较
		JAE error             ;超过允许的范围,则跳转到error,输出错误信息
		MOV AH, 0x00 
		MOV DL ,0x00
		INT 0x13              ;这三句表示重置驱动器
		JMP retry

这部分代码是多次读取磁盘,防止偶尔磁盘出错带来的问题。如果没有出错,则跳转到next读取下一个扇区。

  • next部分
next:
		MOV AX,ES          
		ADD AX ,0x0020     
		MOV ES ,AX          ;将内存地址后移0x200,相当于到下一个扇区起始地址
		ADD CL,1            ;下一个扇区
		CMP CL ,18          ;比较CL和18,即判断是否读到18扇区
		JBE readloop        ;每次读取新的扇区前需要将记录失败次数的寄存器重复值为0
		MOV CL,1            ;从扇区1开始
		ADD DH,1            ;DH+1,表示从反面读
		CMP DH ,2            
		JB  readloop            
		MOV DH,0            ;从正面开始读
		ADD CH,1            ;下一个柱面
		CMP CH,CYLS         ;比较CH和CYLS,即判断是否读完10个柱面
		JB readloop

这部分代码的实现逻辑是先判断是否读到18个扇区,读完18个扇区则从反面继续读,正反面读取完成就开始读取下一个柱面,直到读取到指定的柱面。

4、 内容4 着手开发操作系统

(1).内容概要

  • 实验内容: 学会将自己编写的小程序编译后得到的sys文件保存映像文件中;从启动区执行操作系统;确认操作系统的执行情况。
  • 实验重点:了解从启动区执行操作系统的简单流程,并学会调用BOIS确认操作系统的实际执行情况。

保存到映像中的步骤:

	a.使用make install指令,将磁盘映像文件写入磁盘。
	b.在Windows中打开磁盘,将haribote.sys保存到磁盘上。
	c.使用工具将磁盘备份为磁盘映像。

一般向一个空软盘中保存文件时,文件名会写在0x002600以后的地方,文件的内容会写在0x004200以后的地方。当我们将操作系统本身的内容写到名为haribote.sys的文件中,再将其保存到磁盘映像里,确定好磁盘映像0x4200在内存中对应的地址位置,即可从启动区执行操作系统。例如将我们编写的nas文件制作映像文件后打开结果如下:
在这里插入图片描述
在这里插入图片描述
显卡模式设置:设定AH=0x00,AL根据具体的数值设置相应的模式。其中0x03表示16色字符模式,8025;0x12表示VGA模式,6404804位彩色模式,独特的4面存储模式;0x13表示VGA图形模式,320200*8为彩色模式,调色板模式;0x6a表示扩展的VGA图形模式;无返回值。

内存的地址分布,下图是实验过程中找的内存的地址分区图,对于理解笔者汇编的涉及到的地址有一定的帮助。
在这里插入图片描述
(2).关键代码分析
在这里插入图片描述
这部分代码的功能是使得CPU进行待机功能的小程序。ORG表示将磁盘的内容装载到0xc200处。在ipl.nas中读取磁盘完成后加上JMP 0xc200表示跳转到0xc200。当装载启动区执行时,读取磁盘完成后,就会跳转到0xc200处执行我们预先使用ORG指令装载好的程序内容。INT 0x10表示调用显卡,对应的寄存器AH设置为0x00,AL 设置为对应模式。

5、 内容5 进入32位模式,并导入C语言,实现HLT指令

(1).内容概要

  • 实验内容: 了解进入32位模式下需要做哪些前期准备;学会将编写的C语言程序导入sys文件;编写实现特定功能的C语言程序,如HLT指令。
  • 实验重点:32位模式和16位模式下的区别;如何将一个C程序文件变成一个汇编程序,并导入sys文件。

32位模式和16位模式:32位模式,指的是CPU的模式。CPU有32位和16两种模式。如果通过16位模式启动,使用AX和CX等寄存器会十分方便,而EAX和ECX等32位的寄存器就会比较麻烦。在不同的模式下机器语言的命令代码不一样,解释方法不一样,故16位模式的机器语言在32位模式下不能运行。另外,32位下可以使用CPU的自我保护功能(识别出可疑的机器语言并进行屏蔽,以避免破坏系统)。

C语言文件变成机器语言,并生成haribote.sys的基本操作步骤:

	a.使用ccl.exe将bootpack.c生成bootpack.gas
	b.使用gas2nask.exe将bootpack.gas生成bootpack.nas
	c.使用nask.exe将bootpack.nas生成bootpack.obj
	d.使用obi2bim.exe将bootpack.obj生成bootpack.bim
	e.使用bim2hrb.exe将bootpack.bim生成bootpack.hrb
	f.使用copy指令将asmhead.bin与bootpack.hrb结合生成baribote.sys文件

整个过程的流程图如下所示:
在这里插入图片描述
在这里插入图片描述
编写c程序和汇编程序时需要注意,在nask目标文件的模式下,必须设定文件名信息,写明程序的函数名。特别在函数名前需要加上“_”,否则就不能很好地与C语言函数链接,链接的函数名必须使用GLOBAL声明。

(2).关键代码分析

  • haribote.nas代码
; 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显卡,320*200*8位彩色
		MOV		AH,0x00
		INT		0x10
		MOV		BYTE [VMODE],8	; 记录画面模式
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000
; 用BIOS取得键盘上各种LED指示灯的状态
		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL	
fin:
		HLT
		JMP fin

这部分代码主要是设置画面模式,画面的像素数,颜色数和从BIOS取得的键盘信息都保存起来,保存在内存中0x0ff0的位置处。

  • naskfunc.nas代码
[FORMAT "WCOFF"]				; 制作目标文件的模式
[BITS 32]						; 制作32位模式用的机器语言
; 制作目标文件的信息
[FILE "naskfunc.nas"]			; 程序中包含的函数名
		GLOBAL	_io_hlt			; 
; 以下是实际的函数
[SECTION .text]		
_io_hlt:	; void io_hlt(void);
		HLT
		RET

这部分代码是汇编写的HLT指令的实现函数

  • bootpack.c的代码
void io_hlt(void);/* 函数声明用;表示函数在别的文件中 */
void HariMain(void)
{
fin:
	io_hlt(); /* 执行naskfunc.nas里面的_io_hlt函数 */
	goto fin;
}

这部分代码是用C语言写的具有停机功能的程序,里面调用了汇编代码写的HLT指令。

二、遇到的问题及解决方法

1、 描述问题1

  • 问题描述

在笔者书中提到,将软盘内容读到内存0x8200,内存结构中0x7c00 ~ 0x7dff用于载入ipl,0x7e00~0x7fff用于引导区运行时栈,为什么计算0x4200对应位置时是从0x8000开始?

  • 解决方法

通过上网查阅资料,BIOS将磁盘0位置的内容拷贝到了内存0x7c00处,执行启动区的内容后,会将软盘内容读入第2个扇区即0x8200的位置,而0x4200是相对于0号地址中第1个扇区的起始地址,所以0x4200对应内存中0x8200+0x4200-0x200=0x8000+0x4200。

2、 描述问题2

  • 问题描述:
    在这里插入图片描述
  • 解决方法

make –r img时没有规则生成ipl10.bin文件。仔细检查后发现笔者Makefile文件中使用的工具是去上一级目录中z_tools里面找,而我新建了一个文件夹,导致没有工具生成ipl10.bin文件。

修改Makefile文件中所有对应路径;将路径修改为Makefile中对应的路径,前者需要修改的地方太多,还是选择后者吧。

三、程序设计创新点

1、 描述创新点1,关键代码及结果截图

  • 创新点1

根据教材58页上VRAM存储着画面的像素,而每个像素在地址0xa0000~0xaffff中,改变地址里边的像素即可改变显示画面。

  • 关键代码
bootpack.c代码
void change(int s,int d);
void HariMain(void)
{
	int i;
	for(i=0xa0000;i<=0xaffff;i+=0x200)
	{
		if(i>0xaffff||i+10>0xaffff||i+20>0xaffff) break;
		change(i,45);
		change(i+10,10);
		change(i+20,8);
	}
}

这部分代码是用来修改制定地址中像素,change函数用汇编代码编写。

change代码
[FORMAT "WCOFF"]				; 制作目标文件的模式
[INSTRSET "i486p"]
[BITS 32]						; 制作32位模式用的机器语言
; 制作目标文件的信息
[FILE "naskfunc.nas"]			; 程序中包含的函数名
		GLOBAL	_change			; 
[SECTION .text]		
_change:	; void change(int s,int d);
		MOV ECX,[ESP++4]
		MOV AL,[ESP+8]
		MOV [ECX],AL
		RET

函数调用过程中参数1,参数2放在栈中esp+4和esp+8的位置,故只需要将esp+8处的数据放到esp+4的地址中即可。

  • 结果截图
    在这里插入图片描述

四、实验心得体会

  • 本次实验是自制操作系统的第3天,学习的内容比较多,包括继续介绍汇编语言的相关指令和BIOS的调用;讲解读取磁盘的汇编程序;从启动区开始执行操作系统,并确认其执行情况;进入32位模式导入C语言等内容。有了之前汇编语言的基础,在阅读教材的时候比较容易理解笔者所写的汇编代码,比较不清楚的是关于软盘的结构,磁盘和内存地址的对应关系,通过查阅相关资料,解决了自己遇到的问题。总体来说,这次实验内容多,但是都不难理解,跟着笔者的讲解一步步深入,实验很容易完成。
  • 在这次实验中梳理C程序转化为汇编代码的步骤时,用到了流程图的方式描述,清晰简洁,可以在以后学习过程中对繁杂步骤梳理,以便学习和理解。实验中受到教材58页VRAM存储着画面的像素,于是想通过改变不同地址中像素的大小来绘制简单的图案,这就是本次实验我想到的创新点。另外,是否能用C程序实现其他功能,比如简单加法输出。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值