30天自制操作系统第三天
操作系统实验日志3
学号 | 201708010402 | 姓名 | 徐冰娜 | 专业年级班级 |
---|---|---|---|---|
实验日期 | 2019.9.28 | 实验项目 | 第3天:进入32位模式并导入C语言 | 智能1701 |
30天自制操作系统第三天
一、实验主要内容
1、内容1: 新出现的指令以及名词解释
① INT 0x13:调用bios的0x13号函数
AH=0x00 | 复位磁盘驱动器 | AH=0x0D | 复位硬盘控制器 |
---|---|---|---|
AH=0x01 | 检查磁盘驱动器状态 | AH=0x15 | 取得驱动器类型 |
AH=0x02 | 读扇区 | AH=0x16 | 取得软驱中盘片的状态 |
AH=0x03 | 写扇区 | AL=处理对象的扇区数 | 只能同时处理连续的扇区 |
AH=0x04 | 校验扇区 | CH=柱面号&0xff | 柱面有80个(0~79) |
AH=0x05 | 格式化磁道 | CL=扇区号(0-5位)|(柱面号&0x300)>>2 | 每个柱面18个扇区(1~18号) |
AH=0x08 | 取得驱动器参数 | DH=磁头号 | 正面位0反面为1 |
AH=0x09 | 初始化硬盘驱动器参数 | DL=驱动器号 | 从0开始,制定从哪个软盘驱动器上的软盘读取数据 |
AH=0x0C | 寻道 | ES:BX=缓冲地址 | |
返回值:FLACS.CF=0 | 没错误,AH=0 | FLACS.CF=1 | 有错,错误号码存入AAH |
② INT 0x16:
③ 软盘的磁盘结构: 磁盘被分成若干个磁道即柱面,每个柱面又分为若干个扇区,每个扇区存储512个字节。柱面是一组同心圆,一个1.44M的软盘,它有80个柱面,每个磁道有18个扇区,两面都可以存储数据,因此有正反两个磁头。
注释:使用软盘时,需要注意不要划伤盘片,盘片不能变形、不能受高温、不能受潮、不要靠近磁性物质等等。
④ 变量改写Makefile: 变量采用$(变量)的格式。
⑤ JC: 如果进位标志是1的话,就跳转。
⑥ JNC: jump if not carry 如果进位标志是0就跳转。
⑦ JAE: jump if above or equal 大于或等于+时跳转。
⑧ JBE: jump if below or equal 小于等于则跳转。
⑨ VRAM: 指显卡内存,也就是用来显示画面的内存。可以向内存一样存储数据,且各个地址都对应着画面上的像素,因此能在画面上绘制出五彩缤纷的图案。
⑩ INT 0x10画面模式下“VRAM是0xa0000~0xaffff的64KB”。
⑾ 汇编指令EQU: 用符号名代表字符串。用一个具有一定含义的符号名定义某一个较长的字符串,在随后的程序中就用该符号名。
2、内容2:用IPL装载程序
启动区位置: C0-H0-S1(柱面0,磁头0,扇区1的缩写);
段址+基址的地址表示方法: 使用段寄存器时用ES:BX这种方式来表示,写成“MOV AL, [ES:BX]”,代表ES*16+BX的内存地址;
操作系统安装步骤: 首先软盘中的启动区会被装载到内存的0x7c00~0x7dff中,然后cpu会执行已经加载的启动区程序的指令,将软盘中的其余数据按需求加载到内存的指定位置中。
3、内容3:软盘读取数据(读取一个扇区->试错->读到18个扇区->读到10个柱面)
根据教材中的代码,由于第一个扇区是留给启动区,所以从第二个扇区开始读,即从C0-H0-S2读到C0-H0-S18,然后再读取另一个磁头,即从C0-H1-S1读到C0-H1-S19,再不断读取下一个柱面、扇区和磁头,即从C1-H0-S1读到C9-H1-S18.
试错:当出现错误,会重新读,5次还不行就放弃,每次出错的时候,就调用bios的13号函数,重置驱动器。
4、内容4:从启动区执行操作系统
过程: 因为已经将操作系统的内容保存到了.sys,文件,接下来只要找到它的位置,然后启动区在执行的时候,跳转到那个位置就可以了。所以要设置段寄存器,所以就在操作系统的文件中加了0rg 0xc200。
注释:sys是Windows的系统文件。如安装文件,日志文件,驱动文件,备份文件,操作如播放等文件,还有些垃圾文件等诸如此类。都是这类sys后缀名的。
我们已经得到的结论是:向一个空软盘保存文件时,
(1)文件名会写到0x002600以后的位置;
(2)文件的内容会写在0x004200以后的地方;
所以最终系统的内容就被储存到0x8000+0x4200=0xc200地址的位置。(为什么从8000开始加后面的问题解答会写到)
- 32位模式前期准备
(1)为什么要进行前期准备:16位机器语言模式不能在32位机器语言模式下运行,而bios是用16位机器语言写的,32位模式就不能调用BIOS功能了,所以我们要在开头做好bios要做的事情。
(2)BIOS都要做什么事:画面模式的设定、得到键盘状态
- 开始导入C语言
将C语言变成汇编语言:
工具 | 作用 | 输入 | 输出 |
---|---|---|---|
cc1 | gcc以gas汇编语言为基础,输出gas用的源程序 | .c | .gas |
gas2nask | 把gas变换成nask能翻译的语法 | .gas | .nas |
nask | 翻译成机器语言,生成目标文件.obj | .nas | .obj |
obj2bim.exe | 目标文件需与其他文件link才能编程真正可以执行的机器语言,bim是二进制映像文件,是一种代替的形式 | .obj | .bim |
bim2hrb.exe | 为了能够实际使用,要做成适合本书操作系统要求的形式 | .bim | .hrb |
实现HLT:
①naskfunc.nas是用汇编写的函数,还要与bootpack.obj链接,它也需要编译成目标文件。
②在nask目标文件的模式下,必须设定文件名信息,然后再写明下面程序的函数名。“_”需加载函数名前面,否则就不能很好地与C语言函数链接。需要链接的函数名,都要用GLOBAL指令声明。
文件结构流程图:
二、遇到的问题及解决方法
1.描述问题1:今天和同学讨论了一下本实验代码中的ORG,有如下几个疑惑,ORG命令后的地址是什么地址?代码中为什么总是使用ORG
0x7c00?为什么有时候去掉ORG指定地址或者使用7c00后的地址后还可以正常执行吗?如果说ORG指令后的地址是启动区的装载地址,那么ORG以及之前的指令被加载内存的什么地方?
解决方法:和同学讨论后,又查阅了一些资料后得知:
①ORG后的地址是程序被载入内存时的起始地址;在我们的实验代码中,org指令本身并不能决定程序将要加载到内存的什么位置,它只是告诉编译器,我的程序在编译好后需要加载到哪个地址;
②引导程序加载到内存的7c00h处是一项标准,并不是在编程时决定的,在实际装系统的过程中(并非是虚拟机),将org后的数字改成其他值,bois程序一样将它加载到7c00处;
③不一定。在数据访问时,都是采用段地址+基址的方式,如果不用org指定地址那么段地址就会清0,最后读取数据的地址就不是我们预期的那个地址了;当程序中没有对内存的寻址操作时,不加org
0x7c00就不会出错。
④org指令只会在编译期影响到内存寻址指令的编译(编译器会把所有程序用到的段内偏移地址自动加上org后跟的数值),而其自身并不会被编译成机器码。
2.描述问题2:
不明白为什么0x8000到0x81ff区域也要留给启动区,而且为什么不是从0x7e00开始?
解决方法:经过查阅了一些资料得知,BIOS读完启动扇区以后,会跳转到0x7C00启动,占用0x7C00-0x7DFF这一段(512字节),而一般bootloader还需要一个栈空间或者读磁盘的交换空间,一般是放到0x7E00-0x7FFF这512字节里,所以有些操作系统的镜像起点是0x8000。然后启动区确实会拷贝一份映射到0x8000位置上。但是BIOS里读取启动扇区都是加载到0x7C00上的。
三、程序设计创新点
1、描述创新点1: 改写c语言,改变不同地址的值,显示出条纹图案
运行结果:
四、实验心得体会
通过本次实验,我真正了解了操作系统的执行过程,以及启动区的位置以及作用。知道从开机到装载内存到指令执行都是怎么回事。在和同学讨论的过程中,真的很惊讶王文斌的研究能力,能在很小的细节上看出问题,然后深入的研究。比如说哪个org命令,我自己就没有看出那么多问题,经过他一点播,我才有了后续那些思考。我也还有一些问题没有搞清楚,是关于后缀名的,我不太清楚为什么都是二进制文件,有的就要命名bin有的就要obj,猜测是window是根据后缀名来分配权限。相比来说linux这一点就完全不同,它不根据后缀名来区分文件,而是根据文件的权限来区分。