Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement VirtIO block device #539

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

otteryc
Copy link

@otteryc otteryc commented Jan 23, 2025

This commit migrates @shengwen-tw's brilliant virtio implementation from semu, with the following modification:

  1. Rename virtio_blk_reg_read/write to virtio_blk_read/write The original virtio_blk_read verified whether the virtio MMIO was aligned to 4. Since rv32emu does not enforce alignment checks for UART and PLIC devices or raise misalignment exceptions, this verification has been omitted.

  2. Implement MMIO_VIRTIOBLK

  3. Implement vblk_new() and vblk_delete()
    These functions align with the conventions used for UART and PLIC devices.

  4. Introduce new argument '-x vblk:<disk_image>' for virtio-blk disk image

This pull request has been tested on:

  1. Linux 6.8.0 @ Intel core i7-7700K
  2. Mac OS Sequoia 15.1 @ Apple Silicon M2

To try out virtio-blk:
Generate ext4 image file for virtio block device in Unix-like system:

$ dd if=/dev/zero of=disk.img bs=4M count=32
$ mkfs.ext4 disk.img

Boot the Guest OS

$ ./build/rv32emu -k <kernel_img_path> -i <rootfs_img_path> -x vblk:disk.img

Mount the virtual block device and create a test file after booting:

$ mkdir mnt
$ mount /dev/vda mnt
$ echo "rv32emu" > mnt/emu.txt
$ umount mnt

Reboot the system and re-mount the virtual block device, the written file should remain existing.

Copy link
Contributor

@jserv jserv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Benchmark suite Current: b2d8304 Previous: 613cd0a Ratio
Dhrystone 1334 Average DMIPS over 10 runs 1346 Average DMIPS over 10 runs 1.01
Coremark 964.709 Average iterations/sec over 10 runs 972.884 Average iterations/sec over 10 runs 1.01

This comment was automatically generated by workflow using github-action-benchmark.

src/system.c Outdated Show resolved Hide resolved
Copy link
Contributor

@jserv jserv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Specify Shengwen Cheng as co-author in git commit messages. See https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors
  2. Consolidate GitHub Actions to automate virtio-blk test procedure.

src/devices/virtio-blk.c Outdated Show resolved Hide resolved
src/main.c Outdated Show resolved Hide resolved
@vacantron
Copy link
Collaborator

Does it have any instructions / documentations for demonstrating or testing of this newly added feature?

@jserv jserv changed the title Migrate virtio-blk from semu Implement VirtIO block device Jan 23, 2025
@jserv jserv added this to the release-2025.1 milestone Jan 23, 2025
@ChinYikMing
Copy link
Collaborator

rv32emu use snake_case naming scheme (check CONTRIBUTING.md), but I see CamelCase in the implementation. @otteryc Can you unify the naming scheme or any strong reason to use CamelCase?

@otteryc
Copy link
Author

otteryc commented Jan 23, 2025

@vacantron @ChinYikMing Thank you for the insightful comments.
CamelCase names have been replaced with snake_case, and a new section has been added to the README to demonstrate virtio-blk.

src/devices/virtio-blk.c Outdated Show resolved Hide resolved
src/devices/virtio.h Outdated Show resolved Hide resolved
src/devices/virtio.h Outdated Show resolved Hide resolved
src/devices/virtio.h Outdated Show resolved Hide resolved
src/devices/virtio.h Outdated Show resolved Hide resolved
src/main.c Outdated Show resolved Hide resolved
src/devices/virtio.h Outdated Show resolved Hide resolved
src/devices/virtio-blk.c Outdated Show resolved Hide resolved
src/devices/virtio-blk.c Outdated Show resolved Hide resolved
src/devices/virtio-blk.c Outdated Show resolved Hide resolved
Copy link
Collaborator

@ChinYikMing ChinYikMing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the description of this pull request, adding information for others to build the system emulator and test the virtio-blk feature. This will make it easier for others to access the information without needing to refer to the README but also keep them in README :) .

@jserv
Copy link
Contributor

jserv commented Jan 23, 2025

Compilation warnings reported by GCC:

