跳转到内容

构建与运行

OpenOS 使用两步构建过程:

  1. 编译内核 - 使用 Rust nightly 编译内核二进制
  2. 创建磁盘镜像 - 使用 bootloader 创建可引导的 BIOS 磁盘镜像
源代码 (Rust) → 内核二进制 → BIOS 磁盘镜像 → QEMU 运行
  1. 编译内核

    Terminal window
    cargo build -p openos-kernel --target x86_64-unknown-none \
    -Zbuild-std=core,compiler_builtins,alloc \
    -Zbuild-std-features=compiler-builtins-mem

    这将生成内核二进制文件 target/x86_64-unknown-none/debug/openos-kernel

  2. 创建用户态程序(可选)

    Terminal window
    # 汇编用户态程序
    nasm -f elf64 user/hello.asm -o target/debug/hello.o
    # 链接
    ld -static -o target/debug/hello.elf target/debug/hello.o
  3. 创建 initrd(可选)

    Terminal window
    python3 tools/mkinitrd.py target/debug/initrd.img \
    hello.elf=target/debug/hello.elf
  4. 创建磁盘镜像

    Terminal window
    cargo run -p openos --target x86_64-unknown-linux-gnu -- \
    target/x86_64-unknown-none/debug/openos-kernel \
    target/debug/openos-bios.img \
    target/debug/initrd.img
Terminal window
make run-serial

优点:

  • 输出到终端,便于调试
  • 无头模式,适合服务器环境
  • 可与 GDB 配合使用

QEMU 参数:

Terminal window
qemu-system-x86_64 \
-drive format=raw,file=target/debug/openos-bios.img \
-serial mon:stdio \
-display none
Terminal window
make run

优点:

  • 可视化 VGA 输出
  • 适合演示

QEMU 参数:

Terminal window
qemu-system-x86_64 \
-drive format=raw,file=target/debug/openos-bios.img \
-serial mon:stdio
Terminal window
make debug

使用方法:

  1. 启动调试会话:

    Terminal window
    make debug
  2. 在另一个终端连接 GDB:

    Terminal window
    gdb target/x86_64-unknown-none/debug/openos-kernel
    (gdb) target remote :1234
    (gdb) break kernel_main
    (gdb) continue
  3. 常用 GDB 命令:

    • next / n - 单步执行
    • step / s - 进入函数
    • continue / c - 继续执行
    • print / p - 打印变量
    • backtrace / bt - 查看调用栈
Terminal window
make release

优化选项(在 Cargo.toml 中配置):

[profile.release]
panic = "abort"
opt-level = "s" # 优化大小
lto = true # 链接时优化

对于嵌入式环境,可以进一步优化:

Terminal window
# 使用 svelte 优化
RUSTFLAGS="-C link-arg=-s" make release
# 使用 strip 去除符号
strip target/x86_64-unknown-none/release/openos-kernel

OpenOS 使用 BIOS 引导的磁盘镜像:

偏移量 内容
0x0000 引导扇区 (512 字节)
0x0200 内核加载器
0x1000 内核代码
... 内核数据
(initrd) 初始 ramdisk(如果存在)

引导过程:

  1. BIOS 加载引导扇区到 0x7C00
  2. 引导加载器加载内核到 0x1000
  3. 引导加载器设置页表(高半内核映射)
  4. 跳转到内核入口点

内核入口点在 kernel/src/main.rs 中定义:

#[no_mangle]
pub extern "C" fn _start() -> ! {
// 初始化代码
kernel_main();
loop {
x86_64::instructions::hlt();
}
}

内存布局在 kernel/src/arch/x86_64/linker.ld 中配置:

KERNEL_OFFSET = 0xFFFFFFFF80000000
PHYSICAL_OFFSET = 0x100000
SECTIONS {
. = KERNEL_OFFSET + PHYSICAL_OFFSET;
.text : AT(ADDR(.text) - KERNEL_OFFSET) {
*(.text .text.*)
}
.rodata : AT(ADDR(.rodata) - KERNEL_OFFSET) {
*(.rodata .rodata.*)
}
.data : AT(ADDR(.data) - KERNEL_OFFSET) {
*(.data .data.*)
}
.bss : AT(ADDR(.bss) - KERNEL_OFFSET) {
*(.bss .bss.*)
}
}

可能原因:

  • 磁盘镜像损坏
  • 内核 panic

解决方法:

  1. 检查 QEMU 输出的错误信息
  2. 使用 make debug 启动调试
  3. 在内核入口点添加断点

可能原因:

  • 串口驱动未初始化
  • QEMU 参数错误

解决方法:

  1. 确保使用 make run-serial
  2. 检查 QEMU 参数中是否有 -serial mon:stdio

优化方法:

  1. 使用增量编译:cargo build(默认)
  2. 使用并行编译:cargo build -j$(nproc)
  3. 使用 sccache 缓存编译结果