目標:實做支援 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 ``` ![](https://hackmd.io/_uploads/rJtL2-w9n.png) ## 手動編譯 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/