# Tinker-V 先按照[官方說明](https://github.com/TinkerBoard/TinkerBoard/wiki/Tinker-V)將 bootloader, Kernel image 燒錄到板子上,裡面有用到 Tera term 傳送 Flash Writer 到板子上的操作,我不知道如何在 Linux 上面做,所以都是在 Windows 上面用好,確定透過 UART 看 log、下命令,才到 Ubuntu 上面改用 [screen](https://linux.die.net/man/1/screen) 連線到板子上 ## 注意事項: 1. Tinker-V 用到的 glibc 版本為 2.28,如果用新版的 toolchain 編譯出來的 box64 會找不到新版 glibc,執行起來就像下面這樣 ``` root@rzfive-tinker-v:~/tests# ./box64_v2 ./x86/puzzle ./box64_v2: /lib/libc.so.6: version `GLIBC_2.29' not found (required by ./box64_v2) ./box64_v2: /lib/libc.so.6: version `GLIBC_2.33' not found (required by ./box64_v2) ./box64_v2: /lib/libc.so.6: version `GLIBC_2.38' not found (required by ./box64_v2) ./box64_v2: /lib/libc.so.6: version `GLIBC_2.32' not found (required by ./box64_v2) ./box64_v2: /lib/libc.so.6: version `GLIBC_2.34' not found (required by ./box64_v2) ``` 2. 當 Tinker-V 接好 UART 到電腦上,可以找 `/dev` 底下有沒有 `/dev/ttyUSB{id}`,確定裝置後用 screen 連線到 Tinker-V 上面,鮑率要設 115200 ```shell $ ls /dev | grep USB /dev/ttyUSB0 $ sudo screen /dev/ttyUSB1 115200 ``` 這時候應該能夠看 `rzfive-tinker-v login:`,輸入 `root` 即可登入 3. screen 沒辦法捲動終端機,或許可以試試看 PuTTY 有時候 UART 會遇到下面這些問題,遇到的話就把 RS232 拔掉重連,或是拔電源重開 - 打字 lag。偶爾會延遲 1~2 秒才出現之前打的字 - 打字會出現前一次的字。例如輸入 `abc`,當輸入到 b 才會出現 a,輸入到 c 才出現 b,最後印出的是 `ab` - 亂碼? 有時候會無法用 backspace 刪除字元,所以會一直出現 log 把螢幕填滿,讓畫面很混亂,甚至打的字都不會印出 4. GPIO 佔用 kernel 使用 patching 詳見 : [issue](https://github.com/TinkerBoard/TinkerBoard/issues/11) 5. glib2.0 來源遺失 修改 recipe ,詳見:[issue](https://github.com/TinkerBoard/TinkerBoard/issues/12) 6. 修改 `linux_libc_headers_5.10.bb` 缺少 checksum 在 `linux_libc_headers_5.10.bb` 中添加 : ```shell SRC_URI[sha256sum] = "c1d276741f8387da5aab790954e7486354feb7de2c830f123ea830a1723bf604" ``` 7. `glibc-2.28-r0 do_fetch`: Fetcher failure 要將 meta-renesas/meta-rz-common/recipes-debian/buster/source 內的 glibc.inc 改為: ```shell # This is generated by debian-source.bbclass DPV = "2.28-10+deb10u4" DPV_EPOCH = "" REPACK_PV = "2.28" PV = "2.28" DEBIAN_SRC_URI = " \ ${DEBIAN_SECURITY_UPDATE_MIRROR}/main/g/glibc/glibc_2.28-10+deb10u4.dsc;name=glibc_2.28-10+deb10u4.dsc \ ${DEBIAN_SECURITY_UPDATE_MIRROR}/main/g/glibc/glibc_2.28.orig.tar.xz;name=glibc_2.28.orig.tar.xz \ ${DEBIAN_SECURITY_UPDATE_MIRROR}/main/g/glibc/glibc_2.28-10+deb10u4.debian.tar.xz;name=glibc_2.28-10+deb10u4.debian.tar.xz \ " SRC_URI[glibc_2.28-10+deb10u4.dsc.md5sum] = "b39dd7f7f54c6b7da3eefcd391470af2" SRC_URI[glibc_2.28.orig.tar.xz.md5sum] = "2d78d5b080fbe4fefa2e1ccef9c39dbc" SRC_URI[glibc_2.28-10+deb10u4.debian.tar.xz.md5sum] = "8ebb6ee80ba6a5e39eacc31c95994ef0" SRC_URI[glibc_2.28-10+deb10u4.dsc.sha256sum] = "55e4ebd9a55755c84d42709b23f9b269f46b6a76f5040a0e05cfd323ba67f8af" SRC_URI[glibc_2.28.orig.tar.xz.sha256sum] = "53d3c1c7bff0fb25d4c7874bf13435dc44a71fd7dd5ffc9bfdcb513cdfc36854" SRC_URI[glibc_2.28-10+deb10u4.debian.tar.xz.sha256sum] = "dc287870d4b8cb5d1d175fa9b95e3a97d6b68699680b443ae7b2a1b89f0fe8fc" ``` --- ## Box64 ### 安裝 Toolchain :::warning 本部分資訊已過時 ::: 要用舊版 RISC-V 編譯器來編譯 box64 才能夠在板子上面執行,需下載 glibc 版本的 [toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases/tag/2021.01.26) 來用,解壓縮到 `/opt` 並更新好 `PATH` 變數後,應能夠在終端機使用到 toolchain 提供的執行檔 ```shell $ riscv64-unknown-linux-gnu-gcc --version riscv64-unknown-linux-gnu-gcc (GCC) 10.2.0 Copyright (C) 2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ``` ### 更新 library 如果要用 QEMU 來執行 box64 的程式,會遇到某些 library 找不到(e.g. `ld-linux-riscv64-lp64d.so.1`),可以將 `{toolchain_path}/sysroot/lib` 更新到 `LD_LIBRARY_PATH` Note: 新版的 toolchain 在 `bin/` 目錄底下會有 QEMU 可以使用 ``` export LD_LIBRARY_PATH="/opt/riscv64-unknown-linux-gnu_1320/lib:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH="/opt/riscv64-unknown-linux-gnu_1320/sysroot/lib:$LD_LIBRARY_PATH" ``` ### 更新 man page(非必要) 如果要用 man 來閱讀 toolchain 的文件,可以將 toolchain 提供的 man 目錄複製到 PC 的 `/usr/local/share/man/` 底下 ``` > sudo cp -r /opt/riscv64-unknown-linux-gnu_1320/share/man/man5 /usr/local/share/man/man5 ``` 複製好後就可以使用 man 來閱讀 toolchain 的文件了 ``` > man riscv64-unknown-linux-gnu-gcc ``` ### 編譯 box64 :::warning 使用最新的 [GNU Toolchain for RISC-V](https://github.com/riscv-collab/riscv-gnu-toolchain/releases),選 `riscv64-glibc-ubuntu-20.04-gcc-nightly` ::: 安裝 ninja 以加快編譯: ```shell $ sudo apt-get install ninja-build ``` 編譯 box64 可以設定幾個選項來編譯,詳細可以看[官方文件](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md),這裡我主要針對 RISC-V 配置編譯選項,最後 make 時,用 bear 輸出 `compile_commands.json` 給 [clangd](https://clangd.llvm.org/) 來分析程式碼,以便用來 trace code ```shell $ mkdir -m 777 build $ cd build $ cmake \ -G Ninja \ -D RV64=1 -D RV64_DYNAREC=ON \ -D CMAKE_BUILD_TYPE=RelWithDebInfo \ -D CMAKE_C_COMPILER=riscv64-unknown-linux-gnu-gcc \ .. $ ninja ``` 預期可見到 `box64` 執行檔,注意在連結階段可能會等待較長時間,之後可改用 mold。 由於 `box64` 使用新版 toolchain 內附的 glibc,因此會遇到跟原本 rootfs 裡頭 glibc 符號不匹配的狀況,因此可利用 [patchelf](https://github.com/NixOS/patchelf) 工具,修改動態連結器和函式庫的位置。首先安裝 [patchelf](https://github.com/NixOS/patchelf): ```shell $ git clone https://github.com/NixOS/patchelf $ cd patchelf $ ./bootstrap.sh $ ./configure --prefix=/usr $ make $ sudo make install ``` 利用 [patchelf](https://github.com/NixOS/patchelf) 修改上面產生的 `box64` 執行檔: (假設切換到 `box64/build` 目錄) ```shell $ patchelf --set-rpath /lib:/lib/custom box64 $ patchelf --set-interpreter /lib/custom/ld-linux-riscv64-lp64d.so.1 box64 ``` 先準備 `/lib/custom` 目錄和從 GNU Toolchain 複製必要檔案: (`__TOOLCHAIN__` 是從 [GNU Toolchain for RISC-V](https://github.com/riscv-collab/riscv-gnu-toolchain/releases) 取得並解開的目錄) ```shell $ mkdir -p sysroot/lib/custom $ cp __TOOLCHAIN__/sysroot/lib/*.so* sysroot/lib/custom ``` 接著利用 QEMU 測試: ```shell $ qemu-riscv64 -L sysroot box64 --help ``` 預期可見到: ``` Dynarec for RISC-V With extension: I M A F D C Zba Zbb Zbc Zbs Vector (vlen: 128) ... This is Box64, The Linux x86_64 emulator with a twist ... ``` 接著可用 `box64` 執行預先編譯好的 x86-64 執行檔,例如 `/bin/busybox`。 將上述 `sysroot/lib/custom` 目錄的內容,放到 Tinker V 的檔案系統中,確保 `/lib/custom` 目錄包含 `ld-linux-riscv64-lp64d.so.1` 和 `libc.so.6` 在內的動態連結函式庫檔案。 為了在 x86-64 主機測試更多程式,進行以下準備: (記得修改 `box64/build` 的路徑) ```shell $ sudo su - $ cd /lib $ ln -s box64/build/sysroot/lib/custom . $ exit ``` 執行 xlogo 程式: ```shell $ qemu-riscv64 -L sysroot box64 /usr/bin/xlogo ``` 預期可見 `X` 字樣的視窗。 #### 使用 mold 來縮減連結時間 Rui Ueyama 是一位高產的開放原始碼先鋒,他常帶給技術社群各式驚喜,代表作品像是 8cc (短小精悍且可 self-hosting) 和 lld (LLVM linker,比 GNU gold 或 Microsoft Visual Studio linker 快)。他從 2020 年 9 月開始發展名為 mold 的新連結器 (linker),並於 2022 年初發布 mold 連結器的 1.0 版,以更快的演算法和高效的內部結構,獲得比 LLVM 的 lld 更快的表現,引起許多開發者的重視,GCC 12 也納入相關的支援。 通常構建時間 (build time) 由編譯時間和連結時間組成。與編譯時間相比,後者可藉由 Ninja 和 ccache 等工具加速,連結時間主要依賴於連結器本身的效率。因此,連結器的速度至關重要,mold 無疑是目前開放原始碼實作效率最高,且有足夠好相容性的專案,例如 LLVM 子專案 lld 儘管也強調平行化的連結,但不支援 GCC LTO,而 GNU gold 一開始要跳脫 GNU ld 的效能限制,但現在 gold 發展停滯。 安裝 mold: ```shell $ curl -L -o mold.tar.gz https://github.com/rui314/mold/releases/download/v2.34.1/mold-2.34.1-x86_64-linux.tar.gz $ sudo tar -xz --strip-components=1 -C /usr/ -f mold.tar.gz ``` 在上述的 `cmake` 階段,要增加 `-D WITH_MOLD=1` 選項,重新執行 `cmake` 後,執行以下: ``` $ mold -run ninja ``` 在 Intel Xeon CPU E5-2650 v4 @ 2.20GHz 機器上,原本要花 7 分鐘建構 `box64`,利用 mold 則縮減到 4 分鐘 ## clangd 可觀看[撿到槍的系統軟體工程師 GDB&VScode](https://youtu.be/OLeCNFtb1EE?si=f5rINofBC7N4R4aT) ,大致了解 clangd 的配置和用途。 建議在 VSCode 的 user setting 加入關閉自動插入 header 的設定,有時候會引入到不對的 header ```json "clangd.arguments": [ "--header-insertion=never", ], ``` clangd 還有哪些 arguments 可以修改?請在終端機輸入 `clangd --help` ### `.clangd` 示範 `.clangd` 為 clangd 的設定檔,一般來說會放在 project 的根目錄,細節可以看[文件](https://clangd.llvm.org/config),這裡示範如何在不同環境下引入 header files。例如使用不同的 ARM 或是 RISC-V toolchain 會有自己的 C library,如果在 x86 的 PC 上面練習 RISC-V 的 C code,對程式碼的 `memset` 跳躍到定義,會跳到 `usr/include/string.h`,顯然這不是真正被宣告的路徑。 上述例子看似沒什麼大不了,toolchain 都應該支援標準的 C headers,那麽如果要在 PC 上練習 ARM 的 neon 指令,VSCode 就會找不到 `arm_neon.h`,還是可以 ARM 的 toolchain 編譯,但就是不方便 trace code,下面那 RISC-V 和 Kernel module 為例。 如果要用 RISC-V 的 toolchain 來開發,可以在 `.clangd` 的 compiler flags 加上 headers 的路徑,改完後重新啟動 clangd,找一個 standard C 函式 goto defination,例如 `printf` 就會跳到 toolchain 的 `stdio.h`,而不是 `/usr/include/stdio.h` ```yaml CompileFlags: Add: [-I/opt/riscv64-unknown-linux-gnu_1320/sysroot/usr/include] Remove: -W* Compiler: riscv64-unknown-linux-gnu-gcc ``` 反之如果要開發 Kernel module 就可以把 `-I` 改成 `usr/src/` 底下的 *Linux*/include,可用 echo 搭配 `uname -r` 查看 Kernel version ```bash $ echo /usr/src/linux-headers-`uname -r`/include /usr/src/linux-headers-6.8.0-40-generic/include ``` 把 include 的路徑貼到 `.clangd` 即可 ```yaml CompileFlags: Add: [-I/usr/src/linux-headers-6.8.0-40-generic/include] Remove: -W* Compiler: gcc ``` 這樣就可以跳躍到 Kernel 的 headers,寫程式也會跳出 Kernel 函式的提示字 例如下面兩個是 Kernel module 會用到的 header,一般情況下,VSCode 找不到路徑,按上述修改完路徑,就能跳躍過去 ```c #include <linux/printk.h> #include <linux/slab.h> ``` 如此一來,就算換成開發板提供的 toolchain,只要加入 headers 的路徑到 `.clangd` 就能夠讓 VSCode 跳躍到實際宣告的 header 或函式的實作。 ## 編譯 x86 程式 :::warning `-static` 非必要,且為了讓 box64 能善用 wrapper,應儘量採用動態連結 (即預設編譯組態)。 ::: 編譯 x86 的程式要加上 `-static`,因為環境從 PC 換到 Tinker-V,板子不一定會有 PC 的函式庫,避免板子找不到函式庫而無法執行。以 [rv32emu](https://github.com/sysprog21/rv32emu) 的 puzzle.c 為例 ```shell > gcc -static puzzle.c -o puzzle_x86 ``` 編譯完之後可以存到 SD 卡或是 USB, - [ ] SD 卡 可以在板子上用 `fdsik -l` 來看是 SD 卡的裝置是那一個 掛載 SD card 到 `/media` ``` mount -t ext4 /dev/mmcblk1p2 /media mount -t ext4 /dev/sda /media ``` 卸載 ``` umount /media ``` - [ ] USB(OTG) 如果程式存到 USB 可以透過 micro USB(OTG) 接到板子上再掛載到指定目錄,載入方式和 SD 卡一樣 >[!Note] >或許也可以透過某種方式用 wget 來下載程式到板子上就不用每次都要插拔儲存裝置?之前有用過網路線接到板子後可以使用 wget 下載檔案 ## 遠端連線 ### WinSCP 1. 下載並安裝 WinSCP 2. 使用網路線連接板子與 PC 3. 用`ifconfig` 獲得 `inet addr` 4. 用inet addr登入 接著就可以傳輸、刪除檔案,如下圖所示: ![image](https://hackmd.io/_uploads/r14IagKkJe.png) 也可以使用 ssh 來操控 tinker-v 的終端機 ```shell $ ssh root@{inet addr} ``` ### scp Linux PC 可以先將自己的 public key 加入到 Tinker-V 的 `~/.ssh/authorized_keys`,往後複製檔案和連線都不必輸入密碼 Tinker-V 和 PC 都要 SSH key-gen,如果已經 keygen 過的話可以省略 ``` $ ssh-keygen -t ed25519 -b 4096 -C "your_email@example.com" ``` 將 PC 的公鑰內容複製好,複製公鑰到遠端主機的 authorized_keys ``` $ ssh-copy-id {user}@{inet addr} ``` Windows 可以用下面的命令達成 `ssh-copy-id` 的效果 ```powershell type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh {your_host} "cat >> .ssh/authorized_keys" ``` VSCode 沒辦法用 SSH 連線到 Tinker-V,會出現下面的錯誤訊息,但還是可以在 VSCode 的終端機用 ssh 命令來連線,這樣就不必透過 screen 了 >Resolver error: Error: The remote host's architecture is not supported ### Tinker-V 傳資料到 PC 先把 Tinker-V 的公鑰內容複製到 PC 端的 `~/.ssh/authorized_keys` 再開啟 PC 的 ssh server 的功能 ```shell $ sudo apt-get install openssh-server $ sudo service ssh start ``` 在 Tinker-V 上面一樣使用 scp 傳檔案到 PC 端,PC 的 IP 地址一樣用 `ifconfig` 查詢,user 就是 `whoami` 命令輸出的名稱 ```shell $ scp ./msg.txt lambert-wu@{PC inet addr}:~/Documents ``` Tinker-V 傳完檔案後可以在 PC 的 `~/Documents` 目錄確認有沒有 `msg.txt` 如果開啟 SSH server 不放心的話,可以用下面的命令關掉 ssh service ``` $ sudo service ssh stop Stopping 'ssh.service', but its triggering units are still active: ssh.socket $ sudo service disable --now ssh.socket $ systemctl -a | grep ssh ``` `systemctl -a | grep ssh` 用來確認 ssh 相關的服務是不是 `inactive dead` 的狀態 # 執行 box64 當 box64 和 x86 程式都在 Tinker-V 上面,就可以測試了 ``` >./box64 ./puzzle_x86 ``` 目前使用幾個 rv32emu 的 test cases 在 box64 上面執行,大部分沒遇到 crash 問題,但是有些程式會執行很久。 executable 空白欄位表示程式可以執行,但執行時間要很久,沒有完全執行完,先終止掉 | program | executable | Note | | ---------- | ---------- | ---- | | aes | Y | | | donut | Y | | | hamilton | | 執行太久,用 time 來測量,到 `mapping edges` 終止,已達 181m | | lena | Y | | | mandelbrot | Y | | | nqueens | Y | 大約 size = 12 後會變慢 | | pi | Y | | | qrcode | Y | | | rvsim | Y | | | stream | | | | captcha | Y | | | fcalc | Y | | | jit | N | segement fault | | line | Y | | | mt19937 | Y | | | nyancat | Y | 中止程式後,畫面會看不到游標,使用 clear 依舊如此,但還是可以打字下命令 | | puzzle | Y | | | richards | | | | spirograph | Y | 會影響到終端機顯示,同 nyancat | | test-path | Y | | 推薦先讀 box64 官方的 [blog](https://box86.org/blog/) 找幾篇相關的文章來了解 box64 的運作,像是 [Inner workings](https://box86.org/2021/07/inner-workings-a-high%E2%80%91level-view-of-box86-and-a-low%E2%80%91level-view-of-the-dynarec/) # Benchmarking 利用 /usr/bin/time -p 測量 RV64 和 box64 對應的執行時間: (user time) | Benchmark Name | RV64 | x86-64 | |----------------|-------|---------| | aes | 3.41 | 482.13 | | dhrystone | 1.05 | 353.21 | | miniz | 9.74 | 1612.67 | | norx | 2.47 | 214.66 | | primes | 16.01 | 678.36 | | qsort | 3.52 | 795.05 | | sha512 | 2.01 | 395.96 | 使用動態連結之後的數據: (user time) 註: 會遇到 `sh: relocation error: /lib/custom/libc.so.6: symbol __nptl_set_robust_list_avail version GLIBC_PRIVATE not defined in file ld-linux-riscv64-lp64d.so.1 with link time reference` ,但輸出正確,原因待查明 使用動態編譯後: | Benchmark Name | RV64 | x86-64 | |----------------|-------|---------| | aes | 4.06 | 8.37 | | dhystone | 1.17 | 33.86 | | miniz | 11.79 | 181.11 | | norx | 2.8 | 4.51 | | primes | 18.54 | 24.82 | | sha512 | 2.25 | 3.97 | | NBench | 206.93 | 211.38 | | Coremark | 16.10 | 22.60 | | whetstonez | 4.16 | 51.87 | 更新後的數據 ```shell Dynarec for RISC-V With extension: I M A F D C PageSize:4096 Running on unknown riscv64 cpu with 1 Cores Will use Hardware counter measured at 12.0 MHz emulating 3.0 GHz Params database has 14 entries Box64 with Dynarec v0.3.1 126cf279 built on Nov 1 2024 18:08:42 ``` | Benchmark Name | RV64 | x86-64 | |----------------|-------|---------| | aes | 3.01 | 6.32 | | dhrystone | 1.17 | 26.39 | | miniz | 9.43 | 145.21 | | norx | 2.23 | 3.38 | | primes | 15.84 | 21.03 | | qsort | 2.97 | 124.39 | | sha512 | 2.00 | 3.20 | | NBench | 205.80 | 209.08 | | Coremark | 9.79 | 9.67 | | whetstonez | 3.38 | 47.42 | --- ## Use case 在 Tinker V 上面執行 proprietary x86-64 (closed source) 的程式: 在完全不用 recompile 程式的前提 (事實上,也沒辦法做到,因為沒辦法取得原始程式碼),利用 box64 Tinker V (RV64) 在模擬 x86-64 程式,並利用 X11 forwarding,將視窗操作導向到具備 顯示及輸入的裝置,過程中,proprietary x86-64 的程式沒有任何洩漏的風險,且運行效率尚可,亦即 將 Tinker V 視為 Hardware Security Modules (HSM),換言之,在 Tinker V 上面可執行密碼學 或者涉及特定領域專業之演算法,在最小資訊揭露的前提,進行裝置之間的互動。 TODO: 撰寫 X11 forwarding 原理 TODO: 製作 Hardware Security Modules (HSM) 介紹圖文 ---