操作系统的引导
lab 1
环境:通过bochs虚拟机运行的linux0.11
0x7C00是BIOS将主引导扇区(第一个扇区)内容载入进内存的一个地址。操作系统或者引导程序必须假设他们的汇编代码从内存的0x7C00地址开始
task 1
更改系统启动的提示文字。
文件在boot/bootsect.s中。
直接用源码的这个文件在里面改也是可以的,也可以自己写一个如下内容的bootsect.s来进行实验,也是能正常运行。(记得备份)
|
|
|
|
因为ld86产生的是Minix可执行文件,该类型额外包括MInix可执行文件头部,结构如下
|
|
通过计算 char6(6 byte)+short1(2 byte)+long*6(24 byte)=32 byte,512+32=544.所以我们应该跳过bootsect的前32字节,再把他放入引导扇区中。
根据如下命令
|
|
将编译产生的Image文件复制到Linux-0.11目录下
|
|
综上,得到如下界面
bootsect.s是操作系统最开始的部分,共512个字节,再0磁道0扇区位置,读入内存0x7c00。
现在系统还在实模式下运行,物理地址=代码段cs*16+偏移,所以代码里写BOOTSEG=0x07c0才能得到0x7c00(这里的代码没用到)
bootsect.s和setup.s是为了完成将内核加载到内存,并跳转到内核执行而写的。bootsect.s是由BIOS加载到内存中,无法完成跳转到内核执行的任务。而setup.s就能完成进入32位模式并跳转到内核执行的任务,还可通过BIOS中断获取硬件信息的任务。
所以接着我们应该编写setup.s文件,让其输出提示该文件开始运行的字符串,再让其输出光标位置,内存大小和磁参数等硬件信息
task 2
首先输出字符串
我们直接将bootsect.s的代码复制过来,因为现在两者功能都是输出字符串。
但我们需要进行一些更改
|
|
上面是setup.s文件的内容,
此时我们还需要更改bootsect.s的内容让其能载入setup.s文件
我们需要确定setup所占用的扇区,bootsect.s只占用一个扇区,setup.s从下一个扇区开始,我们定义其占用两个(Linux0.11占用4个)。源码会将bootsect移动到0x9000处,此处我们不移动,所以bootsect.s在内存的0x7c00的位置,占512个字节,那么setup就载入0x7e00处,因为是实模式,所以逻辑地址应该为0x07e0.
bootsect.s代码如下
|
|
以上 bootsect.s和setup.s就完成,接着是通过makefile共同编译
指令如下
|
|
然后会得到报错
|
|
因为makefile会执行build.c,他要求命令行参数得到bootsect、setup和system内核的文件名。但我们只做了前两者,所以会报错,那我们直接将build.c第三个参数的部分代码注释掉即可。
如图所示。
接着再使用如下指令
|
|
将得到如下结果
task 3
接着在完善setup.s文件让其还能再输出光标位置,内存大小和磁盘参数的信息
我们将这些信息载入内存0x9000的位置
|
|
我们可以得到结果(我第一次试的时候不会弹两个窗口,但是第一次运行得到的数据出错)
第一次运行:
第二次运行
对第二次分析
memory size = 3c00KB+1MB=16MB
cylinders=00cc(H)=204(D)
一些问题:
首要问题 还是对汇编各种寄存器操作比较陌生,但还好慢慢啃,也能明白10%,知道基本的用法,需要抽时间好好学汇编。目前问题就是为什么有些寄存器能直接获得某些值,而不用赋值。不明白各种寄存器的用法和它本身会自己进行的操作有哪些。(提的问题也比较模糊,因为确实对汇编了解过少)例如为什么要把cs的值赋给es?之前也没有处理cs,他是代码寄存器,会默认存储代码段的地址吗?大概就是这类的问题。
之前提到一个问题就是 为什么在bootsect.s中 mov ds,0x0000 是控制磁盘,而在setup.s中mov ax,0x0000却是中断向量表的位置。 答案:前者的是在int 0x13 即BIOS中断上操作的0x0000是对某个寄存器设置相应的值来获得某种功能进而控制磁盘,不是内存地址的0x0000。而setup.s的0x0000是内存的地址。