编译与运行¶
本指南介绍如何编译 NoobKernel 并在 QEMU 中运行。
Makefile 结构¶
项目使用模块化的 Makefile 结构:
Makefile # 主 Makefile,定义全局变量和目标
rules.mk # 编译规则模板
src/*/Makefile # 各模块的 Makefile
scripts/kernel.ld # 链接脚本
主要变量¶
| 变量 | 说明 | 默认值 |
|---|---|---|
TOOL_PREFIX |
工具链前缀 | riscv64-unknown-elf- |
ARCH |
目标平台 | QEMU |
INIT_PROC |
初始进程 | usershell |
GDB_PORT |
GDB 端口 | 15234 |
内核模块¶
当前启用的模块(MODULES 变量):
MODULES := boot misc mm hal trap task sync fs
待实现的模块:
- syscall - 系统调用
- ipc - 进程间通信
- async - 异步机制
编译命令¶
编译内核¶
make
编译产物位于 build/QEMU/ 目录:
kernel- ELF 格式内核镜像kernel.asm- 反汇编文件(带源码)kernel.sym- 符号表
清理¶
make clean
删除当前架构的构建目录。
编译指定平台¶
make ARCH=QEMU
当前仅支持 QEMU virt 平台。
运行内核¶
直接运行¶
make run
内核将在 QEMU 中启动,日志输出到终端。
按 Ctrl+A 然后按 X 退出 QEMU。
QEMU 参数说明¶
QEMU_FLAGS = \
-nographic # 无图形界面,使用终端输出
-machine virt # 使用 virt 虚拟机
-m 128M # 128MB 内存
-kernel $(TARGET) # 加载内核镜像
-drive file=fs.img,... # 挂载磁盘镜像
调试内核¶
GDB 调试¶
make debug
此命令会: 1. 启动 QEMU(暂停状态,等待 GDB) 2. 自动连接 GDB
在 GDB 中:
# 继续执行
continue
# 设置断点
break main
break kerneltrap
# 查看寄存器
info registers
# 查看当前函数
backtrace
VSCode 调试¶
make vs-debug
然后在 VSCode 中按 F5 开始调试。
内核初始化流程¶
内核启动后会执行以下初始化:
main() @ src/boot/main.c
│
├── clear_bss() # 清零 BSS 段
├── init_cpu() # 初始化 CPU 结构
├── pm_init() # 物理内存管理初始化
├── plic_init() # PLIC 中断控制器初始化
├── trap_init() # 中断处理初始化
├── timer_init() # 定时器初始化
├── kvminit() # 内核虚拟内存初始化
├── init_runq() # 运行队列初始化
├── blk_init() # 块设备初始化
├── bcache_init() # 缓冲区缓存初始化
├── virtio_init() # VirtIO 设备初始化
├── vfs_init() # VFS 初始化
├── fd_table_init() # 文件描述符表初始化
├── ramfs_init() # RAM 文件系统初始化
├── vfs_mount_root() # 挂载根文件系统
├── sched_enabled=true # 启用调度器
├── context_switch_to()# 切换到 idle 进程
└── sched_yield() # 开始调度
常见问题¶
编译错误¶
找不到头文件:检查 include/ 目录结构是否完整。
链接错误:检查 scripts/kernel.ld 是否存在。
运行问题¶
QEMU 无输出: 1. 检查内核是否正确编译 2. 确认 SBI 正常启动(QEMU 默认使用 OpenSBI)
内核崩溃:
1. 查看 kernel.asm 分析崩溃位置
2. 使用 GDB 调试定位问题