
Nova-Quantum 是一個很有意思的項目一個約 41 MB 的 ISO 鏡像啟動后不進入 Linux、不加載 Windows而是直接進入一個自定義內核由這個內核自己完成大語言模型的加載和推理。項目副標題里的 Bootet Ohne OS 是德語意思就是“在沒有操作系統的狀態下啟動”。換句話說從 BIOS 或 UEFI 固件交棒之后頁表、內存管理、串口輸出、模型文件解析、tokenizer、transformer 前向計算、采樣輸出全部由項目自己的代碼接管。這種形態不是常見的“嵌入式 Linux 推理框架”而是把 Linux 內核、用戶態、驅動、Python、PyTorch 這一整條棧全部去掉只保留真正做推理的那部分。它的價值不在性能多強而在于把“從按下電源鍵到生成第一個 token”之間的每一層細節都暴露出來。對想理解引導過程、想在受限硬件上跑 LLM、或者想從零看一遍 transformer 前向計算的開發者來說這是一個可學習、可復現、可排查的切入點。這篇文章會圍繞 Nova-Quantum 的工程形態說明 bare-metal LLM kernel 的啟動鏈路、ISO 結構、內核骨架、模型加載與推理實現以及最常見的踩坑點和排查順序。1. Bare-Metal LLM Kernel 是什么和常規推理棧有什么本質區別1.1 一句話解釋內核自己就是“操作系統”常規的 LLM 部署鏈路通常很長。操作系統負責內存管理、設備驅動、進程調度Python 運行時負責解釋代碼PyTorch 負責算子調度最終才會落到矩陣乘法上。每一步都有成熟工具但每一步也都有抽象屏蔽。Nova-Quantum 走的是另一條路線它自己實現一個極小的內核這個內核只做兩件事先初始化最基本的硬件環境再加載模型權重并執行 LLM 前向計算。沒有 shell沒有文件系統驅動沒有進程模型沒有虛擬內存保護除了最基礎的頁表。啟動之后直接進入推理狀態。這種設計的前提是推理本身不需要操作系統的大部分能力。LLM 推理本質上是幾百次矩陣乘法和內存搬家需要的只是“一塊能讀寫的內存”和“一個能做乘加的 CPU”。把這些能力直接暴露給推理代碼反而省去了中間所有轉換和調度的開銷。1.2 與常規部署方式的對比對比項Linux Python PyTorch嵌入式 Linux C 推理引擎Nova-Quantum 這類 Bare-Metal 內核啟動過程BIOS/UEFI - 內核 - init - Python 進程BIOS/UEFI - 內核 - 應用進程BIOS/UEFI - GRUB - LLM 內核內存管理內核負責用戶態通過系統調用內核負責應用通過 malloc內核自己管理簡單堆區設備驅動完整驅動棧按需裁剪只做串口、內存、可能加上定時器模型加載文件系統 系統調用文件系統或裸分區GRUB module 直接放進內存體積數 GB數百 MB約 41 MB ISO調試難度日志、gdb、perf 齊全有基礎調試手段主要靠 QEMU 和串口日志學習價值被抽象隔離部分暴露全鏈路暴露表格里的“約 41 MB”是 Nova-Quantum ISO 的總大小不是內核大小。這個數字決定了它在學習環境里很容易被分享和下載也決定了模型必須經過量化否則根本放不進去。1.3 41 MB 這個體積意味著什么一個 41 MB 的 ISO并不是全部空間都裝模型。用 grub-mkrescue 生成的鏡像會包含 GRUB 的 BIOS 引導代碼和 UEFI 運行時通常要占 3 MB 到 6 MB內核 ELF 包含啟動匯編、驅動和推理邏輯1 MB 到 2 MB 很常見剩下大約 33 MB 到 36 MB 才是模型權重區域。按 4 位塊量化每參數約 4.5 比特計算33 MB 大約能容納 5000 萬到 6000 萬參數的小模型。這個規模放在大模型領域很小但放在“一個 ISO 直接啟動”的場景里是合理的。它可以完成簡單的文本補全、關鍵詞生成、表達式計算也可以作為教學模型演示完整的 transformer 前向過程。易誤解的地方是不要指望這個體積的模型具備 ChatGPT 級別的能力。Bare-Metal LLM kernel 的目標是“能用極簡棧跑通 LLM”而不是“用極小模型打敗大模型”。理解了這一點后續學習方向才不會跑偏。2. 先理解從 ISO 到模型推理的整條啟動鏈路2.1 固件、GRUB、multiboot2 三者如何交接Nova-Quantum 并不是從零寫引導器而是使用 GRUB2 加載自己的內核。這樣做是合理的GRUB 已經處理好了 BIOS 和 UEFI 兩類固件的差異包括文件系統讀取、內存探測、圖形模式初始化。內核只需要遵循 multiboot2 協議把自己聲明成 GRUB 可以識別的 ELF 文件即可。整條鏈路如下機器上電固件初始化硬件。固件找到啟動介質進入 GRUB。GRUB 讀取 ISO 里的grub.cfg顯示菜單。用戶選擇 Nova-QuantumGRUB 用 multiboot2 協議加載內核 ELF。GRUB 同時加載module2指定的模型文件到內存。CPU 跳轉到內核入口_start內核從此完全接管。Linux 啟動時經常出現Decompressing Linux... Parsing ELF... done. Booting the kernel.這類日志Nova-Quantum 沒有解壓環節GRUB 直接按 ELF 的 program headers 把段加載到指定地址然后跳轉入口。這也是裸內核比常規系統啟動更快的原因之一。2.2 模型文件通過 GRUB module 機制加載Bare-Metal 環境沒有文件系統驅動內核自己讀 ISO 里的文件非常麻煩。Nova-Quantum 這類項目通常采用 multiboot2 的 module 機制在grub.cfg里用module2聲明一個文件GRUB 會在加載內核后把該文件讀入內存并把它的起始地址和結束地址寫進 multiboot2 信息結構里內核通過解析這個結構就能拿到模型數據。set timeout3 set default0 menuentry Nova-Quantum (Bare-Metal LLM Kernel) { multiboot2 /boot/nova-quantum.elf module2 /boot/model.bin }這個設計的精妙之處在于GRUB 已經解決了文件系統解析問題內核不需要再實現 ISO9660 驅動。代價是模型文件必須能整體放進內存且內存映射不能和內核自身代碼沖突。對 33 MB 的模型來說這個約束完全可接受。2.3 內核態跑推理的運行時約束內核態推理和用戶態推理有幾個關鍵差異直接影響代碼組織方式沒有標準庫可用printf、malloc、memcpy要么自己實現要么使用 freestanding 編譯器提供的-ffreestanding模式。沒有系統調用內存只能自管。內核啟動后要自己把可用內存劃分成代碼區、堆區、模型區和 KV cache 區。沒有異常處理機制兜底。用戶態程序段錯誤會終止進程內核里訪問非法地址就是 page fault處理不好就是 triple faultQEMU 直接重啟。沒有調度器。推理循環是獨占 CPU 的一次 token 生成期間不能被打斷。這些約束不是缺點而是理解 OS 內核工作原理的入口。Nova-Quantum 正好把這些約束都壓縮在一個最小項目里。3. 構建環境工具鏈、依賴和目錄結構3.1 工具鏈清單本地構建 Nova-Quantum 至少需要四類工具匯編器、交叉編譯器、鏈接器以及生成 ISO 的 GRUB 工具。推薦環境是 LinuxWindows 下建議用 WSL 或虛擬機避免工具鏈路徑問題。sudo apt update sudo apt install build-essential nasm xorriso grub-pc-bin grub-common mtools qemu-system-x86各工具作用如下工具作用說明nasm匯編啟動代碼負責 multiboot2 頭和 long mode 切換x86_64-elf-gcc編譯 C 內核代碼需要 freestanding 模式x86_64-elf-ld鏈接內核 ELF配合自定義鏈接腳本xorriso生成 ISOgrub-mkrescue 依賴它grub-pc-binGRUB 二進制模塊提供 BIOS 引導所需文件mtools操作 FAT 鏡像grub-mkrescue 的間接依賴qemu-system-x86本地驗證不需要真機也能跑完整流程交叉編譯工具鏈如果沒有安裝可以下載 x86_64-elf 版本的 GCC 工具鏈也可以先確認系統自帶 gcc 是否支持-ffreestanding -mcmodelkernel。學習階段兩者都行但建議從一開始就使用交叉編譯器減少內核對宿主環境的隱式依賴。3.2 工程目錄結構一個可維護的 Bare-Metal LLM 內核工程建議這樣組織nova-quantum/ ├── Makefile ├── boot.S # multiboot2 頭、棧、long mode 切換 ├── kernel.c # 內核入口、串口、模型解析、推理循環 ├── linker.ld # 內核內存布局 ├── grub.cfg # GRUB 啟動菜單 ├── src/ │ ├── serial.c # 串口驅動 │ ├── vga.c # 屏幕輸出 │ ├── model.c # 模型文件解析 │ ├── tokenizer.c # 字節級 BPE tokenizer │ └── transformer.c # attention、ffn、采樣 ├── tools/ │ └── export_model.py # 把 PyTorch 權重導出為裸二進制格式 └── iso_root/ └── boot/ ├── grub/grub.cfg ├── nova-quantum.elf └── model.bin這里model.bin是模型權重的裸二進制文件不是 PyTorch 的safetensors也不是 GGUF。裸二進制的目的是讓內核代碼零依賴讀取文件頭自己定義結構。3.3 構建前檢查清單在寫第一行代碼之前先做這幾項檢查能省掉后面很多排查時間確認nasm -v、x86_64-elf-gcc -v、grub-mkrescue --version都能正常輸出版本號。確認 QEMU 可用運行qemu-system-x86_64 --version。確認grub-pc-bin已安裝否則 grub-mkrescue 會提示缺少 BIOS 支持文件。確認model.bin文件頭魔數和內核代碼里定義的 magic 一致。確認目標內存模式內核代碼只放在 1 MB 以上模型模塊加載地址由 GRUB 決定需要在內核里打印出來確認。4. 編寫最小 Bare-Metal 內核骨架4.1 引導匯編multiboot2 頭與 long mode 切換內核第一個文件是boot.S。它做三件事聲明 multiboot2 頭、初始化棧、從 32 位保護模式切換到 64 位 long mode。multiboot2 頭的結構是固定的magic 值0xe85250d6、架構字段、長度字段、校驗和以及若干 tag。GRUB 通過掃描 ELF 前 8 KB 來尋找這個頭如果校驗和錯誤會出現error: no multiboot header found。section .multiboot align 8 multiboot_start: dd 0xe85250d6 dd 0 dd multiboot_end - multiboot_start dd -(0xe85250d6 0 (multiboot_end - multiboot_start)) ; end tag dw 0 dw 0 dd 8 multiboot_end: section .bss align 16 stack_bottom: resb 16384 stack_top: section .text global _start _start: cli mov esp, stack_top call init_long_mode lgdt [gdt64] jmp 0x08:long_mode_entry這里注意兩點。第一.multiboot段必須放在鏈接腳本最前面保證 GRUB 能在映像開頭找到。第二進入 C 代碼前必須先建立自己的棧因為在 long mode 切換之后call kernel_main需要rsp指向合法內存。long mode 切換的完整代碼比較長核心步驟如下init_long_mode: ; 關閉分頁 mov eax, cr0 and eax, 0x7fffffff mov cr0, eax ; 設置 PML4 - PDPT - PD先建立臨時頁表 mov eax, pml4 or eax, 0x3 mov cr3, eax ; 開啟 PAE mov eax, cr4 or eax, 0x20 mov cr4, eax ; 設置 EFER.LME mov ecx, 0xC0000080 rdmsr or eax, 0x100 wrmsr ; 開啟分頁和保護模式 mov eax, cr0 or eax, 0x80000001 mov cr0, eax ret頁表使用 2 MB 大頁可以簡化時間。常見做法是用 NASM 宏展開 512 項把物理地址 0 到 1 GB 區間的每個 2 MB 頁都映射一遍。這段匯編里最容易出錯的地方是CR0.PG開啟的時機以及GDT是否已經加載。順序錯了就會觸發 triple faultQEMU 表現為主機直接重啟。4.2 鏈接腳本把內核放到固定虛擬地址鏈接腳本決定內核段在 ELF 文件里的地址布局。Bare-Metal 內核通常從1M地址開始因為低 1 MB 區域被 BIOS、VGA 顯存和固件占用。ENTRY(_start) SECTIONS { . 1M; .multiboot : ALIGN(8) { *(.multiboot) } .text : ALIGN(8) { *(.text*) } .rodata : ALIGN(8) { *(.rodata*) } .data : ALIGN(8) { *(.data*) } .bss : ALIGN(8) { *(COMMON) *(.bss*) } }這里的關鍵點是.multiboot必須放在最前面。鏈接完成后用objdump -h nova-quantum.elf檢查.multiboot段的地址如果它沒有出現在文件開頭或者地址超過 4 MB都需要回頭檢查鏈接腳本。4.3 C 入口串口初始化和內存信息打印kernel.c的第一個任務是讓內核“說話”。在 bare-metal 環境里串口是最可靠的調試輸出通道。QEMU 里用-serial stdio可以把串口輸出直接顯示在終端。void serial_init(void) { outb(0x3F8 1, 0x00); // 關閉中斷 outb(0x3F8 3, 0x80); // 設置 DLAB outb(0x3F8 0, 0x03); // 波特率 38400 outb(0x3F8 1, 0x00); outb(0x3F8 3, 0x03); // 8 位數據無校驗 outb(0x3F8 2, 0xC7); // 開啟 FIFO } void kernel_main(void* mb_info) { serial_init(); printk(Nova-Quantum: bare-metal LLM kernel\n); printk(booted without OS (Bootet Ohne OS)\n); printk(multiboot2 info 0x%x\n, (uint64_t)mb_info); for (;;) { asm volatile(hlt); } }outb是端口 I/O 指令需要內聯匯編實現。printk是自己寫的極簡格式化輸出函數只支持%s、%x、%u。不要在這里引入標準庫的printf它依賴大量用戶態環境。4.4 用 GRUB 打包可啟動 ISO內核編譯出 ELF 后利用 GRUB 的grub-mkrescue生成 ISO。Makefile 至少包含編譯匯編、編譯 C、鏈接、打包四個目標。AS nasm CC x86_64-elf-gcc LD x86_64-elf-ld CFLAGS -ffreestanding -fno-pic -fno-stack-protector -mno-red-zone -O2 LDFLAGS -n -T linker.ld all: nova-quantum.iso boot.o: boot.S $(AS) -f elf64 boot.S -o boot.o kernel.o: kernel.c $(CC) $(CFLAGS) -c kernel.c -o kernel.o nova-quantum.elf: boot.o kernel.o $(LD) $(LDFLAGS) boot.o kernel.o -o nova-quantum.elf nova-quantum.iso: nova-quantum.elf model.bin grub.cfg rm -rf iso_root mkdir -p iso_root/boot/grub cp nova-quantum.elf iso_root/boot/ cp model.bin iso_root/boot/ cp grub.cfg iso_root/boot/grub/ grub-mkrescue -o nova-qu