写在前面:这是本系列的第三篇。

俗话说“三天不练手生”,复习一下上节课的核心:程序 == 状态机。用 GDB 单步执行,其实就是看着状态机一步步发生状态迁移。而系统调用 (Syscall),则是软件与操作系统之间唯一的接口。

今天,我们将继续往下挖,看看在操作系统还没有醒来之前,那个“无情的指令执行机器”(硬件)是如何被唤醒,并把世界交给操作系统的。

在这里插入图片描述

成为 Power User:GDB 调试与 AI 提问的艺术

南大也接入了 DeepSeek。在这个时代,把 AI 当成一个不厌其烦教你的专业人士,是拉开差距的关键。

如果你想和其他人拉开差距:

  1. 不要一味去卷 GPA。
  2. 熟练使用 Prompt:“我在做…。如果你是一位…专业人士,有更好的方法和建议吗?尽可能全面。”
  3. 你的学习效率会极大提高。留给人类的时间不多了!

Prompt 实战: 我在命令行中使用 gdb 调试。如果你是一位专业人士,有更好的方法和建议吗?尽可能全面。

AI 给出的专业 GDB 进阶指南:

  1. 使用 TUI 模式:
    gdb -tuiCtrl+X+A 启用文本用户界面,边看源代码边看调试信息(绝杀技巧!)。
  2. 设置断点:
    • break <function> 在函数入口设置断点。
    • break <file>:<line> 在指定文件的某行设置断点。
  3. 条件断点:
    break <location> if <condition> 仅在满足特定条件时才中断(找 Bug 神器)。
  4. 查看变量:
    • print <variable> 查看单次变量值。
    • display <variable> 每次停止时自动显示变量值。
  5. 多线程调试:
    • info threads 查看所有线程。
    • thread <id> 切换到指定线程。
  6. 回溯调用栈:
    bt 查看当前调用栈,frame <number> 切换到指定栈帧。
  7. 反汇编:
    disassemble 查看当前函数的汇编代码。
  8. 使用 GDB 脚本:
    将常用命令写入 .gdbinit 文件,启动时自动加载配置。
  9. 优化调试体验:
    • set pagination off 禁用满屏后的分页暂停。
    • set logging on 记录调试输出到文件。

硬件视角的操作系统

以开源的 RISC-V 处理器为例(基于精简指令集计算 RISC 原则)。

硬件根本不知道操作系统的存在! 它只是一个无情的指令执行机器。

CS 的终极抽象

计算机科学的精髓在于抽象:下层不需要知道上面怎么用,它只管**“无情地提供服务”**。

计算机系统的状态机模型

  • 状态: 内存、寄存器的数值。
  • 初始状态: 由系统硬件设计者硬性规定。
  • 状态迁移: 硬件从 PC (Program Counter) 寄存器指向的内存地址取指令,译码,执行。

除了内存和寄存器,还有外部世界:

  • Memory-mapped I/O (内存映射 I/O): 把外部设备的寄存器映射到内存地址上。
  • Interrupt Line (中断线): 保证了系统不会陷入死循环,随时可以响应外部事件。
  • Reset Line (复位线): 保证系统可以在任何混乱状态下,瞬间恢复到初始状态

计算机系统:初始状态 (CPU Reset)

当你按下机箱上的 Reset 按钮时,会发生什么?

x86-64 的 CPU Reset 状态是怎样的?

在过去,你需要去 Intel 的《The Friendly Manual》里大海捞针(Volume 3A 差不多 400 多页,那是老师年代学习《操作系统》的圣经)。

今天,地球人都不再需要自己翻厚重的手册了,你可以让 AI 帮你去茫茫文档中捞针。

RISC-V 的哲学

RISC-V 的设计原则是:极度节省电路。软件能做的事情,硬件坚决不管。所以它的 Reset 状态极其简单。

总结一句话:硬件根本不知道有没有操作系统,操作系统在硬件眼里,就是一个普通的二进制程序。


固件 (Firmware):硬件和 OS 之间的桥梁

遗漏的细节:第一条指令从哪来?

  • CPU Reset 开始执行。
  • Mem[PC] 取指令。
  • 译码、执行、往复…

问题来了: 这个初始的 PC 指向的内存位置,必须有一段合法的代码,否则 CPU 直接死机。这段代码是谁放进去的?

Firmware (固件) 的登场

这段代码叫引导程序 (Bootloader),来自系统主板厂商。

硬件会把一个特殊的只读存储器 (ROM) 映射到 CPU Reset 后的初始地址上。这段代码“出生”就拥有机器的绝对控制权。它负责初始化硬件设备、设置内存、最后加载操作系统。

  • 早期的固件: 写死在 ROM 芯片里,更新固件必须拔换芯片。
  • 现代的固件 (如 UEFI): 存在闪存里,可以通过软件更新。也就是 Legacy BIOS 到 UEFI 的进化。

固件安全与防篡改

既然固件也是代码,而且还能被软件更新,那黑客岂不是可以随便改?

  • 早期的写保护很容易被破解。
  • 现在的防御机制:只允许写入“受信任”的固件更新。 这依赖于数字签名机制和公钥加密(Diffie-Hellman/RSA)。
  • 感谢今天的 SSL/TLS (HTTPS) 奠定的密码学基础。这也是为什么现在电脑底层的病毒越来越少的原因(更安全的操作系统、AppStore 机制、云端备份)。

