# 2019q1 Homework7 (riscv)
contributed by < `zodf0055980` >
###### tags: `Linux 核心設計`
# 自我檢查清單
- [ ] riscv-emu 原始程式碼中多次出現 virtio,這樣的機制對於 host 和 guest 兩端有何作用?在閱讀 Virtio: An I/O virtualization framework for Linux 一文後,對照原始程式碼,你發現什麼?
要了解 virtio,首先要了解完全虛擬化和半虛擬化。
全虛擬化:允許未經修改的 Guest OS 隔離運行在 VMM 上,並對Guest OS 隱藏了真實的硬體。所有硬體特徵像是指令集、中隊都對應到虛擬機上。所以我們電腦可以直接運行的軟體都可以直接運行在虛擬機上,不用修改。然而 VMM 必須捕捉這些請求並模擬硬體的行為,雖然有彈性但是造成效率低落。例如:以前常用的 Oracle VM VirtualBox。
半虛擬化:則要求對 Guest OS 做出必要的更改,以適應 VMM 提供的半虛擬化API。而且 Guest OS 運行時知道自己是運行在虛擬化的機器上, 並自己包含驅動程序的前端驅動,而 VMM 為後端驅動。而 Virtio 前後端的溝通提供標準化接口以提高效率。
![](https://i.imgur.com/rJ74ym3.gif)
Virtio 所提供的 API 透過簡單的 buffer 來把對 Guest OS 的命令做封裝傳輸,並提供兩個層來幫助 Guest OS 與 VMM 的通訊,其中頂層使用 Queue 作為虛擬接口連接前後端,也被稱為 virtio。
![](https://i.imgur.com/Jof9LQH.gif)
virtio_driver : 代表 Guest OS 的前端驅動程序。與此驅動程序匹配的設備由 virtio_device 封裝。
virtio_config_ops : 定義配置virtio設備操作的結構
virtqueue : 引用 virtio_device。使用 Queue 做資料結構。virtqueue_ops : 定義 virtqueue 中 Queue的基本操作。
- [ ] 透過 $ temu root-riscv64.cfg, 我們在 RISCV/Linux 模擬環境中,可執行 gcc 並輸出對應的執行檔,而之後我們則執行 riscv64-buildroot-linux-gnu-gcc,這兩者有何不同?
當我們一般在 linux 使用 gcc 來編譯某個程式,程式只能執行相同指令集的電腦上,而我們要使用虛擬機模擬 RISCV 架構,就不能使用 電腦上的編譯器去編譯。而透過 Cross Compiler 可以編譯出執行在不同指令集的程式,因此我們程式要在 RISCV 的虛擬機上執行,便要透過 riscv64-buildroot-linux-gnu-gcc 去編譯。
- [ ] 在 Guest 端透過 $ dmesg | grep 9pnet 命令,我們可發現 9P2000 字樣,這和上述 VirtFS 有何關聯?
嘗試執行:
```
[root@localhost ~]# dmesg | grep 9pnet
[ 0.278541] 9pnet: Installing 9P2000 support
```
把上面一一拆解,[dmesg](http://www.runoob.com/linux/linux-comm-dmesg.html) 用來顯示開機訊息, kernel 會把開機訊息存在 ring buffer 和 /var/log 中 dmesg 的文件。
而 grep 可以搜尋要找的字串,所以上述指令是在開機訊息中尋找 9pnet。
>9P(又名九號計劃檔案系統協定或Styx),是貝爾實驗室九號計劃分散式作業系統所開發的網絡協定,作用在於連結九號計劃系統內的元件。在九號計劃第四版中,9P被更名為9P2000,也增加了一些基礎上的改進。
>
在文章中可知在 guest 和 host 的 OS 中設置 VirtFS ,使的資料夾可以共享。
>VirtFS (Plan 9 folder sharing over Virtio - I/O virtualization framework)
>
- [ ] 在 root-riscv64.cfg 設定檔中,有 bios: "bbl64.bin" 描述,這用意為何?
bbl 全名是 the Berkeley Boot Loader。文章中提到為了避免把硬體的假設寫入映像檔,使用兩種抽象機制:
1. 設備樹(device tree): 一種現代系統用來描述硬體資源的結構,這指定了記憶體映射,系統中配置以及所有靜態分配的設備。它通過 bootloader 將硬體資源傳給 kernel,使得 kernel 和硬體資源描述相對獨立。
>Documentation for device trees, a data structure by which bootloaders pass hardware layout to Linux in a device-independent manner, simplifying hardware probing.
>
2. supervisor binary interface (SBI) : supervisor 的機器二元碼介面,允許由較低優先權的 stack 提供的接口寫入 supervisor。
而在 RISC-V supervisor-mode 中,設備樹和 SBI 都由 machine-mode 的 bbl 提供。
- [ ] 為何需要在 host 端準備 e2fsprogs 工具呢?具體作用為何呢?
e2fsprogs(又稱為e2fs programs)是用以維護ext2,ext3和ext4檔案系統的工具程式集。
# 實驗 客製化 buildroot,將 kilo 編輯器加入到 build image
參考 [Buildroot Manual]( https://buildroot.org/downloads/manual/manual.html#adding-packages),在 /package 中創建 kilo 資料夾,並參考寫出 `Config.in`:
```clike
config BR2_PACKAGE_KILO
bool "kilo"
help
Kilo is a small text editor in less than 1K lines of code (counted with cloc).
https://github.com/sysprog21/kilo
```
以及 `kilo.mk` :
```
################################################################################
#
# kilo
#
################################################################################
KILO_VERSION = af3919d68cb2e70a3d9a2309596cf290cf6bc1ac
KILO_SITE = $(call github,sysprog21,kilo,$(KILO_VERSION))
KILO_LICENSE = BSD-2-Clause
define KILO_BUILD_CMDS
$(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D) all
endef
define KILO_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(@D)/kilo $(TARGET_DIR)/usr/bin
endef
$(eval $(generic-package))
```
在 Buildroot Manual 有寫到:
LIBFOO_VERSION, mandatory, must contain the version of the package. Note that if HOST_LIBFOO_VERSION doesn’t exist, it is assumed to be the same as LIBFOO_VERSION. It can also be a revision number or a tag for packages that are fetched directly from their version control system. Examples:
a version for a release tarball: LIBFOO_VERSION = 0.1.2
a sha1 for a git tree: LIBFOO_VERSION = cb9d6aa9429e838f0e54faa3d455bcbab5eef057
而觀看 [github.com/sysprog21/kilo/](https://github.com/sysprog21/kilo/commit/af3919d68cb2e70a3d9a2309596cf290cf6bc1ac) 發現最新 commit 檔案為 af3919d68cb2e70a3d9a2309596cf290cf6bc1ac 將此作為 KILO_VERSION。
以及 [加入git檔案](https://buildroot.org/downloads/manual/manual.html#github-download-url)的說明,他有提供工具可以從 github 下載檔案,因此
`KILO_SITE = $(call github,sysprog21, kilo, $(KILO_VERSION))`。
更改 package/Config.in 把 kilo 加入 menu "Text editors and viewers",接著執行 make menuconfig 就能看到 kilo 出現在選單中。
![](https://i.imgur.com/qrHqAKM.png)
可以看到 package/Config.in 有這段
```
if BR2_PACKAGE_BUSYBOX_SHOW_OTHERS
source "package/vim/Config.in"
endif
```
得知如果我們沒有預設文字編輯器的話,會自動用 vim。
之後在 diskimage-linux-riscv-2018-09-23 資料夾中建立 test64.cfg,因為如果在 /tmp 資料夾下如果重開機,檔案會自動做清除。(被這個害慘,下載檔案下載好多次 .......)因此把檔案移到 home 目錄下作實驗,把 test64.cfg 修改為
```
{
version: 1,
machine: "riscv64",
memory_size: 128,
bios: "bbl64.bin",
kernel: "kernel-riscv64.bin",
cmdline: "console=hvc0 root=/dev/vda rw",
drive0: { file: "/home/yuan/buildroot-riscv-2018-10-20/output/images/rootfs.ext2" },
fs0: { tag: "/dev/root", file: "/tmp" },
eth0: { driver: "user" },
}
```
之後執行 temu test64.cfg ,進到模擬器中,因為我們已經把預設的文字編輯器改成 kilo,直接輸入 kilo XXX ,便能出現 kilo 做處理了。
![](https://i.imgur.com/HkSl0Ul.png)
在 [8.10. Graphing the filesystem size contribution of packages](https://buildroot.org/downloads/manual/manual.html#_graphing_the_filesystem_size_contribution_of_packages) 提到能利用 $ make graph-size 去顯示大小,下面做小小測試:
```shell=
yuan@yuan-X555LF:~/buildroot-riscv-2018-10-20$ make graph-size
You need python-matplotlib to generate the size graph
Makefile:737: recipe for target 'graph-size' failed
make: *** [graph-size] Error 1
```
發現需要 python-matplotlib 的套件,透過執行 $sudo apt-get install python-matplotlib 安裝套件
最後在執行一次,會在 buildroot-riscv-2018-10-20/output/graphs/graph-size.pdf
![](https://i.imgur.com/0nGDcz8.png)
接著想要移除 vi,讓ext2 image 變得更精簡
輸入$ make busybox-source 和$ make busybox-menuconfig
把 busybox-menuconfig 中 editer 的 vi 給取消。
![](https://i.imgur.com/RdHLEMP.png)
發現大小並沒有改變,應此跑去更改 buildroot-riscv-2018-10-20/package/busybox/busybox.config
把 CONFIG_VI=y 改成 CONFIG_VI=n ,並重新編譯看看。
![](https://i.imgur.com/5QIPPda.png)
發現檔案大小確實減少了,去觀察 package 得狀況:
![](https://i.imgur.com/LP0BBv8.png)
發現 bustbox的大小減少了一點。