開發 Diosix
優先順序為 安全性 > 安全性 > 正確性 > 可維護性。撰寫自我說明、記憶體安全且嚴格約束的慣用 Zig 0.17.0 與 RISC-V 組合語言,使每次更動都能在第一次審查時通過 reviewing-diosix,無需在提交前進行重構。
核心強制規範
- 可執行、完整且可建置的程式碼(基本門檻):每次更動都必須在 Root VM/Hypervisor 建置與主機單元測試套件(
./scripts/build.sh和./scripts/build.sh test)中乾淨編譯。絕不留下中斷的程式碼、存根的TODO佔位符、模擬的生產路徑或部分實作的功能。 - 行數與檔案限制(細分為子資料夾,絕不截斷):所有程式碼與註解必須在 <= 80 欄 內換行。保持原始檔 <= 500 行。當檔案超過 500 行時,絕不截斷其功能或測試;應將其分解到專用的子資料夾(
panes/vm.zig、vm/run.zig、tests/gui.zig),而不是擴充 flatprefix_subname.zig檔案(panes_vm.zig、vm_run.zig、tests_gui.zig),並將每個子模組掛接到父層的test區塊(_ = @import("vm/run.zig");)。 - 子資料夾優於前綴底線檔名,且零複製貼上:使用簡潔的
snake_case檔名,不要包含冗餘的專案、目錄或同層前綴(使用api.zig、main.c、vm/info.zig和tests/nav.zig,永遠不要使用diosix_api.zig、diosix-alsa-init.c、vm_info.zig或tests_nav.zig)。絕不在不同模組間複製共享的基本元件(如Spinlock、頁對齊運算、路徑遍歷驗證器或 ABI 常數);從hypervisor/interface/、hypervisor/core/atomic.zig或common.zig匯入它們。 - 慣用分發:切勿為命令、旗標或配置鍵撰寫
if (std.mem.eql(...)) else if (...)鏈。定義一個enum,使用std.meta.stringToEnum(EnumType, slice)進行解析,並使用switch進行分發。 - 明確的固定寬度 ABI 型別、小寫十六進位與具名位元遮罩:在所有 ABI/硬體結構(
extern struct、packed struct)與 64 位元客戶機暫存器狀態中使用明確的固定寬度型別(u64、u32、u16、u8)—— 絕不使用usize或 C 語言的unsigned long。始終使用 comptime 字面量(const w: usize = @min(n, 1280);)來標註從@min/@max初始化的區域變數,以免 Zig 推斷出一個窄整數型別(u11)而後溢出。所有十六進位字面量均以小寫書寫(0xfff、0xffff_ffff,絕不使用0xFFF),並將魔術位元遮罩/偏移量((vaddr & 0xfff) > 0xffc)替換為具名常數與自我說明的輔助函式(PAGE_OFFSET_MASK、crossesPageBoundary(vaddr, @sizeOf(u32)))。 - 動態分配優於靜態猜測:僅在堆積初始化之前執行的早期 M-mode 啟動程式碼中允許使用固定靜態緩衝區。一旦分配器可用,就應動態分配並增長緩衝區,而不是猜測固定堆疊緩衝區大小(例如,避免使用
var buf: [4096]u8)。 - 記憶體擁有權與清理:每次分配(
alloc、create、dupe、print、mmap)後立即使用defer或errdefer配對。清除已釋放的客戶機頁面與加密機密(std.crypto.secureZero)。 - 企業級 Hypervisor 隔離:絕不因客戶機輸入或狀態而在 M-mode 中引發恐慌;應返回 SBI 錯誤或終止違規的客戶機子樹。在驗證之前,將共享的客戶機記憶體複製一次(
@memcpy)到 Hypervisor 擁有的記憶體中,以防止雙重擷取(TOCTOU)漏洞。 - 程式碼中體現機制,建置/執行時配置中體現策略:絕不在 Zig 程式碼中硬編碼策略層級的設定或可調預設值。將可調參數與設定移至建置時配置(
build.zig選項 /boot/hypervisor.conf)或執行時配置檔案(/etc/diosix/*.toml,保持key = "value"在單行且不超過 80 欄)。 - 在建置時建置二進位檔與映像,而非在 Zig 中動態組裝:避免在執行時於 Zig 中逐字組裝 ELF 二進位檔、機器碼墊片或媒體映像。將墊片保留在於建置時編譯的組合語言或 Zig 原始檔中,使用專用腳本建置媒體映像,並且絕對不要將產生的建置輸出放入
tools/overlay-common/中(應使用.zig-cache/overlay-dynamic/)。 - 同地單元測試與獨立整合測試:將單元
test區塊放在它們所測試的原始檔內部(呼叫std.testing.refAllDecls(@This()))。將多元件整合測試放在專用的tests/目錄中。 - 向後相容,但不累積舊版備援:維護對外部合約(SBI 超呼叫 ABI、
/dev/diosixioctls、已記錄的dsxCLI 命令/JSON 架構,以及使用者自訂的/etc/diosix/*.toml檔案)的相容性,但絕不為同一版本管理的內部管道累積多路徑備援陣列(DEFAULT_GUEST_CANDIDATES)。當生產者與消費者在同一個儲存庫中一起發布時,應以原子方式更新所有樹內的生產者、消費者與測試,以使用單一規範路徑或符號,並在啟動/安裝邊界一次性處理持久性磁碟佈局升級,而不是永遠探測歷史路徑。 - 不確定時,停下來詢問主要維護者:絕不猜測架構決策、不明確的需求或缺失的子系統能力。在繼續之前停下來詢問主要維護者。
M-Mode 與 U-Mode 執行環境
| 面向 | M-Mode Hypervisor (hypervisor/) | U-Mode 工具 (tools/) |
|---|---|---|
| 目標 | riscv64-freestanding-none | riscv64-linux-musl(或測試時的主機) |
| 堆積前啟動 | 在 entry.s 中靜態的每核心 slab (0..31) | 不適用(OS 程序環境在 main 時已就緒) |
| 分配器 | 每核心 pcore.this().allocator.allocator() | std.heap.SafeAllocator / page_allocator / ArenaAllocator |
| 崩潰策略 | 絕不因客戶機輸入而恐慌;隔離並終止違規的客戶機 VM | 返回描述性錯誤與乾淨的退出碼 |
| 硬體存取 | 直接 CSR/MMIO(必須用 if (is_test) 包裝以進行主機單元測試) | /dev/diosix ioctls(api.zig)、DRM/evdev、Linux 系統呼叫 |
重點參考指南
在撰寫或修改程式碼前,請閱讀相關的參考檔案:
- Zig 0.17.0 慣用語法與內建函數:
最新的 Zig 0.17 語法(
@backingInt、@splat、allocator.print、SafeAllocator、stringToEnum、適用於extern struct的@ptrCast、固定寬度 ABI 型別、帶有類型註解的@min、80 欄格式化與尾隨逗號,以及建置快取純粹性)。 - 記憶體管理與動態緩衝區:
M-mode 與 U-mode 分配器模式、動態緩衝區增長、
defer/errdefer規範、機密清除以及輸出指標初始化。 - 架構與 TigerStyle: 完整功能實作、不遺失單元測試的模組化檔案分割、零複製貼上重複、有界迴圈、斷言配對,以及覆蓋層/配置管理規範。
- RISC-V 與企業級 Hypervisor: RV64 組合語言慣例、CSR 模擬、爆炸半徑控制、雙重擷取防範模式、IRQ 安全的自旋鎖定順序,以及 G-stage/PMP 隔離。