feat(mm): parse UEFI memory map in kernel
This commit is contained in:
parent
f60b6af52f
commit
62c8836886
252
README.md
252
README.md
@ -1,230 +1,72 @@
|
||||
# Tianole
|
||||
|
||||
新的起点。这个仓库现在不保留旧实现,先把目标机器、开发环境、技术路线和最小步骤固定下来,避免再次在错误方向上堆代码。
|
||||
Tianole 是一个面向 `UEFI x86_64` 机器的自制操作系统项目。
|
||||
|
||||
## 当前结论
|
||||
当前目标不是一次性做“大而全”的系统,而是按 Linux 风格的分层思路,逐步把启动链、内核基础设施、用户态和文件系统建立起来,最终能在真机上安全启动,并逐步具备运行本地 `git` 的能力。
|
||||
|
||||
- 语言:第一版用 `C`
|
||||
- 架构:`x86_64`
|
||||
- 启动方式:`UEFI`
|
||||
- 主开发环境:`WSL2`
|
||||
- 日常验证:先 `QEMU + OVMF`
|
||||
- 真机验证:先 `U 盘 UEFI` 启动
|
||||
- 最终目标:在自己的笔记本上以独立启动项或可控方式启动,不先破坏现有 `Windows 11 + Linux Mint + GRUB`
|
||||
## 当前状态
|
||||
|
||||
## 为什么现在不用旧代码
|
||||
- 已跑通 `QEMU + OVMF` 下的最小 `UEFI` 启动链
|
||||
- 已拆分为 `bootloader + kernel`
|
||||
- `bootloader` 已能加载独立 `kernel.elf`
|
||||
- `kernel_main()` 已能实际执行
|
||||
|
||||
旧实现的问题不是“有几个 bug”,而是路线已经和目标真机错位:
|
||||
|
||||
- 旧项目是 `32位 + Multiboot + GRUB + qemu-system-i386`
|
||||
- 你的目标机器是现代 `UEFI + GPT + x86_64`
|
||||
- 旧项目已经铺到任务、FAT16、ATA PIO、用户态切换,但底座仍是老 PC 路线
|
||||
- 继续修补会持续消耗精力在错误底座上
|
||||
|
||||
所以现在直接重开,比在旧代码上修修补补更省。
|
||||
|
||||
## 这台机器已经确认的信息
|
||||
|
||||
- 当前日期环境:`2026-05-08`
|
||||
- 机器:`LENOVO 21HX`
|
||||
- CPU:`13th Gen Intel Core i5-13500H`
|
||||
- 核心/线程:`12` 核 `16` 线程
|
||||
- 内存:`16 GB`
|
||||
- 显卡:`Intel Iris Xe Graphics`
|
||||
- 磁盘:`1 TB NVMe SSD`
|
||||
- 固件模式:`UEFI`
|
||||
- 分区表:`GPT`
|
||||
- BIOS 版本:`LBCN26WW`
|
||||
- BIOS 日期:`2024-08-23`
|
||||
- 当前系统状态:你现在在 `Windows 11`,机器上同时有 `Linux Mint`
|
||||
- 启动情况:GRUB 由 `Mint` 管理,你现在只是从该多启动环境进入了 Windows
|
||||
- 额外观察:系统报告 `HypervisorPresent = True`
|
||||
- 未确认项:`Secure Boot` 状态未成功读出,后续真机启动自制 OS 时必须单独检查
|
||||
|
||||
## 这些信息意味着什么
|
||||
|
||||
- 不要走 `BIOS + MBR + 16位 boot sector` 教程路线
|
||||
- 不要再把 `32位` 当主线
|
||||
- 第一阶段不要碰真实 GPU 驱动,先用 `UEFI GOP framebuffer`
|
||||
- 第一阶段不要碰真实 `NVMe` 驱动
|
||||
- 第一阶段不要急着做复杂用户态
|
||||
- 真机阶段不要一开始去改现有 `GRUB` 或覆盖 EFI 启动链
|
||||
|
||||
## 为什么现在选 C,不选 Rust
|
||||
|
||||
你的条件是:
|
||||
|
||||
- 想长期做
|
||||
- 但会断断续续
|
||||
- 目标是最后装到自己的真机
|
||||
- 设计思路参考 Linux
|
||||
|
||||
在这个组合下,`C + x86_64 + UEFI` 的阻力最低。
|
||||
|
||||
原因:
|
||||
|
||||
- 回坑成本低
|
||||
- Linux 资料、历史实现、底层文档更贴近 C
|
||||
- 你要适配的核心问题是 `UEFI / GPT / framebuffer / 内存管理 / 中断`,不是语言特性
|
||||
- Rust 不是不能做,但更容易把精力花在 `no_std`、启动框架和抽象边界上
|
||||
|
||||
结论:
|
||||
|
||||
- 第一版内核主体:`C`
|
||||
- 少量汇编:只保留最必要的入口和极少数底层切换
|
||||
- 以后如果需要,再局部引入 Rust
|
||||
|
||||
## 为什么用 WSL2
|
||||
|
||||
主开发环境建议:
|
||||
|
||||
- `WSL2 + Ubuntu`
|
||||
|
||||
原因:
|
||||
|
||||
- `gcc/clang`
|
||||
- `make`
|
||||
- `nasm`
|
||||
- `lld`
|
||||
- `objdump/readelf`
|
||||
- `qemu`
|
||||
- `mtools`
|
||||
- `ovmf`
|
||||
|
||||
这套工具在 Linux 环境里更顺,资料也基本默认 Linux。
|
||||
|
||||
Windows 仍然保留这些职责:
|
||||
|
||||
- 日常文件管理
|
||||
- 处理下载
|
||||
- 需要时管理 U 盘
|
||||
- 重启进入 BIOS/启动菜单
|
||||
- 真机测试前的辅助操作
|
||||
|
||||
长期工作流:
|
||||
|
||||
1. 在 `WSL2` 中写代码、编译、跑 `QEMU`
|
||||
2. 需要更底层的镜像/介质实验时,可以切去 `Mint`
|
||||
3. 真机验证优先走 `U 盘 UEFI` 启动
|
||||
4. 系统稳定后,再决定是否集成进本机磁盘启动项
|
||||
|
||||
## 目标路线
|
||||
|
||||
第一阶段只做最小系统:
|
||||
|
||||
1. `UEFI` 启动成功
|
||||
2. 获取内存映射
|
||||
3. 初始化 `framebuffer`
|
||||
4. 屏幕输出
|
||||
5. 建立基础页表
|
||||
6. 基础中断框架
|
||||
7. 一个极简内核循环
|
||||
|
||||
这一阶段完成后,再考虑:
|
||||
|
||||
1. 物理内存分配器
|
||||
2. 简单堆分配
|
||||
3. 键盘输入
|
||||
4. 简单 shell
|
||||
5. ELF 加载
|
||||
6. 用户态
|
||||
7. 文件系统
|
||||
|
||||
## WSL2 中建议的基础环境
|
||||
|
||||
以 Ubuntu 为例:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
build-essential \
|
||||
clang \
|
||||
lld \
|
||||
nasm \
|
||||
make \
|
||||
cmake \
|
||||
qemu-system-x86 \
|
||||
ovmf \
|
||||
mtools \
|
||||
dosfstools \
|
||||
gdisk \
|
||||
xorriso \
|
||||
gdb \
|
||||
python3
|
||||
```
|
||||
|
||||
可选检查:
|
||||
|
||||
```bash
|
||||
gcc --version
|
||||
clang --version
|
||||
ld.lld --version
|
||||
nasm -v
|
||||
qemu-system-x86_64 --version
|
||||
```
|
||||
|
||||
## 新仓库的起步步骤
|
||||
|
||||
切到 `WSL` 后,建议按这个顺序开始:
|
||||
|
||||
1. 在 `WSL` 中打开这个仓库
|
||||
2. 保持仓库目标单纯,只做 `C + UEFI + x86_64`
|
||||
3. 先搭最小目录结构
|
||||
4. 先让一个最小 `UEFI` 程序在 `QEMU + OVMF` 下跑起来
|
||||
5. 再把它拆成 `bootloader / kernel` 或直接决定最小加载方案
|
||||
6. 先证明启动链可控,再扩内核
|
||||
|
||||
## 建议的最小目录结构
|
||||
|
||||
第一版建议从非常小的结构开始:
|
||||
## 当前目录
|
||||
|
||||
```text
|
||||
tianole/
|
||||
README.md
|
||||
.gitignore
|
||||
AGENTS.md
|
||||
Makefile
|
||||
boot/
|
||||
kernel/
|
||||
arch/
|
||||
docs/
|
||||
include/
|
||||
kernel/
|
||||
scripts/
|
||||
build/
|
||||
```
|
||||
|
||||
先不要一开始就拆出:
|
||||
当前还没有直接复制 Linux 的完整目录树,但已经开始按接近 Linux 的方式分层:
|
||||
|
||||
- `fs/`
|
||||
- `drivers/`
|
||||
- `mm/`
|
||||
- `userland/`
|
||||
- `lib/`
|
||||
- `arch/`:架构相关代码
|
||||
- `kernel/`:通用内核主体逐步放这里
|
||||
- `include/tianole/`:项目自有共享接口
|
||||
- `docs/`:正式设计和路线图
|
||||
|
||||
等真正需要时再拆,不要先造目录架子。
|
||||
## 开发顺序
|
||||
|
||||
## 真机测试原则
|
||||
当前建议的实现顺序是:
|
||||
|
||||
你这台机器是 `Windows 11 + Linux Mint` 双系统,并且已有 `GRUB` 启动环境,所以真机测试要克制:
|
||||
1. 启动链
|
||||
2. 早期调试输出
|
||||
3. 内存与异常基础
|
||||
4. 执行流与调度
|
||||
5. 用户态入口
|
||||
6. 文件系统与存储
|
||||
7. shell / 工具
|
||||
8. 面向 `git` 的补齐
|
||||
9. 真机落地
|
||||
|
||||
1. 第一阶段只在 `QEMU + OVMF` 验证
|
||||
2. 第二阶段只从 `U 盘` 启动
|
||||
3. 第三阶段再考虑新增 UEFI 启动项
|
||||
4. 不要一开始改当前磁盘上的 `GRUB` 配置
|
||||
5. 不要一开始尝试覆盖现有 EFI 分区中的关键文件
|
||||
更细的阶段说明见:
|
||||
|
||||
## 当前最重要的技术边界
|
||||
- [docs/roadmap.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/roadmap.md)
|
||||
|
||||
- 做现代 PC,不做老式 BIOS 教程项目
|
||||
- 先做可启动、可显示、可调试
|
||||
- 先不要做“看起来很完整”的模块铺设
|
||||
- 先把启动链做对,再谈进程、文件系统、用户态
|
||||
- 任何新代码都要服务于真机 `UEFI x86_64` 目标
|
||||
## 构建与运行
|
||||
|
||||
## 下一步
|
||||
在 WSL2 / Ubuntu 中:
|
||||
|
||||
切到 `WSL` 后,下一步不是继续讨论语言,而是直接开始搭最小骨架:
|
||||
```bash
|
||||
make
|
||||
make run
|
||||
```
|
||||
|
||||
1. 建立 `Makefile`
|
||||
2. 建立最小 `boot/` 与 `kernel/`
|
||||
3. 跑通 `QEMU + OVMF`
|
||||
4. 在屏幕上输出一行可见文本
|
||||
无界面调试:
|
||||
|
||||
做到这一步后,再继续扩展。
|
||||
```bash
|
||||
make run-headless
|
||||
cat build/debug.log
|
||||
```
|
||||
|
||||
## 文档
|
||||
|
||||
- 路线图:[docs/roadmap.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/roadmap.md)
|
||||
- 本机环境与真机启动约束:[docs/host-machine.md](//wsl.localhost/Ubuntu/home/indole/tianole/docs/host-machine.md)
|
||||
- agent 入口:[AGENTS.md](//wsl.localhost/Ubuntu/home/indole/tianole/AGENTS.md)
|
||||
|
||||
@ -49,6 +49,27 @@ static void mem_zero(void *dst, uint64_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
void *memset(void *dst, int value, __SIZE_TYPE__ size) {
|
||||
uint8_t *out = (uint8_t *)dst;
|
||||
__SIZE_TYPE__ i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
out[i] = (uint8_t)value;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void debug_put_hex64(uint64_t value) {
|
||||
static const char digits[] = "0123456789abcdef";
|
||||
int shift;
|
||||
|
||||
debug_puts("0x");
|
||||
for (shift = 60; shift >= 0; shift -= 4) {
|
||||
debug_putc(digits[(value >> shift) & 0xf]);
|
||||
}
|
||||
}
|
||||
|
||||
static efi_status open_root(
|
||||
efi_handle image_handle,
|
||||
efi_system_table_t *system_table,
|
||||
@ -222,6 +243,63 @@ static efi_status load_kernel_image(
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static efi_status fetch_memory_map(
|
||||
efi_system_table_t *system_table,
|
||||
tianole_boot_info_t *boot_info
|
||||
) {
|
||||
tianole_efi_memory_descriptor_t *memory_map;
|
||||
efi_uintn_t memory_map_size;
|
||||
efi_uintn_t map_key;
|
||||
efi_uintn_t descriptor_size;
|
||||
uint32_t descriptor_version;
|
||||
efi_status status;
|
||||
|
||||
memory_map_size = 0;
|
||||
map_key = 0;
|
||||
descriptor_size = 0;
|
||||
descriptor_version = 0;
|
||||
status = system_table->boot_services->get_memory_map(
|
||||
&memory_map_size,
|
||||
0,
|
||||
&map_key,
|
||||
&descriptor_size,
|
||||
&descriptor_version
|
||||
);
|
||||
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||
return status;
|
||||
}
|
||||
|
||||
memory_map_size += descriptor_size * 8;
|
||||
status = system_table->boot_services->allocate_pool(
|
||||
EFI_LOADER_DATA,
|
||||
memory_map_size,
|
||||
(void **)&memory_map
|
||||
);
|
||||
if (status != EFI_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = system_table->boot_services->get_memory_map(
|
||||
&memory_map_size,
|
||||
memory_map,
|
||||
&map_key,
|
||||
&descriptor_size,
|
||||
&descriptor_version
|
||||
);
|
||||
if (status != EFI_SUCCESS) {
|
||||
system_table->boot_services->free_pool(memory_map);
|
||||
return status;
|
||||
}
|
||||
|
||||
boot_info->memory_map = (uint64_t)(uintptr_t)memory_map;
|
||||
boot_info->memory_map_size = memory_map_size;
|
||||
boot_info->memory_map_key = map_key;
|
||||
boot_info->memory_descriptor_size = descriptor_size;
|
||||
boot_info->memory_descriptor_version = descriptor_version;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
efi_status EFIAPI efi_main(efi_handle image_handle, efi_system_table_t *system_table) {
|
||||
efi_file_protocol_t *root;
|
||||
void *kernel_image;
|
||||
@ -255,6 +333,19 @@ efi_status EFIAPI efi_main(efi_handle image_handle, efi_system_table_t *system_t
|
||||
return status;
|
||||
}
|
||||
|
||||
status = fetch_memory_map(system_table, &boot_info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
debug_puts("failed: fetch memory map\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
debug_puts("memory_map descriptors_size=");
|
||||
debug_put_hex64(boot_info.memory_descriptor_size);
|
||||
debug_puts("\n");
|
||||
debug_puts("memory_map size=");
|
||||
debug_put_hex64(boot_info.memory_map_size);
|
||||
debug_puts("\n");
|
||||
|
||||
debug_puts("jumping to kernel entry\n");
|
||||
kernel_entry(&boot_info);
|
||||
|
||||
|
||||
@ -141,13 +141,19 @@ struct efi_boot_services {
|
||||
efi_physical_address_t *memory
|
||||
);
|
||||
void *free_pages;
|
||||
void *get_memory_map;
|
||||
efi_status(EFIAPI *get_memory_map)(
|
||||
efi_uintn_t *memory_map_size,
|
||||
void *memory_map,
|
||||
efi_uintn_t *map_key,
|
||||
efi_uintn_t *descriptor_size,
|
||||
uint32_t *descriptor_version
|
||||
);
|
||||
efi_status(EFIAPI *allocate_pool)(
|
||||
int pool_type,
|
||||
efi_uintn_t size,
|
||||
void **buffer
|
||||
);
|
||||
void *free_pool;
|
||||
efi_status(EFIAPI *free_pool)(void *buffer);
|
||||
void *create_event;
|
||||
void *set_timer;
|
||||
void *wait_for_event;
|
||||
|
||||
75
docs/host-machine.md
Normal file
75
docs/host-machine.md
Normal file
@ -0,0 +1,75 @@
|
||||
# 本机环境与真机启动约束
|
||||
|
||||
这个文档记录 Tianole 未来在本机落地时必须考虑的环境信息。它不属于 README 首页内容,但对后续真机启动、U 盘验证、启动项接入很重要。
|
||||
|
||||
## 机器信息
|
||||
|
||||
- 日期环境:`2026-05-08`
|
||||
- 机器:`LENOVO 21HX`
|
||||
- CPU:`13th Gen Intel Core i5-13500H`
|
||||
- 核心 / 线程:`12` 核 `16` 线程
|
||||
- 内存:`16 GB`
|
||||
- 显卡:`Intel Iris Xe Graphics`
|
||||
- 磁盘:`1 TB NVMe SSD`
|
||||
|
||||
## 固件与启动环境
|
||||
|
||||
- 固件模式:`UEFI`
|
||||
- 分区表:`GPT`
|
||||
- BIOS 版本:`LBCN26WW`
|
||||
- BIOS 日期:`2024-08-23`
|
||||
- 当前系统状态:本机有 `Windows 11` 与 `Linux Mint`
|
||||
- 启动情况:当前多启动由 `Mint` 的 `GRUB` 管理
|
||||
- 额外观察:系统报告 `HypervisorPresent = True`
|
||||
- 未确认项:`Secure Boot` 状态仍需单独确认
|
||||
|
||||
## 这些信息意味着什么
|
||||
|
||||
- 不走 `BIOS + MBR + 16-bit boot sector` 路线
|
||||
- 不把 `32-bit` 作为主线
|
||||
- 第一阶段不碰真实 GPU 驱动,先依赖 `UEFI GOP framebuffer`
|
||||
- 第一阶段不碰真实 `NVMe` 驱动
|
||||
- 真机阶段不应一开始改写现有 `GRUB`
|
||||
- 真机阶段不应一开始覆盖现有 EFI 分区中的关键文件
|
||||
|
||||
## 真机验证原则
|
||||
|
||||
1. 第一阶段只在 `QEMU + OVMF` 下验证
|
||||
2. 第二阶段优先用 `U 盘 UEFI` 启动验证
|
||||
3. 第三阶段再考虑新增本机 UEFI 启动项
|
||||
4. 在系统稳定前,不改写现有系统磁盘启动链
|
||||
|
||||
## 开发环境
|
||||
|
||||
主开发环境建议:
|
||||
|
||||
- `WSL2 + Ubuntu`
|
||||
|
||||
推荐工具:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
build-essential \
|
||||
clang \
|
||||
lld \
|
||||
nasm \
|
||||
make \
|
||||
cmake \
|
||||
qemu-system-x86 \
|
||||
ovmf \
|
||||
mtools \
|
||||
dosfstools \
|
||||
gdisk \
|
||||
xorriso \
|
||||
gdb \
|
||||
python3
|
||||
```
|
||||
|
||||
Windows 侧主要承担:
|
||||
|
||||
- 日常文件管理
|
||||
- 下载与资料整理
|
||||
- U 盘管理
|
||||
- BIOS / 启动菜单辅助操作
|
||||
- 真机测试前准备
|
||||
129
docs/roadmap.md
129
docs/roadmap.md
@ -1,77 +1,57 @@
|
||||
# Tianole 路线图
|
||||
|
||||
## 第 0 阶段
|
||||
## 总原则
|
||||
|
||||
- 建立最小 `UEFI` 启动程序。
|
||||
- 在 `QEMU + OVMF` 下运行。
|
||||
- 在屏幕和 `debug.log` 中输出可见的启动标记。
|
||||
- 保证启动后常驻,便于后续调试。
|
||||
这个项目按“可中断、可回坑、每一阶段都能单独验收”的方式推进。
|
||||
|
||||
## 第 1 阶段
|
||||
目标不是只在虚拟机里亮屏,而是:
|
||||
|
||||
- 把当前单体启动程序拆成 `boot/` 与 `kernel/`。
|
||||
- 定义 `boot_info` 交接结构。
|
||||
- 由 `bootloader` 加载独立 `kernel` 映像。
|
||||
- 跳转到 `kernel` 入口并建立稳定栈。
|
||||
- 在 `UEFI x86_64` 真机上独立启动
|
||||
- 逐步具备完整内核基础设施
|
||||
- 逐步具备运行本地 `git` 的能力
|
||||
|
||||
## 第 2 阶段
|
||||
这里参考 Linux 的是分层思路和演进顺序,不是照搬早期 Linux 的启动方式或目录树。
|
||||
|
||||
- 获取 `UEFI memory map`。
|
||||
- 正确执行 `ExitBootServices`。
|
||||
- 建立最小 framebuffer 控制台。
|
||||
- 开始做物理内存管理。
|
||||
## 推荐开发顺序
|
||||
|
||||
## 第 3 阶段
|
||||
|
||||
- 建立 `IDT` 和基础异常处理。
|
||||
- 增加定时器来源。
|
||||
- 开始早期 `ACPI` 解析。
|
||||
- 逐步过渡到接近 Linux 风格的 `arch/`、`mm/`、`kernel/` 边界。
|
||||
|
||||
## 总体流程
|
||||
|
||||
这个项目要按“可中断、可回坑、每一阶段都能单独验收”的方式推进。最终目标不是只在虚拟机里亮屏,而是要在这台 `UEFI x86_64` 笔记本上独立启动,并逐步具备运行本地 `git` 的能力。
|
||||
|
||||
建议的长期阶段如下:
|
||||
|
||||
### 阶段 A:启动链
|
||||
### 1. 启动链
|
||||
|
||||
- 跑通 `UEFI app -> bootloader -> kernel`
|
||||
- 保证 `kernel_main()` 真正开始执行
|
||||
- 保证屏幕或串口可见输出
|
||||
- 保证最小可见输出
|
||||
|
||||
完成标志:
|
||||
|
||||
- `bootloader` 成功把控制权交给独立 `kernel`
|
||||
- `kernel` 能输出第一行字并停住
|
||||
|
||||
### 阶段 B:早期内核基础
|
||||
### 2. 早期调试输出
|
||||
|
||||
- 定义 `boot_info`
|
||||
- 获取 `memory map`
|
||||
- 正确执行 `ExitBootServices`
|
||||
- 建立 early console
|
||||
- 建立最小 panic / assert / log
|
||||
- 保留当前 `debug` 输出路径
|
||||
- 增加 early serial log
|
||||
- 为后续脱离固件后的调试做准备
|
||||
|
||||
完成标志:
|
||||
|
||||
- 退出 UEFI 后内核仍能稳定运行
|
||||
- 崩溃时能给出可定位信息
|
||||
- 内核在更早阶段也能稳定输出日志
|
||||
|
||||
### 阶段 C:内存与异常
|
||||
### 3. 内存与异常基础
|
||||
|
||||
- 建立物理页分配器
|
||||
- 建立内核堆分配器
|
||||
- 获取 `UEFI memory map`
|
||||
- 正确执行 `ExitBootServices`
|
||||
- 建立 `GDT/IDT`
|
||||
- 处理基础异常
|
||||
- 增加基础异常处理
|
||||
- 建立物理页分配器
|
||||
- 建立内核堆
|
||||
- 增加定时器
|
||||
|
||||
完成标志:
|
||||
|
||||
- 能稳定分配页和堆内存
|
||||
- 退出 UEFI 后内核仍稳定运行
|
||||
- 关键异常能进入处理路径
|
||||
- 内核能稳定分配页和堆内存
|
||||
|
||||
### 阶段 D:任务模型
|
||||
### 4. 执行流与调度
|
||||
|
||||
- 建立内核线程
|
||||
- 建立调度器
|
||||
@ -83,11 +63,11 @@
|
||||
- 可以同时运行多个内核线程
|
||||
- 调度由时钟驱动
|
||||
|
||||
### 阶段 E:用户态基础
|
||||
### 5. 用户态入口
|
||||
|
||||
- 建立用户地址空间
|
||||
- 增加系统调用入口
|
||||
- 增加 ELF 加载
|
||||
- 增加 ELF 用户程序加载
|
||||
- 增加进程创建和等待
|
||||
|
||||
完成标志:
|
||||
@ -95,7 +75,7 @@
|
||||
- 能加载并运行最小用户程序
|
||||
- 用户程序能调用系统调用输出
|
||||
|
||||
### 阶段 F:存储与文件系统
|
||||
### 6. 文件系统与存储
|
||||
|
||||
- 建立块设备层
|
||||
- 建立 `VFS`
|
||||
@ -107,7 +87,7 @@
|
||||
- 能挂载文件系统
|
||||
- 能打开、读取、写入文件
|
||||
|
||||
### 阶段 G:最小用户空间
|
||||
### 7. shell 与基础工具
|
||||
|
||||
- 增加 `init`
|
||||
- 增加简单 shell
|
||||
@ -119,9 +99,10 @@
|
||||
- 启动后能进入 shell
|
||||
- 能执行几个基础程序
|
||||
|
||||
### 阶段 H:面向 git 的补齐
|
||||
### 8. 面向 git 的补齐
|
||||
|
||||
- 优先支持本地 `git`,不先碰网络
|
||||
- 优先支持本地 `git`
|
||||
- 不先碰网络协议栈
|
||||
- 补足 `git` 依赖的文件、进程、时间、路径等接口
|
||||
- 先以 `git init / status / add / commit` 为目标
|
||||
|
||||
@ -129,7 +110,7 @@
|
||||
|
||||
- 能运行本地仓库的基础 `git` 操作
|
||||
|
||||
### 阶段 I:真机落地
|
||||
### 9. 真机落地
|
||||
|
||||
- 先 `QEMU + OVMF`
|
||||
- 再 `U 盘 UEFI` 启动
|
||||
@ -137,31 +118,25 @@
|
||||
|
||||
完成标志:
|
||||
|
||||
- 不破坏现有 `Windows 11 + Linux Mint + GRUB`
|
||||
- 不破坏现有本机启动链
|
||||
- 能在真机上独立启动并进入系统
|
||||
|
||||
## 当前所处阶段
|
||||
## 当前进度
|
||||
|
||||
当前只完成了第 0 阶段的最小成果:
|
||||
当前已经完成:
|
||||
|
||||
- `UEFI` 启动程序可构建
|
||||
- `QEMU + OVMF` 能执行它
|
||||
- 屏幕和 `debug.log` 有可见输出
|
||||
- 程序可常驻,便于调试
|
||||
|
||||
当前已经开始进入第 1 阶段:
|
||||
|
||||
- 代码结构已经为 `bootloader -> kernel` 交接预留边界
|
||||
- `boot_info` 已经作为项目自有交接结构存在
|
||||
- `arch/x86/` 已经承载当前架构专用启动代码
|
||||
- 最小 `UEFI` 启动链
|
||||
- `bootloader + kernel` 拆分
|
||||
- 独立 `kernel.elf` 加载
|
||||
- `kernel_main()` 实际执行
|
||||
- `memory map` 已通过 `boot_info` 传递,并能在 kernel 中统计描述符与可用页数
|
||||
|
||||
当前还没有完成:
|
||||
|
||||
- 独立 `kernel` 接管
|
||||
- `bootloader -> kernel` 交接
|
||||
- `memory map`
|
||||
- `ExitBootServices`
|
||||
- 真正的内核子系统
|
||||
- early serial log
|
||||
- framebuffer console
|
||||
- 真正的内存管理和异常子系统
|
||||
|
||||
## 当前代码组织原则
|
||||
|
||||
@ -177,25 +152,23 @@
|
||||
|
||||
- `UEFI` 相关定义留在 `arch/x86/`
|
||||
- 通用交接结构放在 `include/tianole/`
|
||||
- 以后新增架构时,优先新增新的 `arch/<name>/`,而不是改写通用代码
|
||||
- 以后新增架构时,优先新增新的 `arch/<name>/`
|
||||
|
||||
## 接下来最近三个里程碑
|
||||
## 最近里程碑
|
||||
|
||||
### 里程碑 1:独立 kernel 接管
|
||||
### 里程碑 1:退出 UEFI 前的最后准备
|
||||
|
||||
- 让 `bootloader` 加载独立 `kernel`
|
||||
- 建立 `boot_info`
|
||||
- 跳到 `kernel_main()`
|
||||
- 由 `kernel` 自己输出第一行字
|
||||
- 获取并保存完整 `memory map`
|
||||
- 扩展 `boot_info`
|
||||
- 建立 early serial log
|
||||
|
||||
### 里程碑 2:退出 UEFI
|
||||
|
||||
- 获取并保存 `memory map`
|
||||
- 正确执行 `ExitBootServices`
|
||||
- `kernel` 在退出固件服务后继续稳定运行
|
||||
|
||||
### 里程碑 3:早期调试和内存基础
|
||||
### 里程碑 3:早期内核基础设施
|
||||
|
||||
- 增加 early serial / framebuffer console
|
||||
- 增加 framebuffer console
|
||||
- 建立物理页分配器
|
||||
- 建立基础异常处理
|
||||
|
||||
@ -3,6 +3,17 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define TIANOLE_EFI_MEMORY_TYPE_CONVENTIONAL 7u
|
||||
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
uint32_t pad;
|
||||
uint64_t physical_start;
|
||||
uint64_t virtual_start;
|
||||
uint64_t number_of_pages;
|
||||
uint64_t attribute;
|
||||
} tianole_efi_memory_descriptor_t;
|
||||
|
||||
/*
|
||||
* Boot-time handoff data owned by Tianole rather than by a specific
|
||||
* firmware or architecture API. Fields can grow over time while the
|
||||
@ -11,6 +22,12 @@
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t boot_flags;
|
||||
uint64_t memory_map;
|
||||
uint64_t memory_map_size;
|
||||
uint64_t memory_map_key;
|
||||
uint64_t memory_descriptor_size;
|
||||
uint32_t memory_descriptor_version;
|
||||
uint32_t reserved0;
|
||||
} tianole_boot_info_t;
|
||||
|
||||
#define TIANOLE_BOOT_INFO_VERSION 1u
|
||||
|
||||
@ -15,6 +15,54 @@ static void debug_puts(const char *text) {
|
||||
}
|
||||
}
|
||||
|
||||
static void debug_put_u64_decimal(uint64_t value) {
|
||||
char digits[20];
|
||||
uint32_t index = 0;
|
||||
|
||||
if (value == 0) {
|
||||
debug_putc('0');
|
||||
return;
|
||||
}
|
||||
|
||||
while (value != 0) {
|
||||
digits[index++] = (char)('0' + (value % 10));
|
||||
value /= 10;
|
||||
}
|
||||
|
||||
while (index != 0) {
|
||||
debug_putc(digits[--index]);
|
||||
}
|
||||
}
|
||||
|
||||
static void log_memory_map_summary(const tianole_boot_info_t *boot_info) {
|
||||
uint64_t offset;
|
||||
uint64_t descriptors = 0;
|
||||
uint64_t conventional_pages = 0;
|
||||
|
||||
if (boot_info == 0 || boot_info->memory_map == 0 || boot_info->memory_descriptor_size == 0) {
|
||||
debug_puts("memory map metadata missing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (offset = 0; offset + sizeof(tianole_efi_memory_descriptor_t) <= boot_info->memory_map_size;
|
||||
offset += boot_info->memory_descriptor_size) {
|
||||
const tianole_efi_memory_descriptor_t *descriptor =
|
||||
(const tianole_efi_memory_descriptor_t *)(uintptr_t)(boot_info->memory_map + offset);
|
||||
|
||||
descriptors++;
|
||||
if (descriptor->type == TIANOLE_EFI_MEMORY_TYPE_CONVENTIONAL) {
|
||||
conventional_pages += descriptor->number_of_pages;
|
||||
}
|
||||
}
|
||||
|
||||
debug_puts("memory map descriptors=");
|
||||
debug_put_u64_decimal(descriptors);
|
||||
debug_puts("\n");
|
||||
debug_puts("conventional memory pages=");
|
||||
debug_put_u64_decimal(conventional_pages);
|
||||
debug_puts("\n");
|
||||
}
|
||||
|
||||
void kernel_main(const tianole_boot_info_t *boot_info) {
|
||||
debug_puts("kernel_main entered\n");
|
||||
if (boot_info != 0 && boot_info->version == TIANOLE_BOOT_INFO_VERSION) {
|
||||
@ -27,6 +75,8 @@ void kernel_main(const tianole_boot_info_t *boot_info) {
|
||||
debug_puts("boot services still active\n");
|
||||
}
|
||||
|
||||
log_memory_map_summary(boot_info);
|
||||
|
||||
for (;;) {
|
||||
__asm__ volatile("hlt");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user