加载操作系统

从硬件到操作系统的接力赛

以经典的 IBM PC 为例:

  1. MBR (主引导记录): 磁盘的第一个扇区。
  2. 计算机从 CPU Reset 开始,此时 0x7c00 内存处啥也没有。
  3. 固件代码扫描了磁盘,把 MBR 加载到了 0x7c00
  4. Grub 登场: 这是固件和系统程序员的第一个接口。Grub 会扫描磁盘,找到附近的 ELF 文件头,将其加载到内存,然后弹出选择操作系统的窗口。
  5. 加载 Linux Kernel: 将接力棒彻底交给操作系统内核。

硬核实操:RISC-V 固件与 OpenSBI 编译

遇到不懂的底层机制?只需要向 AI 提问 & 追问就行了!

  • Q: RISC-V 系统是如何复位、加载操作系统的?

A: 复位后,系统依次执行 ZSBL、FSBL、OpenSBI 等固件阶段,最终加载并启动操作系统内核。

  • Q: OpenSBI 的入口位于什么地方?

A: 通常位于 0x80000000,由 FSBL 加载并跳转执行。

  • Q: _start 开始的 _try_lottery 是做什么的?

A: 在多核系统中选择一个“主核”并进行核心同步,确保系统启动的有序性。

编译 OpenSBI (Everything is a State Machine)

Makefile 也是程序,它也是状态机!
如果构建程序不好读,我们可以调试它。记住计算机系统的公理:“你能想到的就一定有人做到,总有人会去发明轮子。”

OpenSBI (Open Source Supervisor Binary Interface) 是 RISC-V 架构中极其重要的组件。

第一步:安装交叉编译工具链

本来以为要源码克隆、配置构建,搞一堆复杂的文件夹……
结果发现,其实只需要一行命令:

apt install binutils-riscv64-linux-gnu
第二步:编译!

进入 OpenSBI 源码目录,执行:

make PLATFORM=generic FW_TYPE=FW_DYNAMIC

最终生成的二进制固件文件位于 build/platform/generic/firmware/fw_payload.bin

第三步:使用 QEMU 启动!

注:QEMU 是一个强大的开源模拟器,能够用纯软件模拟出 RISC-V 硬件的运行环境。

root@LAPTOP-GT06V0GS:/mnt/d/CSLab/osCourse/lec3/opensbi# qemu-system-riscv64 -machine virt -kernel build/platform/generic/firmware/fw_payload.bin -nographic

激动人心的启动日志 (带 AI 辅助注释):

# 显示当前运行的 OpenSBI 版本(1.3)。
OpenSBI v1.3
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|___/_____|
        | |
        |_|

# 平台名称:riscv-virtio,qemu,表示这是一个在 QEMU 上运行的虚拟 RISC-V 平台。
Platform Name             : riscv-virtio,qemu

# 平台特性:medeleg,表示支持将机器模式的异常委托给监督模式。
Platform Features         : medeleg

# HART 计数:1,表示只有一个硬件线程(Core)。
Platform HART Count       : 1

# IPI / 定时器 / 控制台设备初始化
Platform IPI Device       : aclint-mswi
Platform Timer Device     : aclint-mtimer @ 10000000Hz
Platform Console Device   : uart8250

# 固件内存布局信息
Firmware Base             : 0x80000000
Firmware Size             : 322 KB
Firmware RW Offset        : 0x40000
Firmware RW Size          : 66 KB
Firmware Heap Offset      : 0x48000
Firmware Heap Size        : 34 KB (total), 2 KB (reserved), 9 KB (used), 22 KB (free)
Firmware Scratch Size     : 4096 B (total), 760 B (used), 3336 B (free)
Runtime SBI Version       : 1.0

# 域信息与启动 HART 信息
Domain0 Name              : root
Domain0 Boot HART         : 0
Domain0 Next Address      : 0x0000000080200000
Domain0 Next Mode         : S-mode
Boot HART ID              : 0
Boot HART Priv Version    : v1.12
Boot HART Base ISA        : rv64imafdch

为什么我们要折腾编译固件?(拒绝功利)

中间多次想放弃编译 OpenSBI,但还是听老师的话坚持下来了,主要靠 AI 辅助排雷。最终成功看到了 QEMU 跑起 .bin 的瞬间,成就感拉满!这绝不是没好处的事:

  1. 理解 RISC-V 架构: 了解 M 模式 (Machine) 和 S 模式 (Supervisor) 的通信。
  2. 直击启动过程: 亲眼见证 OpenSBI 初始化硬件并准备加载 OS。
  3. 理解硬件抽象层 (HAL): 固件抹平了底层硬件差异,让 OS 可以平台无关地运行。
  4. 掌握隔离与虚拟化: 理解同一硬件如何跑多 OS,以及底层的特权级委托机制。

尾声:配置自己的极客 AG (AI Agent)!

今天我有我自己的舞台,我一直认为我很独特!我一定会有自己的天地的!!!

部署本地大模型:Deepseek-r1-7b

笔记本性能有限,跑不了满血版本,但部署一个 7B 的蒸馏版本,足以作为一个专属的、断网可用的极客交流助手。在命令行里敲下大模型启动命令的那一刻,才是真正属于赛博时代 Power User 的浪漫。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