初始化引导程序
基本概念
BIOS会将磁盘的第0个扇区(大小为512字节),加载到0x7c00处。
引导程序负责操作系统的加载,主要用于为操作系统运行提供初始化环境,并运行加载操作系统。
BIOS只加载磁盘的第0个扇区(512字节)到内存中,次程序无法做很多事情。
因此,我们可以采取以下两种方式种的任意一种。
X86在上电后,自动进入实模式,目的是为了兼容早期的应用程序。
X86与编程相关的主要内核寄存器
AX BX CX DX 是32位寄存器,在实模式的情况下,只能使用低16位寄存器。高16位寄存器是要留给切换到保护模式的。
CS DS SS ES FS GS 为段寄存器,为访问特定内存地址,需要采用段寄存器:偏移的形式。
8086 CPU 在实模式工作的情况下,内存映射。只能够访问1M的内存空间,如下图所示:
工程实战
进入start 示例工程
在source/boot/start.S 添加如下代码。
先build,然后F5启动调试,可以看到各个段寄存器都为 0X0。
按下F11进行单步进行调试。
可以看到进行单步调试前,esp寄存器为:0x6f00
单步调试到27行,esp寄存器就变为:0x7c00
使用BIOS中断显示字符
BIOS提供了一组服务,可以方便地帮助我们操作硬件,避免与硬件细节打交道。
当触发软中断的时,会自动从中断向量表中取相应的地址执行,参数通过寄存器传递。
使用BIOS中断读取字符
将引导程序分成2部分:
1.Boot只是做一些简单的工作,它的程序容量比较小,不超过512字节。
2.把更多的工作放在loader里面做。
BIOS提供了磁盘读取的接口,方便我们从磁盘上读取loader。
BIOS只加载磁盘的第0扇区(512字节)到内存中,此部分程序无法做很多事情。
INT13磁盘读取
然后build,
打开disk1.img磁盘镜像文件,可以看到 55 AA后面,是 E9 0E 开始。
-exec x /20bx 0x8000 ==> 20代表20个字节 b代表byte x代表十六进制
可以看到0x8000地址处的数据为 0xe9 0x0e 0x03 ... 和磁盘中的数据是一样的。说明磁盘的读取是成功的。
进入C语言环境并跳到loader
如果生成loader并写入磁盘映像?怎么样从boot跳转到loader执行呢?
主要流程为如下所示:
第一步:从汇编到C
在source/boot/start.S 目录下添加如下代码,加上断点调试可以进入 boot.c文件中的 这个函数boot_entry 。
然后在source/boot/ 目录下,新增loader文件夹,在loader文件夹下面添加start.S汇编文件,汇编文件的内容如下所示:
添加loader.h loader_16.c(16位实模式) loader_32.c(32位模式)
第二步:添加工程配置文件
首先在顶层的CMakeLists.txt 进行 add_subdirectory
第三步:添加函数指针进行跳转
利用内嵌汇编显示字符串
BIOS提供了一组服务,可以方便地帮助我们操作硬件,避免与硬件细节打交道。
在loader_16.c文件中,添加 show_msg 字符串显示函数,在17行加上断点,编译运行,可以看到:
为了防止汇编器对汇编代码进行优化,通常使用 __asm__ __volatile__
检测内存容量(1)
参考:检测内存容量 · 语雀
首先在source目录下新建comm文件夹,然后分别新建2个文件 types.h和 boot_info.h,这两个文件的内容分别如下所示:
在loader文件夹下的 loader.h 文件,添加对应的文件。
在loader目录下的 loader_16.c文件下,添加一个全局的 boot_info_t 变量。
检测内存容量(2)
未完待续....
切换进程保护模式(1)
CPU上电复位后默认进入实模式,这种模式下没有保护机制,但提供了BIOS服务。(相当于单片机)
与此同时,实模式下可以使用BIOS提供的各种服务接口。
保护模式为后面增加的功能,为操作系统以及应用程序的运行添加很多支持。
从实模式切换到保护模式,需要遵循一定的流程。
CPU流水线