---- 整理自狄泰软件唐佐林老师课程
查看所有文章链接:(更新中)深入浅出操作系统 - 目录
文章目录
1. 整体设计
汇编 | 汇编 | 汇编 + C语言 | ||
---|---|---|---|---|
BOOT | 加载 ==> | LOADER | 加载 ==> | KERNEL |
512字节内完成 加载 loader 的功能,并跳转到loader执行 | 在实模式下完成 加载 kernel 的功能;通过BIOS获取硬件信息;进入保护模式之后 跳转到kernel执行 | 运行于32位保护模式,实现操作系统内核模块 |
1.1 问题
- 为什么不能从boot直接加载kernel,并跳转运行?
1.2 设计思路
- boot 必须小于512字节,无法完成多功能
- kernel 需要运行于32位保护模式(汇编 + C语言)
- 使用 loader 中转:获取必要硬件信息,进入保护模式
1.3 实验:抽象文件加载函数
【参看链接】:40 - 从bootloader到内核雏形 / 40 / 00 / boot.asm
1.4 bootloader重构方案
1.4.1 文件功能定义
文件名 | 功能定义 |
---|---|
common.asm | 常量定义,宏定义 |
blfunc.asm | 实模式下文件加载相关功能的定义 |
boot.asm | 加载loader并跳转 |
loader.asm | 1. 必要硬件初始化 2. 加载kernel 3. 进入保护模式 4. 跳转到kernel执行 |
1.4.2 blfunc.asm接口设计
1.4.3 实验:NO KERNEL
【参看链接】:40 - 从bootloader到内核雏形 / 40 / 01
1.4.4 blfunc.asm注意事项
- %include “blfunc.asm” 必须是第一条“包含语句”
- %include “blfunc.asm” 强制从 BLMain标签处 开始执行
- Buffer为必要的内存缓冲区,必须在代码末尾定义
1.4.5 bootloader重构
【参看链接】:40 - 从bootloader到内核雏形 / 40 / 02
1.5 内核雏形构造
1.5.1 问题
- kernel.out 加载进内存后能直接被x86处理器运行吗?
- 不能。
- 原因分析:
- kernel.out 是Linux系统中的可执行程序
- 而Linux中的可执行程序为 elf 格式的文件(固定数据格式)
- 处理器只“认得”代码和数据,无法正确执行 elf 可执行程序
1.5.2 方案设计
- 提取 elf 文件中的代码段和数据段(删除 elf 文件格式信息)
- 重定位提取后的代码段和数据段,得到内核文件
- 加载内核文件到内存(起始地址可自定义)
- 跳转到内核入口地址处执行
1.5.3 elf2kobj介绍(唐老师写的工具)
1.5.4 解决方案
nasm -f elf kentry.asm -o objs/kentry.o
CFLAGS := -fnobuiltin -fno-stack-protector
gcc $(CFLAGS) -c kmain.c -o objs/kmain.o
ld -s objs/kentry.o objs/kmain.o -o exes/kernel.out
./elf2kobj -cB000 exes/kernel.out kernel
(kernel将被加载到内存地址0xB000处)
1.5.5 编程实验:内核雏形构建
【参看链接】:40 - 从bootloader到内核雏形 / 40 / 03
2. 小结
- 使用nasm和gcc编译得到的是 elf 目标文件
- ld 将 elf 目标文件装配成为 elf 可执行程序
- 使用 elf2kobj 将 elf 可执行程序转换为内核文件
- 在实模式下加载转换得到的内核文件
- 进入保护模式后执行跳转到内核起始位置处执行