feat(mm): parse UEFI memory map in kernel

This commit is contained in:
Microindole 2026-05-08 20:00:10 +08:00
parent f60b6af52f
commit 62c8836886
No known key found for this signature in database
GPG Key ID: 22FB34CD2133ACA1
7 changed files with 339 additions and 285 deletions

252
README.md
View File

@ -1,230 +1,72 @@
# Tianole # 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 ```text
tianole/ tianole/
README.md AGENTS.md
.gitignore
Makefile Makefile
boot/ arch/
kernel/ docs/
include/ include/
kernel/
scripts/ scripts/
build/
``` ```
先不要一开始就拆出 当前还没有直接复制 Linux 的完整目录树,但已经开始按接近 Linux 的方式分层:
- `fs/` - `arch/`:架构相关代码
- `drivers/` - `kernel/`:通用内核主体逐步放这里
- `mm/` - `include/tianole/`:项目自有共享接口
- `userland/` - `docs/`:正式设计和路线图
- `lib/`
等真正需要时再拆,不要先造目录架子。 ## 开发顺序
## 真机测试原则 当前建议的实现顺序是:
你这台机器是 `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)

View File

@ -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( static efi_status open_root(
efi_handle image_handle, efi_handle image_handle,
efi_system_table_t *system_table, efi_system_table_t *system_table,
@ -222,6 +243,63 @@ static efi_status load_kernel_image(
return EFI_SUCCESS; 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_status EFIAPI efi_main(efi_handle image_handle, efi_system_table_t *system_table) {
efi_file_protocol_t *root; efi_file_protocol_t *root;
void *kernel_image; void *kernel_image;
@ -255,6 +333,19 @@ efi_status EFIAPI efi_main(efi_handle image_handle, efi_system_table_t *system_t
return status; 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"); debug_puts("jumping to kernel entry\n");
kernel_entry(&boot_info); kernel_entry(&boot_info);

View File

@ -141,13 +141,19 @@ struct efi_boot_services {
efi_physical_address_t *memory efi_physical_address_t *memory
); );
void *free_pages; 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)( efi_status(EFIAPI *allocate_pool)(
int pool_type, int pool_type,
efi_uintn_t size, efi_uintn_t size,
void **buffer void **buffer
); );
void *free_pool; efi_status(EFIAPI *free_pool)(void *buffer);
void *create_event; void *create_event;
void *set_timer; void *set_timer;
void *wait_for_event; void *wait_for_event;

75
docs/host-machine.md Normal file
View 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 / 启动菜单辅助操作
- 真机测试前准备

View File

@ -1,77 +1,57 @@
# Tianole 路线图 # Tianole 路线图
## 第 0 阶段 ## 总原则
- 建立最小 `UEFI` 启动程序。 这个项目按“可中断、可回坑、每一阶段都能单独验收”的方式推进。
- 在 `QEMU + OVMF` 下运行。
- 在屏幕和 `debug.log` 中输出可见的启动标记。
- 保证启动后常驻,便于后续调试。
## 第 1 阶段 目标不是只在虚拟机里亮屏,而是:
- 把当前单体启动程序拆成 `boot/``kernel/` - 在 `UEFI x86_64` 真机上独立启动
- 定义 `boot_info` 交接结构。 - 逐步具备完整内核基础设施
- 由 `bootloader` 加载独立 `kernel` 映像。 - 逐步具备运行本地 `git` 的能力
- 跳转到 `kernel` 入口并建立稳定栈。
## 第 2 阶段 这里参考 Linux 的是分层思路和演进顺序,不是照搬早期 Linux 的启动方式或目录树。
- 获取 `UEFI memory map` ## 推荐开发顺序
- 正确执行 `ExitBootServices`
- 建立最小 framebuffer 控制台。
- 开始做物理内存管理。
## 第 3 阶段 ### 1. 启动链
- 建立 `IDT` 和基础异常处理。
- 增加定时器来源。
- 开始早期 `ACPI` 解析。
- 逐步过渡到接近 Linux 风格的 `arch/`、`mm/`、`kernel/` 边界。
## 总体流程
这个项目要按“可中断、可回坑、每一阶段都能单独验收”的方式推进。最终目标不是只在虚拟机里亮屏,而是要在这台 `UEFI x86_64` 笔记本上独立启动,并逐步具备运行本地 `git` 的能力。
建议的长期阶段如下:
### 阶段 A启动链
- 跑通 `UEFI app -> bootloader -> kernel` - 跑通 `UEFI app -> bootloader -> kernel`
- 保证 `kernel_main()` 真正开始执行 - 保证 `kernel_main()` 真正开始执行
- 保证屏幕或串口可见输出 - 保证最小可见输出
完成标志: 完成标志:
- `bootloader` 成功把控制权交给独立 `kernel` - `bootloader` 成功把控制权交给独立 `kernel`
- `kernel` 能输出第一行字并停住 - `kernel` 能输出第一行字并停住
### 阶段 B早期内核基础 ### 2. 早期调试输出
- 定义 `boot_info` - 保留当前 `debug` 输出路径
- 获取 `memory map` - 增加 early serial log
- 正确执行 `ExitBootServices` - 为后续脱离固件后的调试做准备
- 建立 early console
- 建立最小 panic / assert / log
完成标志: 完成标志:
- 退出 UEFI 后内核仍能稳定运行 - 内核在更早阶段也能稳定输出日志
- 崩溃时能给出可定位信息
### 阶段 C内存与异常 ### 3. 内存与异常基础
- 建立物理页分配器 - 获取 `UEFI memory map`
- 建立内核堆分配器 - 正确执行 `ExitBootServices`
- 建立 `GDT/IDT` - 建立 `GDT/IDT`
- 处理基础异常 - 增加基础异常处理
- 建立物理页分配器
- 建立内核堆
- 增加定时器 - 增加定时器
完成标志: 完成标志:
- 能稳定分配页和堆内存 - 退出 UEFI 后内核仍稳定运行
- 关键异常能进入处理路径 - 关键异常能进入处理路径
- 内核能稳定分配页和堆内存
### 阶段 D任务模型 ### 4. 执行流与调度
- 建立内核线程 - 建立内核线程
- 建立调度器 - 建立调度器
@ -83,11 +63,11 @@
- 可以同时运行多个内核线程 - 可以同时运行多个内核线程
- 调度由时钟驱动 - 调度由时钟驱动
### 阶段 E用户态基础 ### 5. 用户态入口
- 建立用户地址空间 - 建立用户地址空间
- 增加系统调用入口 - 增加系统调用入口
- 增加 ELF 加载 - 增加 ELF 用户程序加载
- 增加进程创建和等待 - 增加进程创建和等待
完成标志: 完成标志:
@ -95,7 +75,7 @@
- 能加载并运行最小用户程序 - 能加载并运行最小用户程序
- 用户程序能调用系统调用输出 - 用户程序能调用系统调用输出
### 阶段 F存储与文件系统 ### 6. 文件系统与存储
- 建立块设备层 - 建立块设备层
- 建立 `VFS` - 建立 `VFS`
@ -107,7 +87,7 @@
- 能挂载文件系统 - 能挂载文件系统
- 能打开、读取、写入文件 - 能打开、读取、写入文件
### 阶段 G最小用户空间 ### 7. shell 与基础工具
- 增加 `init` - 增加 `init`
- 增加简单 shell - 增加简单 shell
@ -119,9 +99,10 @@
- 启动后能进入 shell - 启动后能进入 shell
- 能执行几个基础程序 - 能执行几个基础程序
### 阶段 H面向 git 的补齐 ### 8. 面向 git 的补齐
- 优先支持本地 `git`,不先碰网络 - 优先支持本地 `git`
- 不先碰网络协议栈
- 补足 `git` 依赖的文件、进程、时间、路径等接口 - 补足 `git` 依赖的文件、进程、时间、路径等接口
- 先以 `git init / status / add / commit` 为目标 - 先以 `git init / status / add / commit` 为目标
@ -129,7 +110,7 @@
- 能运行本地仓库的基础 `git` 操作 - 能运行本地仓库的基础 `git` 操作
### 阶段 I真机落地 ### 9. 真机落地
- 先 `QEMU + OVMF` - 先 `QEMU + OVMF`
- 再 `U 盘 UEFI` 启动 - 再 `U 盘 UEFI` 启动
@ -137,31 +118,25 @@
完成标志: 完成标志:
- 不破坏现有 `Windows 11 + Linux Mint + GRUB` - 不破坏现有本机启动链
- 能在真机上独立启动并进入系统 - 能在真机上独立启动并进入系统
## 当前所处阶段 ## 当前进度
当前只完成了第 0 阶段的最小成果 当前已经完成
- `UEFI` 启动程序可构建 - 最小 `UEFI` 启动链
- `QEMU + OVMF` 能执行它 - `bootloader + kernel` 拆分
- 屏幕和 `debug.log` 有可见输出 - 独立 `kernel.elf` 加载
- 程序可常驻,便于调试 - `kernel_main()` 实际执行
- `memory map` 已通过 `boot_info` 传递,并能在 kernel 中统计描述符与可用页数
当前已经开始进入第 1 阶段:
- 代码结构已经为 `bootloader -> kernel` 交接预留边界
- `boot_info` 已经作为项目自有交接结构存在
- `arch/x86/` 已经承载当前架构专用启动代码
当前还没有完成: 当前还没有完成:
- 独立 `kernel` 接管
- `bootloader -> kernel` 交接
- `memory map`
- `ExitBootServices` - `ExitBootServices`
- 真正的内核子系统 - early serial log
- framebuffer console
- 真正的内存管理和异常子系统
## 当前代码组织原则 ## 当前代码组织原则
@ -177,25 +152,23 @@
- `UEFI` 相关定义留在 `arch/x86/` - `UEFI` 相关定义留在 `arch/x86/`
- 通用交接结构放在 `include/tianole/` - 通用交接结构放在 `include/tianole/`
- 以后新增架构时,优先新增新的 `arch/<name>/`,而不是改写通用代码 - 以后新增架构时,优先新增新的 `arch/<name>/`
## 接下来最近三个里程碑 ## 最近里程碑
### 里程碑 1独立 kernel 接管 ### 里程碑 1退出 UEFI 前的最后准备
- 让 `bootloader` 加载独立 `kernel` - 获取并保存完整 `memory map`
- 建立 `boot_info` - 扩展 `boot_info`
- 跳到 `kernel_main()` - 建立 early serial log
- 由 `kernel` 自己输出第一行字
### 里程碑 2退出 UEFI ### 里程碑 2退出 UEFI
- 获取并保存 `memory map`
- 正确执行 `ExitBootServices` - 正确执行 `ExitBootServices`
- `kernel` 在退出固件服务后继续稳定运行 - `kernel` 在退出固件服务后继续稳定运行
### 里程碑 3早期调试和内存基础 ### 里程碑 3早期内核基础设施
- 增加 early serial / framebuffer console - 增加 framebuffer console
- 建立物理页分配器 - 建立物理页分配器
- 建立基础异常处理 - 建立基础异常处理

View File

@ -3,6 +3,17 @@
#include <stdint.h> #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 * Boot-time handoff data owned by Tianole rather than by a specific
* firmware or architecture API. Fields can grow over time while the * firmware or architecture API. Fields can grow over time while the
@ -11,6 +22,12 @@
typedef struct { typedef struct {
uint32_t version; uint32_t version;
uint32_t boot_flags; 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; } tianole_boot_info_t;
#define TIANOLE_BOOT_INFO_VERSION 1u #define TIANOLE_BOOT_INFO_VERSION 1u

View File

@ -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) { void kernel_main(const tianole_boot_info_t *boot_info) {
debug_puts("kernel_main entered\n"); debug_puts("kernel_main entered\n");
if (boot_info != 0 && boot_info->version == TIANOLE_BOOT_INFO_VERSION) { 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"); debug_puts("boot services still active\n");
} }
log_memory_map_summary(boot_info);
for (;;) { for (;;) {
__asm__ volatile("hlt"); __asm__ volatile("hlt");
} }