# 2024q1 Homework5 (assessment)
contributed by < `nelson0720j` >
## 測驗題改進
## 閱讀〈因為自動飲料機而延畢的那一年〉的啟發
想像總是美好的,在實際去操作後才會發現看似簡單的問題其實有很多的學問。在過程中,遭遇了很多的困難,花費大量的時間和成本才完成,但是我想這一步步思考解決問題的能力才是在往後的日子裡幫助最大的!
其中,平常所學若是有很札實的練習,在它需要出場的時候才能發揮其價值。
也因為有了這個專案,才得以認識許多志同道合的戰友以及貴人,這一年的時間,我想只有本人得以體會到多麼的珍貴難以忘懷吧。
就像現在這門課,每一份文件都是新的事物,一深入閱讀就會遇到更多的困難,更多的教材,更多的工具可以去學習使用,總會感覺到一股好像學到了甚麼但是又遠遠不夠的失落感。
## 研讀教材啟發
### CS:APP 3/e
#### [Chapter 2](https://hackmd.io/@sysprog/CSAPP-ch2?type=view)
了解 bitwise 的各項操作,還有使用 `xor` 來判斷的技巧。
:::info
- [ ] `uintN_t` 和 `intN_t` 保證沒有填充位元,那沒有用到的 bit 位是如何決定 0 或 1 ,在沒有對齊的情況下又是如何去做邏輯運算的?
> 留意 `uint32_t` (恰好 32 位元), `uint_least32_t` (至少 32 位元) 和 `uint_fast32_t` (可能大於 32 位元)
- [ ] 用 XOR 檢查加法後是否有溢位
```
long a, b, x;
x = a + b;
if ((x ^ a) >= 0 || (x ^ b) >= 0)
...
```
為何是用 `||` 而不是 `&&` ?
- [ ] x<=0 --> -x>=0 false?
:::
* 練習題
```c
#include <stdbool.h>
bool tadd_ok(int x, int y) {
int sum = x + y;
bool over_neg = (x < 0) && (y < 0) && (sum >= 0);
bool over_pos = (x >= 0) && (y >= 0) && (sum < 0);
return (!over_neg) && (!over_pos);
}
```
透過 `xor` 來簡化,兩數相加後的正負號和原本兩者都不同。
```c
#include <stdbool.h>
bool tadd_ok(int x, int y) {
int sum = x + y;
bool over = x^sum && y^sum;
return !over;
}
```
> 請愛用 https://godbolt.org/
```c
#include <stdio.h>
// Assume float is 32-bit width.
float float_abs(float x)
{
// using bitwise operation, no branch
// IEEE 754, sign bit
int y = (int)x;
y = y & 0x7fff;
return (float)y;
}
int main()
{
float x = -7;
printf("%f\n", float_abs(x));
}
```
原本想直接強制轉型浮點數,後來發現強制轉型只會存取這個幅點數的整數位,造成浮點數後面的小數資料會遺失。
因此我們改用一個指向整數的指標來指向這個浮點數,使其能以整數的方式訪問浮點數的記憶體,這樣就可以直接操作浮點數的 bit pattern 。
```c
float float_abs(float x)
{
// using bitwise operation, no branch
// IEEE 754, sign bit
int *p = (int *)&x;
int x_bitpattern = *p & 0x7fffffff;
return *(float *)&x_bitpattern;
}
```
## 專案
RISC-V
閱讀 https://hackmd.io/@sysprog/Skuw3dJB3 並紀錄問題
### 問題
:::info
- [ ] 為何加入 kilo 過程需要重新產生 linux kernel image ,Kilo 相關的檔案不是包含在 initramfs 中嗎?
- [ ] 實作客製化 initramfs 錯誤
不清楚為何客製化 initramfs 需要重新建構 kernel image ? 不是只需重新建構 initramfs 嗎?
我的理解是:
kernel 透過 initramfs 這個虛擬根目錄,執行 initramfs 上的初始任務,包括印出 hello semu 的 init 檔和各種系統文件,套件服務。
- [ ] initramfs 建構錯誤
```
$ mkdir initramfs-workspace
$ cd initramfs-workspace
$ mkdir -p hello-initramfs
$ cd hello-initramfs
$ cat > init.c <<EOF
> #include <stdio.h>
> int main()
> {
> printf("Hello semu !!!\n");
> return 0;
> }
> EOF
$ export PATH=$(pwd)/output/host/bin:$PATH
$ riscv32-buildroot-linux-gnu-gcc -static -o init init.c
加入linux.config
$ mkdir -p dev
$ sudo mknod dev/console c 5 1
$ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git -b linux-6.1.y --depth=1
$ cd ../linux # 回到 initramfs-workspace/
$ make menuconfig
開啟 menuconfig 選擇 General setup -> 開啟 Initial RAM filesystem and RAM disk support -> /home/nelson/buildroot/initramfs-workspace/hello-initramfs,保存後退出。
$ make Image
make[1]: *** No rule to make target 'Image'. Stop.
buildroot$ export PATH=$(pwd)/output/host/bin:$PATH
$ cd initramfs-workplace/linux
$ make olddefconfig
$ make Image
$ cp arch/riscv/boot/Image ~/nelson/semu
$ cd ~/semu
$ sudo ./semu -k Image -b minimal.dtb -i rootfs.cpio -d ext4.img
用 `binwalk` 檢查 Image
找不到 init
```
- [ ] initrmfs 問題
>回到 initramfs-workspace/ 目錄下,新增兩個 busybox 子目錄,並將 busybox 執行檔複製過來、擷取當中命令
提到
```
# 這裡一樣先不進行壓縮,也就是不執行最後的 gzip
$ find . | cpio -o -H newc | gzip > ../busybox.initramfs.cpio.gz
```
但程式碼本身卻有進行壓縮?
:::
### 已解決問題
- [x] 執行 buildroot 設定,並將 kilo 加入 buildroot 中 [已解決]
```
$ git clone https://github.com/buildroot/buildroot.git --depth=1
--depth=1 表示只取得最新一筆 commit,在專案很大時可加快下載時間及節省空間。
根據 semu 提供的組態來建構 root file system:
$ cd buildroot
$ cp ../semu/configs/buildroot.config .config
$ make
```
```
for f in busybox.config ; do if [ ! -f "${f}" ]; then printf "Kconfig file or fragment '%s' for '%s' does not exist\n" "${f}" "busybox"; exit 1; fi; done
Kconfig file or fragment 'busybox.config' for 'busybox' does not exist
make[1]: *** [package/busybox/busybox.mk:433: busybox.config] Error 1
make: *** [Makefile:82: _all] Error 2
```
解決辦法
1. 從 semu 複製 busybox.config 到 bootloader 中
按照同學步驟繼續執行,並且可以在 buildroot/output/target/usr/bin/ 下看到 kilo
到此步驟 -> buildroot 建置完成後,至 linux/ 目錄下重新產生 Linux Kernel Image:
```
~/buildroot$ cd linux
$ make -j4 Image
buildroot/linux$ make -j4 Image
make: *** No rule to make target 'Image'. Stop.
```
```bash
$ ls
Config.ext.in
Config.in
linux-ext-aufs.mk
linux-ext-ev3dev-linux-drivers.mk
linux-ext-fbtft.mk
linux-ext-rtai.mk
linux-ext-xenomai.mk
linux.hash
linux.mk
```
沒有看到 Makefile,還是我少了哪一個步驟?
1. 嘗試用 semu build-image 來建構,但因為只需要 kernel image
因此只執行以下
```
~/semu $
export PATH="$PWD/buildroot/output/host/bin:$PATH"
export CROSS_COMPILE=riscv32-buildroot-linux-gnu-
export ARCH=riscv
$ cd linux
$ make olddefconfig
$ make -j4
$ cp -f arch/riscv/boot/Image ../Image
```
仍然在 semu 中無法看到 kilo
2. `lsinitrd` 來查看 rootfs.cpio 是否有包含 kilo
```bash
$ lsinitrd rootfs.cpio | grep kilo
-rwxr-xr-x 1 root root 26176 May 29 21:36 usr/bin/kilo
```
含有 kilo
不重新建構 kernel image ,只將 buildroot 新建立含有 kilo 的 rootfs.cpio 更新到 semu 中
成功出現 kilo !
- [x] `make check` 成功,但出現 kernel panic [已解決]
步驟:
1. 先從 [semu](https://github.com/sysprog21/semu) clone 下來
2. 執行 `sudo apt install device-tree-compiler`
3. `make`
4. `make check`
```bash
failed to allocate TAP device: Operation not permitted
No virtio-net functioned
[ 0.000000] Linux version 6.1.73 (jserv@node1) (riscv32-buildroot-linux-gnu-gcc.br_real (Buildroot 2023.11.1) 12.3.0, GNU ld (GNU Binutils) 2.39) #1 Sat Jan 20 17:48:47 CST 2024
[ 0.000000] Machine model: semu
...
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Starting network: OK
```
5. `./semu -k Image`
```bash
$ ./semu -k Image
...
[ 2.746320] /dev/root: Can't open blockdev
[ 2.746320] VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
[ 2.746622] Please append a correct "root=" boot option; here are the available partitions:
[ 2.746935] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[ 2.747247] CPU: 0 PID: 1 Comm: swapper Not tainted 6.1.73 #1
[ 2.747550] Hardware name: semu (DT)
[ 2.747725] Call Trace:
[ 2.747869] [<c0003a30>] dump_backtrace+0x2c/0x3c
[ 2.748185] [<c0324510>] show_stack+0x40/0x54
[ 2.748492] [<c0327420>] dump_stack_lvl+0x30/0x4c
[ 2.748833] [<c0327458>] dump_stack+0x1c/0x2c
[ 2.749162] [<c03247bc>] panic+0x124/0x2ec
[ 2.749465] [<c032e22c>] mount_block_root+0x1dc/0x238
[ 2.749810] [<c032e334>] mount_root+0xac/0x1dc
[ 2.750132] [<c032e5f4>] prepare_namespace+0x190/0x1a4
[ 2.750480] [<c032dc5c>] kernel_init_freeable+0x1d4/0x21c
[ 2.750833] [<c03276a4>] kernel_init+0x24/0x118
[ 2.751172] [<c0002444>] ret_from_exception+0x0/0x1c
[ 2.751503] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---
```
嘗試重新 Build Linux kernel image and root file system
1. 刪除 semu 底下的 Image 和 Buildroot
2. 執行 `make build-image`
3. `make`
4. `make check`
5. `./semu -k Image`
錯誤仍然一樣
查看 Makefile,印出他的參數
```bash
minimal.dtb: minimal.dtb
KERNEL_DATA: Image
INITRD_DATA: rootfs.cpio
DISKIMG_FILE: ext4.img
```
加入參數,執行
`$ sudo ./semu -k Image -b minimal.dtb -i rootfs.cpio -d ext4.img`
成功!
TODO: semu 的改進:
## 筆記
rootfs.cpio 由 buildroot 執行 make 和 make olddefconfig 產生
:::warning
參照 [bootlin 教育訓練材料](https://bootlin.com/docs/)
:::
make olddefconfig 將現有檔案更新剛剛做的的設定
## reference
[buildroot](https://buildroot.org/downloads/manual/manual.html#full-rebuild)
---
https://man7.org/linux/man-pages/man4/tty.4.html
TODO: https://github.com/sysprog21/semu/issues/26 (cache)
> semu supports MMU ([Sv32](https://riscv.org/wp-content/uploads/2017/05/riscv-privileged-v1.10.pdf))
> https://github.com/sysprog21/semu/pull/28 (using LRU)
> 提交 pull request (進行 code reviewing)
TODO: https://github.com/sysprog21/semu/issues/41 (PMEM)
> https://hackmd.io/@sysprog/linux-kvm (注意 VirtIO)
> 當 pmem 正確建立後,使用記憶體測試的演算法確認存取行為符合預期: https://www.memtest86.com/tech_memtest-algoritm.html