05.进入保护模式前的最后一次折腾内存
上回书咱们说到,操作系统已经完成了各种从硬盘到内存的加载,以及内存到内存的复制。

至此,整个 bootsect.s 的使命就完成了,也是我们品读完的第一个操作系统源码文件。之后便跳转到了 0x90200 这个位置开始执行,这个位置处的代码就是位于 setup.s 的开头,我们接着来看。
| |
又有个 int 指令。
前面的文章好好看过的话,一下就能猜出它要干嘛。还记不记得之前有个 int 0x13表示触发 BIOS 提供的读磁盘中断程序?这个 int 0x10也是一样的,它也是触发 BIOS 提供的显示服务中断处理程序,而 ah 寄存器被赋值为 0x03 表示显示服务里具体的读取光标位置功能。
具体 BIOS 提供了哪些中断服务,如何去调用和获取返回值,请大家自行寻找资料,这里只说结果。
这个 int 0x10 中断程序执行完毕并返回时,dx 寄存器里的值表示光标的位置,具体说来其高八位 dh 存储了行号,低八位 dl 存储了列号。

这里说明一下:计算机在加电自检后会自动初始化到文字模式,在这种模式下,一屏幕可以显示 25 行,每行 80 个字符,也就是 80 列。
那下一步 mov [0],dx 就是把这个光标位置存储在 [0] 这个内存地址处。
注意,前面我们说过,这个内存地址仅仅是偏移地址,还需要加上 ds 这个寄存器里存储的段基址,最终的内存地址是在 0x90000 处,这里存放着光标的位置,以便之后在初始化控制台的时候用到。
所以从这里也可以看出,这和我们平时调用一个方法没什么区别,只不过这里的寄存器的用法相当于入参和返回值,这里的 0x10 中断号相当于方法名。
这里又应了之前说的一句话,操作系统内核的最开始也处处都是 BIOS 的调包侠,有现成的就用呗。
再接下来的几行代码,都是和刚刚一样的逻辑,调用一个 BIOS 中断获取点什么信息,然后存储在内存中某个位置,我们迅速浏览一下就好咯。
| |
以上原理都是一样的。
| 内存地址 | 长度(字节) | 名称 |
|---|---|---|
| 0x90000 | 2 | 光标位置 |
| 0x90002 | 2 | 扩展内存数 |
| 0x90004 | 2 | 显示页面 |
| 0x90006 | 1 | 显示模式 |
| 0x90007 | 1 | 字符列数 |
| 0x90008 | 2 | 未知 |
| 0x9000A | 1 | 显示内存 |
| 0x9000B | 1 | 显示状态 |
| 0x9000C | 2 | 显卡特性参数 |
| 0x9000E | 1 | 屏幕行数 |
| 0x9000F | 1 | 屏幕列数 |
| 0x90080 | 16 | 硬盘1参数表 |
| 0x90090 | 16 | 硬盘2参数表 |
| 0x901FC | 2 | 根设备号 |
由于之后很快就会用 c 语言进行编程,虽然汇编和 c 语言也可以用变量的形式进行传递数据,但这需要编译器在链接时做一些额外的工作,所以这么多数据更方便的还是双方共同约定一个内存地址,我往这里存,你从这里取,就完事了。这恐怕是最最原始和直观的变量传递的方式了。
把这些信息存储好之后,操作系统又要做什么呢?我们继续往下看。
| |
就一行 cli,表示关闭中断的意思。
因为后面我们要把原本是 BIOS 写好的中断向量表给覆盖掉,也就是给破坏掉了,写上我们自己的中断向量表,所以这个时候是不允许中断进来的。继续看。
| |
看到后面那个 rep movsw 熟不熟悉,一开始我们把操作系统代码从 0x7c00 移动到 0x90000 的时候就是用的这个指令,来图回忆一下。

同前面的原理一样,也是做了个内存复制操作,最终的结果是,把内存地址 0x10000 处开始往后一直到 0x90000 的内容,统统复制到内存的最开始的 0 位置,大概就是这么个效果。

由于之前的各种加载和复制,导致内存看起来很乱,是时候进行一波取舍和整理了,我们重新梳理一下此时的内存布局。
栈顶地址仍然是 0x9FF00 没有改变。
0x90000 开始往上的位置,原来是 bootsect 和 setup 程序的代码,现 bootsect 的一部分代码在已经被操作系统为了记录内存、硬盘、显卡等一些临时存放的数据给覆盖了一部分。
内存最开始的 0 到 0x80000 这 512K 被 system 模块给占用了,之前讲过,这个 system 模块就是除了 bootsect 和 setup 之外的全部程序链接在一起的结果,可以理解为操作系统的全部。
那么现在的内存布局就是这个样子。

好了,记住上面的图就好了,这回是不是又重新清晰起来了?之前的什么 0x7c00,已经是过去式了,赶紧忘掉它,向前看!
接下来,就要进行有点技术含量的工作了,那就是模式的转换,需要从现在的 16 位的实模式转变为之后 32 位的保护模式,这是一项大工程!也是我认为的这趟操作系统源码旅程中,第一个颇为精彩的地方,大家做好准备!