目標:實做支援 virtio-blk
CONFIG_SYS_TEXT_BASE (U-Boot)
## 修改 semu 程式碼
1. Kernel 的 **CONFIG_VIRTIO_BLK** 須被啟動 (linux.config 未開啟)
2. Kernel 的 **MS-DOS / FAT32 相關的選項** 要打開
3. VirtIO Device Initialization 流程:
* Reset
* Acknowledgement
* DRIVER
* FEATURES_OK
* DRIVER_OK
4. Virtqueue 由三個連續部份組成:
* Descriptor Area (**QueueDesc**) - used for describing buffers
* Driver Area (**QueueAvail**) - extra data supplied by driver to the device
* Device Area (**QueueUsed**) - extra data supplied by device to driver
5. Request (**QueueAvail**) / Response (**QueueUsed**)
6. virtio-blk 的 descriptor 格式:
* header (讀寫類型) -> data -> status
```
struct virtq_desc {
/* Address (guest-physical). */
le64 addr;
/* Length. */
le32 len;
/* This marks a buffer as continuing via the next field. */
#define VIRTQ_DESC_F_NEXT 1
/* This marks a buffer as device write-only (otherwise device read-only). */
#define VIRTQ_DESC_F_WRITE 2
/* This means the buffer contains a list of buffer descriptors. */
#define VIRTQ_DESC_F_INDIRECT 4
/* The flags as indicated above. */
le16 flags;
/* Next field if flags & NEXT */
le16 next;
};
```
```
struct virtq {
// The actual descriptors (16 bytes each)
struct virtq_desc desc[ Queue Size ];
// A ring of available descriptor heads with free-running index.
struct virtq_avail avail;
// Padding to the next Queue Align boundary.
u8 pad[ Padding ];
// A ring of used descriptor heads with free-running index.
struct virtq_used used;
};
```
```
struct virtq_avail {
#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
le16 flags;
le16 idx;
le16 ring[ /* Queue Size */ ];
le16 used_event; /* Only if VIRTIO_F_EVENT_IDX */
};
```
```
struct virtq_used {
le16 flags;
le16 idx;
struct virtq_used_elem ring[];
/* Only if VIRTIO_F_EVENT_IDX: le16 avail_event; */
};
```
```
/* le32 is used here for ids for padding reasons. */
struct virtq_used_elem {
/* Index of start of used descriptor chain. */
le32 id;
/* Total length of the descriptor chain which was written to. */
le32 len;
};
```
```
struct virtio_blk_req {
le32 type;
le32 reserved;
le64 sector;
u8 data[][512];
u8 status;
};
```
```
#define VIRTIO_BLK_S_OK 0
#define VIRTIO_BLK_S_IOERR 1
#define VIRTIO_BLK_S_UNSUPP 2
```

## 手動編譯 Linux kernel image
### 1. Environment setup
Before starting everything, the following packages are essential:
```
sudo apt install autoconf automake autotools-dev curl gawk git build-essential bison flex texinfo gperf libtool libncurses-dev
```
Since the process to be demonstrated involves switching between several project directories, we can handle them with a workspace directory as:
```
mkdir semu_ws/
cd semu_ws/
```
We then clone the source code of the semu:
```
git clone https://github.com/jserv/semu.git
```
Later, the directory structure should look like:
```
semu_ws/
|
|----- semu/
|
|----- linux/
|
|----- buildroot/
|
|----- riscv-gnu-toolchain/
```
### 2. Compile RISC-V GNU Toolchain
Now, we need to compile the GNU toolchain that targets the RV32 ISA with Linux ABI. This can be done by:
```
git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain/
mkdir build/
cd build/
../configure --prefix=/opt/riscv --with-arch=rv32gc --with-abi=ilp32d
sudo make linux -j$(nproc)
```
After the compilation, type the following command:
```
export PATH=$PATH:/opt/riscv/bin
```
Alternatively, you can save the setting into the `~/.bashrc` and restart the terminal.
### 3. Create root file system with Buildroot
Next, we can use [Buildroot](https://buildroot.org/) to create the root file system, which is essential for building the kernel image.
To download and decompress the source code of Buildroot:
```
cd semu_ws/
wget https://buildroot.org/downloads/buildroot-2023.02.3.tar.gz
tar -xvf buildroot-2023.02.3.tar.gz
mv buildroot-2023.02.3/ buildroot/
```
Usually, Buildroot requires the user to set up its configurations, but here we can copy the settings from the semu:
```
cp semu/configs/buildroot.config buildroot/.config
```
Then, to build the root file system, type:
```
make -j$(nproc) #Type [enter] if you encounter any questions
```
If everything goes right, you should be able to find the result at `buildroot/output/images/rootfs.cpio`
### 4. Compile and build Linux kernel image
Next, clone the kernel source code specified with version `v6.4-rc1`:
```
cd semu_ws/
git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git -b v6.4-rc1
```
Before cross-compiling the kernel, set up the following environment variables:
```
export CROSS_COMPILE=riscv32-unknown-linux-gnu-
export ARCH=riscv
```
Again, copy the configuration file from the semu:
```
cp semu/configs/linux.config linux/.config
cd linux/
make oldconfig
```
Then, start the compilation by typing:
```
make -j$(nproc)
```
After all, you can replace the old kernel image of semu with:
```
cp arch/riscv/boot/Image ../semu/Image
```
## References
https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html#x1-320005
https://brennan.io/2020/03/22/sos-block-device/
https://rootw.github.io/2019/09/firecracker-virtio/