
最終目標就是要在 Tiny Tapeout (TT) 開一顆 SoC ,不過在這之前,我也想先做一些實驗,驗證這些想法是否可行。
KianRiscV 是一顆完整的 RISC-V CPU,也在 TT 開過 IC,但這顆對我們來說還是太大了(雖然說太大也只大一點)。為了省錢,而且這麼大顆也沒有必要,所以我們還是要縮小 Size。在 kianRiscV/linux_socs/kianv_harris_mcycle_edition 下,看說明是在 ULX3S 85F(FPGA Lattice ECP5 LFE5U-85F-6BG381C,有 Open Source 的 Tool)下也可以執行的 uLinux RISC-V CPU core,不僅符合我的目標,而且對我超級友善啊。
裡面還有預設的 Linux kernel 6.1.14 和一個 busybox initramfs,不過我就想,要就做全套嘛,不如把 Linux kernel 換到最新的 7.1 試試看?換到 Linux kernel 7.1 後,碰到的
第一個問題是 Image 太大,Bootloader 預設的 memcpy 量不夠大
Booloader memcpy 從 4MB 改到 6MB就可以解決
第二個問題:”broken padding”
用 `dd` 從舊 kernel 複製 initramfs,但新 kernel 會出現問題,必須用 `fakeroot` 重新打包一份新的 cpio image。
第三個問題:使用預設的 initramfs 開機時,無法進入 shell
錯誤訊息如下
[ 40.383751] TERM=linux
sh: waitpid: Function not implemented
sh: waitpid: Function not implemented
sh: waitpid: Function not implemented
sh: waitpid: Function not implemented
sh: waitpid: Function not implemented
init started: BusyBox v1.36.0 (2023-05-16 20:02:22 CEST)
starting pid 18, tty '': '/etc/init.d/rcS'
sh: waitpid: Function not implemented
sh: waitpid: Function not implemented
sh: waitpid: Function not implemented
sh: waitpid: Function not implemented
mkdir: can't create directory '/': Function not implemented
mkdir: can't create directory '/': Function not implemented
mount: mounting devpts on /dev/pts failed: No such file or directory
mount: mounting tmpfs on /dev/shm failed: No such file or directory
這個問題是,Linux kernel mainline 的 RISC-V 32-bit 是 “time64-only” 架構:它是在 y2038 之後才進入 kernel 的,所以「刻意」不提供那些使用 32-bit 時間的舊 syscall(wait4、gettimeofday……)。而舊的 initramfs 是舊架構的,因此呼叫就會出錯,這需要換成新的 rootfs 來解決。在我處理的時候,buildroot 已經可以產生這個方案,使用 uClibc-ng 函式庫就可以了。
第四個問題:”out of memory”
[ 47.660665] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100 ]---
sh: out of memory
out of memory
本來以為是 bFLT 的 heap/stack 不夠,所以把 stack 從 16KB 改為 1MB——結果沒用。最後發現這個問題和第六個問題是一樣的,本質上是 malloc 的問題。
第五個問題:解完以上的問題之後,還是沒進到 shell,但是也沒有錯誤訊息。
因為大部分都是 AI 解的,所以這邊 AI 也寫了一個程式,不過編譯的時候沒加 `-fPIC`,對 nommu 的 flat binary 來說,程式被載到記憶體的任意位置,所有位址都得是「位置無關」的。non-PIC 的程式用絕對位址(`lui aX, 0xNNN`)去抓字串或全域變數。這件事我知道,但是不常碰到,也很難意會到。光這個 Bug 就解了十輪左右,Claude 還想繼續解,但是我覺得應該要換個思路。
最後是自己去找了 mini-rv32ima,請 AI 分析差異在哪邊,AI 分析的同時還用了 qemu 直接執行程式(哎呀,我怎麼沒想到)。Claude 用了 qemu 後速度就快多了,很快就找到問題是在 -fPIC。
第六個問題:malloc 在 nommu 上回 NULL
直接 mmap 一塊記憶體 → 成功;但 malloc 任何大小 → 都回傳 NULL。把 uClibc 改成 MALLOC_SIMPLE(純 mmap、為小系統設計的實作)就可以了。
雖然中間 claude 走錯很多次路,都需要人為校正回來,尤其是 -fPIC 這件事,我也沒意會到,只是覺得應該不會這樣複雜,所以試著要走別的路。這種經驗性的問題 Claude 是無法即時察覺的。或許 YOLO mode 可能可以最終也取得成本,但是這中間應該還要多燒更多的 tokens 達到目地,例如也有可能 AI 解不掉就生氣重寫一個 shell 或是大改 Linux kernel 之類的。
不過跟 AI debug 的過程還頗有趣的,想法和解題思路很像我會做的事,可能最終我也會走到這邊,但是花的時間會多非常非常多,畢竟以前就幹過類似的事情,只能說青春不值錢啊。以前和現在最大的差別是,有了 AI agents,我應該沒這個耐心自己解題,而是用 supervisor 的角度去解決問題。其實電腦科技發展一直是節省大家時間的,只是效果不會像 AI agents 這麼明顯,像是 assembly 到 C,或是第一次有了 database,dbase 大行其道,perl/php/甚至是 python 對 C/C++ 的衝擊。不過問題還是在於,會去研究底層的人會愈來愈少,但是未來可能會有更多新的不同的工具。但是這也沒關係,有需求就是有人會去弄的(或是花錢找人弄)。就像現在 assembly 很少人會寫,要用到的時候再寫個一點,但是我小時候,大家都要學上一些 assembly,望向我用 Microsoft ASM 寫 editor 的經歷,雖然曾經寫過,但是現在要不要學做 CPU,我也不太想碰 assembly 了。

發佈留言