src/devices/virtio-blk.c: In function ‘vblk_preprocess’:
src/devices/virtio-blk.c:80:60: error: unused parameter ‘vblk’ [-Werror=unused-parameter]
   80 | static inline uint[32](https://github.com/sysprog21/rv32emu/actions/runs/12930766138/job/36065876824?pr=539#step:9:33)_t vblk_preprocess(virtio_blk_state_t *vblk, uint32_t addr)
      |                                        ~~~~~~~~~~~~~~~~~~~~^~~~

Simply add UNUSED (see src/common.h) to get rid of the above.

@otteryc otteryc force-pushed the vblk branch 3 times, most recently from cb15ab4 to f513ee7 Compare January 23, 2025 16:23
README.md Outdated Show resolved Hide resolved
src/devices/virtio-blk.c Outdated Show resolved Hide resolved
@@ -118,6 +120,13 @@ static bool parse_args(int argc, char **args)
opt_bootargs = optarg;
emu_argc++;
break;
case 'x':
if (!strncmp("vblk:", optarg, 5))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why must we introduce such complexity with the vblk: prefix? The brilliant way is to use just the disk file name here and consider adding the long option for different block devices if required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why must we introduce such complexity with the vblk: prefix?

VirtIO features like disk, network, and sound can be dynamically enabled using the -x option, inspired by Oracle/Sun Java virtual machine. For example: -x vblk:<disk> -x vnet:tap0 -x vsnd:alsa. The long command options might be confusing if we want to specify more VirtIO devices, such as a secondary virtio-blk.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. Thanks


/* virtio-blk device */
uint32_t *disk;
virtio_blk_state_t *vblk;
Copy link
Collaborator

@RinHizakura RinHizakura Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok it seems like UART and VIRTIO_BLK come from semu, and PLIC may have a little bit different design here......

I am just thinking of wrapping these things in virtio_blk_t, but maybe we can refactor these in other PR if required. This is not a critical issue.

README.md Outdated Show resolved Hide resolved
@otteryc otteryc force-pushed the vblk branch 2 times, most recently from 8355697 to 40bca99 Compare January 24, 2025 04:40
README.md Outdated Show resolved Hide resolved
Makefile Outdated Show resolved Hide resolved
@otteryc otteryc force-pushed the vblk branch 2 times, most recently from 48536bf to f475a45 Compare January 24, 2025 05:54
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
Copy link
Collaborator

@ChinYikMing ChinYikMing Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you reuse the script of boot Linux instead of creating a new one? By adjusting the script to accept a CLI parameter that determines whether to test the virtio-blk feature.

RUN_LINUX="build/rv32emu ${OPTS}"

dd if=/dev/zero of=build/disk.img bs=4M count=32
mkfs.ext4 build/disk.img
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the presence of mkfs.ext4. That is, something like https://github.com/sysprog21/semu/blob/master/Makefile#L20-L32

README.md Outdated Show resolved Hide resolved
otteryc and others added 2 commits January 26, 2025 10:24
This commit migrates @shengwen-tw's brilliant virtio implementation
from semu, with the following modification:

1. Rename virtio_blk_reg_read/write to virtio_blk_read/write
The original virtio_blk_read verified whether the virtio MMIO was
aligned to 4. Since rv32emu does not enforce alignment checks for UART
and PLIC devices or raise misalignment exceptions, this verification
has been omitted.

2. Implement MMIO_VIRTIOBLK

3. Implement vblk_new() and vblk_delete()
These functions align with the conventions used for UART and PLIC
devices.

4. Introduce new argument '-x vblk:<disk_image>' for virtio-blk disk
image

Co-authored-by: Shengwen Cheng <[email protected]>
Virtio-blk verification has been integrated into boot-linux test, and
is enabled by default.
The p7zip-full package, providing command '7z', is added to
dependencies in order to validate the success of writes to the
Virtio-blk device.
ENABLE_VBLK=1
type dd >/dev/null 2>&1 || ENABLE_VBLK=0
(type mkfs.ext4 >/dev/null 2>&1 || type $(brew --prefix e2fsprogs)/sbin/mkfs.ext4) >/dev/null 2>&1 || ENABLE_VBLK=0
type 7z >/dev/null 2>&1 || ENABLE_VBLK=0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is 7z required?

Copy link
Author

@otteryc otteryc Jan 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe using 7z to list files in disk.img is the simplest and most efficient method to verify whether the file emu.txt written by the guest OS exists.
Other approaches have limitations:

  • Mounting disk.img requires root privileges, which may not always be feasible.
  • Inspecting the image with debugfs provides the desired result but involves navigating a complex interactive interface.
  • dumpe2fs fail with an error, "Wrong magic number for Ext2 Image Header while trying to open disk.img" when attempting to process disk.img.

case _(QueueNumMax):
return VBLK_QUEUE_NUM_MAX;
case _(QueueReady):
return VBLK_QUEUE.ready ? 1 : 0;
Copy link
Collaborator

@ChinYikMing ChinYikMing Jan 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrite as: return (uint32_t) VBLK_QUEUE.ready since VBLK_QUEUE.ready is a boolean that already evaluates to either true or false.


#define DISK_BLK_SIZE 512

#define VBLK_DEV_CNT_MAX 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, does this refer to the virtio block limit? I believe it can attach multiple virtual block devices, can't it?

#define _(reg) VIRTIO_##reg
switch (addr) {
case _(MagicValue):
return 0x74726976;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Define these magic value to a semantic name, just like VIRTIO_VENDOR_ID indicates the vendor ID.

case _(MagicValue):
return 0x74726976;
case _(Version):
return 2;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

case _(Version):
return 2;
case _(DeviceID):
return 2;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

case _(Status):
return vblk->status;
case _(ConfigGeneration):
return 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

TIMEOUT=50
OPTS=" -k build/linux-image/Image "
OPTS+=" -i build/linux-image/rootfs.cpio "
OPTS+=" -b build/minimal.dtb "
if [ "$ENABLE_VBLK" -eq "1" ]; then
dd if=/dev/zero of=build/disk.img bs=4M count=32
mkfs.ext4 build/disk.img || $(brew --prefix e2fsprogs)/sbin/mkfs.ext4 build/disk.img
Copy link
Collaborator

@ChinYikMing ChinYikMing Jan 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No macOS CI is integrated yet. Is it suitable to include brew utility since we do not actually use it for now?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added based on this review. While we do not currently utilize the brew utility, its inclusion is harmless and imposes minimal runtime overhead.

@@ -16,31 +16,62 @@ function ASSERT {

cleanup

ENABLE_VBLK=1
type dd >/dev/null 2>&1 || ENABLE_VBLK=0
(type mkfs.ext4 >/dev/null 2>&1 || type $(brew --prefix e2fsprogs)/sbin/mkfs.ext4) >/dev/null 2>&1 || ENABLE_VBLK=0
Copy link
Collaborator

@ChinYikMing ChinYikMing Jan 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

printf "\n[ ${COLOR_G}${MESSAGES[$ret]}${COLOR_N} ]\n"
printf "\nBoot Linux Test: [ ${COLOR_G}${MESSAGES[$ret]}${COLOR_N} ]\n"
if [ "$ENABLE_VBLK" -eq "1" ]; then
file_list=`7z l build/disk.img`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrite as file_list= $(7z l build/disk.img)

type dd >/dev/null 2>&1 || ENABLE_VBLK=0
(type mkfs.ext4 >/dev/null 2>&1 || type $(brew --prefix e2fsprogs)/sbin/mkfs.ext4) >/dev/null 2>&1 || ENABLE_VBLK=0
type 7z >/dev/null 2>&1 || ENABLE_VBLK=0

TIMEOUT=50
OPTS=" -k build/linux-image/Image "
OPTS+=" -i build/linux-image/rootfs.cpio "
OPTS+=" -b build/minimal.dtb "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this can be remove since -b has been refined to be used to accept custom bootargs. Cc. @RinHizakura

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be removed within this pull request?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be removed within this pull request?

Yes, go ahead. Please also mention the rationale in the commit message.

};

struct virtq_desc {
uint32_t addr;
Copy link

@shengwen-tw shengwen-tw Jan 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Virtual I/O Device (VIRTIO) Version 1.3

2.7.5 The Virtqueue Descriptor Table

struct virtq_desc { 
        /* Address (guest-physical). */ 
        le64 addr; 
        /* Length. */ 
        le32 len; 
        /* The flags as indicated above. */ 
        le16 flags; 
        /* We chain unused descriptors via this, too */ 
        le16 next; 
}; 

We mistakenly defined virtq_desc.addr as 32 bits.
Please consider correcting it here and submitting a pull request for semu.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants