F07: riscv

主講人: jserv / 課程討論區: 2019 年系統軟體課程
:mega: 返回「Linux 核心設計」課程進度表

預期目標

  • 熟悉 GNU Toolchain 相關開發工具
  • 接觸 RISC-V 處理器架構
  • 客製化 Buildroot
  • 學習系統模擬器的內部運作機制

RISC-V 處理器架構

  • 為何要學 RISC-V 呢?跟著「台灣之光」衝
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
    • Andes Technology (晶心科技) 是亞洲地區唯一的 CPU 矽智財供應商,自主開發並提供處理器與周邊平台矽智財以及相關開發工具與軟體。根據 Linley 的調查顯示,晶心市佔率排名全球第 5
  • Embedded Linux on RISC-V
    • Linux 核心和 gcc 在內的 GNU Toolchain 已正式支援 RISC-V
    • BBL: Berkeley Boot Loader
  • RISC-V: Open Hardware for Your Open Source Software (2017)
  • RISC-V Tutorial + PULP

Fabrice Bellard

  • 引自 Fabrice Bellard 是個什麼水平的程序員?計算的威力,智慧的傳奇 —— Fabrice Bellard
    • 上大學前重寫 LZSS 壓縮演算法,解壓軟體速度快體積小
    • 1997 年 1 月 20 日,發佈最快速的計算圓周率的計算程式,是 Bailey-Borwein-Plouffe 公式 的變形,前者的時間複雜度是 O(n3),他改善為 O(n2),使得計算速度提高 43%,這是他在數學領域的成就。此時他僅 25 歲
    • 2000 年他化名 Gérard Lantau,建立 FFmpeg 專案,做過多媒體影音處理的人應該都知道這個專案到底多強大
    • YouTube, VLC, MPlayer 等知名服務和軟體採用 FFmpeg 的編解碼函式庫
    • FFmpeg 易擴展、功能強、速度快、佔資源少,支持的影音格式極其廣泛,超越其他所有同類軟體,這是他在多媒體處理領域的巨大成就
    • 2000-2001 年,贏得兩次國際混淆 C 程式碼大賽 (IOCCC) 獎項
      • 第一個作品是 4 KB 大小的 C 語言編譯器子集 OTCC,這可以算作是 TinyCC 的前身
      • 第二個作品以 475B 這麼小的程式碼實作高效能的找尋質數程式,用傅立葉轉換實現
    • 2002 年他發佈 TinyGL,這是 OpenGL 的一個子集實作,體積小速度快,佔資源還少,這是他在圖像處理領域的成就
    • 2003 年開發 Emacs 的一個變種 QEmacs
    • 2004 年 8 月在之前 OTCC 的基礎上繼續開發,使之具備能夠編譯 Linux 核心的能力,這就是 TinyCC 的正式版,簡稱 TCC
      • 為了證明 TCC 的威力,他又寫了一個只有 138KB 的 boot loader,稱為 TCCBOOT,可在 15 秒內從原始程式碼編譯並啟動 Linux 核心
    • 2005 年發佈 QEMU,這是個爆炸性的項目,現在眾多底層開發人員已經離不開它了,這需要非常廣泛的底層硬體和作業系統等等知識
      • QEMU 的技術已經被應用於 KVM, Xen, VirtualBox 等多個虛擬化專案
    • 2005 年用普通個人電腦和 VGA 顯示卡設計一個數位電視系統
    • 2009 年 12 月 31 日,聲稱打破圓周率計算的世界紀錄,僅用一台普通個人電腦,耗時 116 天,算出圓周率小數點後 2.7 兆位,比 2009年 8 月 17 日由超級計算機算出的世界紀錄多 1200 億位
      • 憑藉這個突出的數學貢獻,登上《科學美國人》法文版
    • 2011 年,用 JavaScript 開發出模擬 Intel x86 為基礎的個人電腦的模擬器
      • 包含一個 32-bit 的 x86 相容處理器、8259 可程式化中斷控制器、8254 可程式化中斷計時器,和 16450 UART
  • 繼續看 Wikipedia 的 詞目
  • TinyEMU 是 Fabrice Bellard 近期作品,支援 RISC-V 和 Intel x86 架構的系統模擬

riscv-emu

以下操作均在 GNU/Linux 環境中進行,在模擬器內執行 RISC-V/Linux,反應時間可能會大幅增加,請保持耐心

命令標示方式:

  • $ 開頭表示在 Host 端 GNU/Linux 輸入的命令,也就是你平常的作業環境
  • ~# 開頭表示在 riscv-emu 模擬環境中的 RISCV/Linux 命令環境中輸入的命令。這樣的模擬環境簡稱 Guest 端
$ sudo apt install libsdl2-dev libssl-dev libcurl4-openssl-dev
  • 編譯和執行
$ make
$ ./temu
temu version 2019-02-10, Copyright (c) 2016-2018 Fabrice Bellard
usage: riscvemu [options] config_file
options are:
-m ram_size       set the RAM size in MB
-rw               allow write access to the disk image (default=snapshot)
-ctrlc            the C-c key stops the emulator instead of being sent to the
                  emulated software
-append cmdline   append cmdline to the kernel command line

Console keys:
Press C-a x to exit the emulator, C-a h to get some help.
  • 透過 riscv-emu 載入預先準備好的 RISC-V/Linux 核心映像檔案和 root file system,確保你的網路連線無誤
$ ./temu https://bellard.org/jslinux/buildroot-riscv64.cfg

請耐心等待,過程中程式會自上述網址下載對應的檔案。
預期會看到以下輸出:

Welcome to JS/Linux (riscv64)
 
Use 'vflogin username' to connect to your account.
You can create a new account at https://vfsync.org/signup .
Use 'export_file filename' to export a file to your computer.
Imported files are written to the home directory.

[root@localhost ~]# 

當看到上方 [root@localhost ~]# 命令提示訊息時,就可以輸入 GNU/Linux 常見命令,如 uname -aps

ls 觀察,可發現 /root 目錄下已有 readme.txt 檔案,請用 cat readme.txt 觀察並作配合的實驗。

例如計算圓周率:

~# tinypi 1000 pi.txt
~# cat pi.txt

甚至可在 risc64 模擬環境中模擬 riscv128:

~# riscvemu128 -m 16 rv128test.bin

預期輸出結果:

RISCV dynamic base ISA change:
RV128I: max register value=340282366920938463463374607431768211455
FP128:  sqrt(2)=1.414213562373095048801688724209698
RV64I:  max register value=18446744073709551615
FP64:   sqrt(2)=1.414213562373095
RV32I:  max register value=4294967295
FP32:   sqrt(2)=1.414213

Power off.

當要離開 riscv-emu 時,先按下 Ctrl-A 組合鍵,「放開後再按」 x

假設目前目錄為 $HOME/riscv-emu,我們設定 $PATH 環境變數,讓之後方便使用:

$ export PATH=`pwd`:$PATH

接著取得預先準備好的 diskimage:

$ cd /tmp
$ wget https://bellard.org/tinyemu/diskimage-linux-riscv-2018-09-23.tar.gz
$ tar zxvf diskimage-linux-riscv-2018-09-23.tar.gz

切換到解開的 diskimage 目錄並啟動模擬器:

$ cd diskimage-linux-riscv-2018-09-23
$ temu root-riscv64.cfg

預期將看到以下輸出:

[    0.406021] NET: Registered protocol family 17
[    0.406693] 9pnet: Installing 9P2000 support
[    0.411081] EXT4-fs (vda): couldn't mount as ext3 due to feature incompatibilities
[    0.412022] EXT4-fs (vda): mounting ext2 file system using the ext4 subsystem
[    0.420029] EXT4-fs (vda): mounted filesystem without journal. Opts: (null)
[    0.420326] VFS: Mounted root (ext2 filesystem) on device 254:0.
[    0.421026] devtmpfs: mounted
[    0.421493] Freeing unused kernel memory: 80K
[    0.421664] This architecture does not have kernel memory protection.
~ # 

檢查處理器架構和核心資訊:

~# uname -a

預期輸出為:

Linux localhost 4.15.0-00049-ga3b1e7a-dirty #10 Thu Sep 13 20:03:10 CEST 2018 riscv64 GNU/Linux

繼續輸入以下命令,觀察輸出結果:

  • cat /proc/cpuinfo
  • cat /proc/meminfo
  • cat /proc/cmdline
  • cat /proc/devices
  • cat /proc/interrupts
  • cat /proc/loadavg

先離開模擬器 (按下 Ctrl-A 組合鍵,放開後再按 x 鍵),編輯檔案 root_9p-riscv64.cfg,確保內容如下:

{ 
    version: 1,
    machine: "riscv64",
    memory_size: 128,
    bios: "bbl64.bin",
    kernel: "kernel-riscv64.bin",           
    cmdline: "console=hvc0 root=/dev/vda rw",
    drive0: { file: "root-riscv64.bin" },
    fs0: { tag: "/dev/root", file: "/tmp" },
    eth0: { driver: "user" },
}

也就是新增 kernel: "kernel-riscv64.bin" 這行。

啟動模擬器:

$ temu root_9p-riscv64.cfg

當看到 ~ # 命令提示訊息時,輸入以下命令:

~# mount -t 9p /dev/root /mnt

上述命令是透過 VirtFS 掛載 Host 端檔案系統到 Guest 端,驗證方式:

~# ls /mnt

觀察輸出的內容,不難發現存在 diskimage-linux-riscv-2018-09-23 目錄,也就是之前我們自壓縮檔案解開的目錄,我們的模擬器也從中載入映像檔案。有這樣的檔案分享機制,你就可以很方便地在模擬器中實驗。

詳細閱讀 TinyEMU System Emulator by Fabrice Bellard

Buildroot

$ wget https://bellard.org/tinyemu/buildroot-riscv-2018-10-20.tar.gz
$ tar zxvf buildroot-riscv-2018-10-20.tar.gz
$ cd buildroot-riscv-2018-10-20
$ cp configs/riscv64_defconfig .config

注意檔案 .config 是我們要透過 buildroot 工具去建構 kernel image + root file system 的設定檔案,我們可透過 $ make menuconfig 去調整。在這之前,確保已經安裝必要的開發套件:

$ sudo apt install libncurses5-dev

接著變更設定:

$ make menuconfig

預期會看到下方輸出:

可嘗試用方向鍵瀏覽,觀看個別設定內容。記錄你發現有趣的選項 (乍看不懂沒關係,保持好奇心)。

由於 buildroot 裡頭 e2fsprogs 套件較舊,可能在新版 GNU/Linux 發行套件彙編譯失敗,於是我們著手更新:

  • 編輯檔案 package/e2fsprogs/e2fsprogs.mk,更改 E2FSPROGS_VERSION = 後面的字串從 1.43.11.44.5
  • 編輯檔案 package/e2fsprogs/e2fsprogs.hash, 新增以下
    ​​​​sha256        ba5eb3069d69160d96818bb9700de9ab5a8458d9add1fd85d427c0000d34c5b9    e2fsprogs-1.44.5.tar.xz
    
  • 刪去檔案 package/e2fsprogs/0002-fuse2fs-might-need-librt.patch

接著終於要使用 buildroot 來建構 root file system,過程要等上一陣子。

$ make

如果沒有遭遇到困難 (就算遇到也別急著 Google 搜尋,嘗試自己排除),應該可在 output 目錄發現 buildroot 幫我們建構的檔案,其中 output/host 是必要的開發工具,如:

$ output/host/usr/bin/riscv64-buildroot-linux-gnu-gcc -v

檢查上述輸出中,是否包含以下字串:

  • --target=riscv64-buildroot-linux-gnu
  • Thread model: posix
  • gcc version 7.3.0

透過 buildroot 產生的 GNU Toolchain 也置放於 output/host 目錄。

建立一個小程式,檔名為 hello.c:

#include <stdio.h>
int main() { puts("Hello!"); return 0; }

先在 Host 端進行 cross-compile:

$ ./output/host/usr/bin/riscv64-buildroot-linux-gnu-gcc -o hello hello.c -static

之後啟動 riscv-emu,需要透過 VirtFS 掛載 Host 端檔案系統到 Guest 端的方式: (自行透過 cd 切換到對應的目錄)

$ temu root_9p-riscv64.cfg

在 Guest 中執行以下命令:

~# mount -t 9p /dev/root /mnt
~# cd /mnt/buildroot-riscv-2018-10-20
~# ./hello

應該可見 Hello! 字串輸出。

透過 buildroot 建立的 root filesystem 位於 output/images/rootfs.ext2,用 file 檢查:

$ file output/images/rootfs.ext2

預期會看到 output/images/rootfs.ext2: Linux rev 1.0 ext2 filesystem data 的輸出,注意到 ext2 字串。

回到 diskimage-linux-riscv-2018-09-23 目錄,建立以下檔案:

{ 
    version: 1,
    machine: "riscv64",
    memory_size: 128,
    bios: "bbl64.bin",
    kernel: "kernel-riscv64.bin",
    cmdline: "console=hvc0 root=/dev/vda rw",
    drive0: { file: "/tmp/buildroot-riscv-2018-10-20/output/images/rootfs.ext2" },
    fs0: { tag: "/dev/root", file: "/tmp" },
    eth0: { driver: "user" },
}

相較之前的設定檔案,變更了 drive0 這項,接著啟動模擬器:

$ temu test64.cfg 

預期會看到以下訊息

Welcome to Buildroot
localhost login:

輸入 root,不用密碼即可登入系統。

在 Guest 中輸入以下命令:

~# busybox --help | head

注意看 BusyBox v1.24.2 旁邊的字串,應該會有 2019-03-26 或更晚的時間,表示你透過 buildroot 編譯的 Busybox 工具。

做完實驗記得在 Guest 端關機: (不要傻到在 Host 端輸入)

~# poweroff

Kilo

kilo 是個極小的程式碼編輯器,支援語法高亮度提示和常見的編輯功能,原始程式碼約 1000 行。

預期執行畫面:

功能按鍵:

  • Ctrl-Q: 離開編輯器
  • Ctrl-F: 尋找特定字串
  • Ctrl-E: 刪去目前所在列
  • Ctrl-J: 移動游標到列首
  • Ctrk-K: 移動游標到列尾

自我檢查清單

  • riscv-emu 原始程式碼中多次出現 virtio,這樣的機制對於 host 和 guest 兩端有何作用?在閱讀 Virtio: An I/O virtualization framework for Linux 一文後,對照原始程式碼,你發現什麼?

  • 透過 $ temu root-riscv64.cfg, 我們在 RISCV/Linux 模擬環境中,可執行 gcc 並輸出對應的執行檔,而之後我們則執行 riscv64-buildroot-linux-gnu-gcc,這兩者有何不同? (提示: cross-compiler, 複習 你所不知道的 C 語言: 編譯器和最佳化原理篇

  • 在 Guest 端透過 $ dmesg | grep 9pnet 命令,我們可發現 9P2000 字樣,這和上述 VirtFS 有何關聯?請解釋運作原理並設計實驗

  • TinyEMU System Emulator by Fabrice Bellard 提到 "Network block device",你能否依據說明,嘗試讓 guest 端透過 host 存取到網際網路呢?

    • tap, bridge, NAT, iptables
  • 最初實驗輸入 $ temu https://bellard.org/jslinux/buildroot-riscv64.cfg,然後就能載入 RISC-V/Linux 系統,背後的原理是什麼呢?請以 VirtIO 9P 檔案系統和 riscv-emu 對應的原始程式碼來解說

    TinyEMU supports the VirtIO 9P filesystem to access local or remote filesystems. For remote filesystems, it does HTTP requests to download the files.
    The protocol is compatible with the vfsync utility. In the "mount" command, "/dev/rootN" must be used as device name where N is the index of the filesystem. When N=0 it is omitted.

  • riscv-emu 內建浮點運算模擬器,使用到 SoftFP Library,請以 sqrt 為例,解說 sqrt_sf32, sqrt_sf64, sqrt_sf128 的運作機制,以及如何對應到 RISC-V CPU 模擬器中

  • root-riscv64.cfg 設定檔中,有 bios: "bbl64.bin" 描述,這用意為何?提示:參閱 Booting a RISC-V Linux Kernel

  • 能否用 buildroot 編譯 Linux 核心呢?請務必參閱 Buildroot Manual

    • BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="/tmp/diskimage-linux-riscv-2018-09-23/patches/config_linux_riscv64"
  • 核心啟動的參數 console=hvc0 root=/dev/vda rw 代表什麼意思呢?這對應到模擬器內部設計的哪些部分?

  • $ cat /proc/loadavg 的輸出意義為何?能否對應到 Linux 核心原始碼去解釋呢? (提示: 熟悉的 fixed-point 操作)

  • 為何需要在 host 端準備 e2fsprogs 工具呢?具體作用為何呢?

  • root file system 在 Linux 核心的存在意義為何?而 initramfs 的存在的考量為何?

  • busybox 這樣的工具有何作用?請搭配原始程式碼解說 (提示: 參見 取得 GNU/Linux 行程的執行檔路徑)

作業要求

  • 回答上述「自我檢查清單」的所有問題,需要附上對應的參考資料和必要的程式碼,以第一手材料 (包含自己設計的實驗) 為佳
  • 調整 buildroot 設定,讓原本輸出的 ext2 image 佔用約 14 MB 空間,變得更精簡
    • 移除套件,但確保仍可開機並提供必要的服務及工具
    • Busybox 裡頭的 vi 也不需要存在,改用 kilo
  • 編譯 kilo 編輯器,允許在 RISC-V/Linux 模擬環境中運作
  • 客製化 buildroot,將 kilo 編輯器加入到 build image,建立 Git repository 來追蹤你對 buildroot 做的變更,並依據 Buildroot Manual 更新套件描述和建構方式
  • 重新編譯 Linux 核心,確保能在 riscv-emu 運作,並思考縮減 image size 的方法

繳交方式

編輯 Homework4 作業區共筆,將你的觀察、上述要求的解說和改善過程,紀錄於新建立的共筆

截止日期

Apr 12, 2019 (含) 之前