🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。
✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!
🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客
🔥温馨提示:划到文末发现专栏彩蛋 点击这里直接传送
🔥本篇概览:详细讲解了手写X86——第六节——加载OS.h.🌈⭕🔥
【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】
🔥 手写底层系列
🔥 手写X86系列
🌈章节引出:
前一篇章:手写X86——第五节——X86实模式下的编程介绍2(寄存器赋初值)-CSDN博客
前面篇章讲解了初始化过程,现在讲解如何加载剩余的OS.c进入内存。
🌈章节速览:
1.理论讲解:
接下来我们在这个启动代码start.S中加点代码,将os.c给拷贝到这个内存中去。这样我们的程序才能够跑。
这一块加载需要用到相关的硬件知识。我们知道os.c这块程序是放在这个磁盘上的。我们要从磁盘里面去读数据很麻烦,我们需要了解这个磁盘的相关的结构,还要了解怎么样去发相关的控制命令等等。所以我们可以简单一点。前面讲过这个BIOS实际上是上电以后就启动,并会负责对整个计算机进行检查,也会识别整个计算机相应的这个磁盘,那它还提供了一个功能,就是提供了相应的这个BIOS中断。
1.简单介绍一下BIOS中断
BIOS中断相当于在我们嵌入在BIOS中的库函数,可以理解为一个工具函数,这些函数提供了很多操作,比如说在屏幕上显示字符,直接帮我们读取硬盘等。我们可以直接调BIOS里面的工具函数,那就是利用BIOS里面的代码来将我后面这一大块OS.h代码读到内存中。
2.通过软中断指令int13完成调用BIOS库函数,实现读写
那这块代码究竟是位于BIOS哪个位置呢?
我们不知道,这个手册上也没有讲,因为BIOS的话,不同厂家,实现不太一样。所以这块代码究竟在哪里这个是没有一个规范的。但是我们可以通过软中断指令int13(X86汇编它这个机器它自带的一个软中断指令int指令)。我们可以加上一个数值,当我们这个CPU执行这个指令时,它就会跳到零地址处,它会有一个终端向量表,相当于一个数组,保存了很多函数的这个指针。当我们执行这个int13这一个指令的时候,它就会从这个终端向量表一个特定的位置去找到这个函数的指针,然后再通过这个指针去调用这个BIOS里面的代码。
3.硬件全自动执行
当然这个过程是自动的,并不需要我们自己去读这个中断向量表,然后去转到这里跳转。我们只需要执行int13这个指令,就可以了。硬件就会自动从去取相应的这个向量表的这个指针,然后跳转到BIOS里面相应的这个代码中去运行好。
这样的话我们就不需要知道这里面的这个磁盘读写相关的代码究竟在哪里,只需要执行这个指令就可以了。
4.通过寄存器传读取扇区等参数
此外需要告诉BIOS我们需要读取磁盘上哪一块位置,比方说我们现在是要从磁盘上的这个第二个扇区开始读取64个扇区。
究竟怎么去读呢?那我们就需要像这个代码去传递一些参数。我们C语言的函数参数都是通过内存去传递的,但BIOS的话他要求通过这个寄存器去传递,也就是我们在前面讲的这个编程模型。执行这个int13指令之前我们必须将相应的这些寄存器给它设置成相应的这个值,比方说将AH寄存器啊给它设置成这个2(第二个扇区),然后这个AL的话设置成这个要读取的这个扇区数。
设置完成之后,我们通过int13指令,就会调用BIOS里面的函数,然后BIOS里面的函数会从相应的寄存器去取相应的值,接着就开始读写磁盘了。
2.手动编码
1.设置寄存器读取参数捏:
读取的位置显然就是引导代码(起始0x7c00)后面的一块大小为512字节的区域。它的起始地址是0x7E0(0x7C00加上0x200(十进制512)).
需要告诉 BIOS,我们要读取的数据究竟应该放在哪里:
将读取的初始地址0X7E00,给到BX寄存器里面
mov $_start_32, %bx // 读取到的内存地址
将要读取的扇区号2,放在CX寄存器里面
mov $0x2, %cx // ch:磁道号,cl起始扇区号
读磁盘命令0x20+设置读扇区数0x40:
mov $0x0240, %ax // ah: 0x02读磁盘命令, al=0x40 64个扇区,多读一些, 32KB
0x80表示读第一块磁盘(早起还有软盘等,所以这里要设置)
(因为我们QEMU的话,目前只是只用了一块磁盘,所以我们在这里的话DX设置80就可以了)
mov $0x80, %dx // dh: 磁头号,dl驱动器号0x80(磁盘1)
读取失败的处理:
就是说如果读取失败的话它会将eflag寄存器里面的cf这个标志位置1,我们就可以通过JC判断一下CF标志位是否为1,如果是1,就说明有错误,那我们就让他重复的去读取磁盘,就是做一个死循环。
则这一整个大步后的代码如下:
// 计算机上电启动后,只取512字节到0x7c00处,即相当于自己只有个头在内存,所以下面全部出来
// 将自己的其余部分读取到0x7E00处,即0x7c00的后512字节
read_self_all:
mov $_start_32, %bx // 读取到的内存地址
mov $0x2, %cx // ch:磁道号,cl起始扇区号
mov $0x0240, %ax // ah: 0x02读磁盘命令, al=0x40 64个扇区,多读一些, 32KB
mov $0x80, %dx // dh: 磁头号,dl驱动器号0x80(磁盘1)
int $0x0013
jc read_self_all // 读取失败,则重复
jmp .
// 跳到引导标志, 由bios在上电后检查
.org 0x1fe // 引导标志
.byte 0x55, 0xaa
2.设置磁盘映像文件数据,便于检查
就是为了后面检查的时候方便,(就是说你怎么知道这一块的这个代码有执行成功呢),我们以16进制的方式打开image磁盘映像文件,所以我们在后面可以加一点点代码,这块代码编译完成之后,它会生成512字节的启动部分,我们可以往后面增加一些数据。如果后面的数据正确加载进内存中,那么说明我们的引导代码没有问题,但目前我们是没有这任何的C代码的。 我们使用填充指令填充后面的32kb数据:
_start_32:
.fill 64*1024, 1, 0x35 // 填充32KB,全为0x35
再次调试就发现写入内存成功了,说明引导成功!
至此,引导程序这块就正式完结了,我们可以添加正式的操作系统代码了!(也就是初始文件的OS.h)
我们下期见!!
💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖
热门专栏推荐
🌈🌈计算机科学入门系列 关注走一波💕💕
🌈🌈CSAPP深入理解计算机原理 关注走一波💕💕
🌈🌈微服务项目之黑马头条 关注走一波💕💕
🌈🌈redis深度项目之黑马点评 关注走一波💕💕
🌈🌈JAVA面试八股文系列专栏 关注走一波💕💕
🌈🌈JAVA基础试题集精讲 关注走一波💕💕
🌈🌈代码随想录精讲200题 关注走一波💕💕
总栏
🌈🌈JAVA基础要夯牢 关注走一波💕💕
🌈🌈JAVA后端技术栈 关注走一波💕💕
🌈🌈JAVA面试八股文 关注走一波💕💕
🌈🌈JAVA项目(含源码深度剖析) 关注走一波💕💕
🌈🌈计算机四件套 关注走一波💕💕
🌈🌈数据结构与算法 关注走一波💕💕
🌈🌈必知必会工具集 关注走一波💕💕
🌈🌈书籍网课笔记汇总 关注走一波💕💕
📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!