Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .ci/boot-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ if [ "${ENABLE_VBLK}" -eq "1" ]; then
expect "# " { send "\x01"; send "x" } timeout { exit 3 }
')

# multiple blocks, Read-only, one disk image, one loop device (/dev/loopx(Linux) or /dev/diskx(Darwin))
TEST_OPTIONS+=("${OPTS_BASE} -x vblk:${VBLK_IMG},readonly -x vblk:${BLK_DEV},readonly")
EXPECT_CMDS+=('
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { send "mkdir mnt && mount /dev/vda mnt\n" } timeout { exit 3 }
expect "# " { send "echo rv32emu > mnt/emu.txt\n" } timeout { exit 3 }
expect -ex "-sh: can'\''t create mnt/emu.txt: Read-only file system" {} timeout { exit 3 }
expect "# " { send "mkdir mnt2 && mount /dev/vdb mnt2\n" } timeout { exit 3 }
expect "# " { send "echo rv32emu > mnt2/emu.txt\n" } timeout { exit 3 }
expect -ex "-sh: can'\''t create mnt2/emu.txt: Read-only file system" {} timeout { exit 3 }
expect "# " { send "\x01"; send "x" } timeout { exit 3 }
')

# Read-write using disk image
TEST_OPTIONS+=("${OPTS_BASE} -x vblk:${VBLK_IMG}")
VBLK_EXPECT_CMDS='
Expand All @@ -77,6 +91,23 @@ if [ "${ENABLE_VBLK}" -eq "1" ]; then
# Read-write using /dev/loopx(Linux) or /dev/diskx(Darwin) block device
TEST_OPTIONS+=("${OPTS_BASE} -x vblk:${BLK_DEV}")
EXPECT_CMDS+=("${VBLK_EXPECT_CMDS}")

# multiple blocks, Read-write, one disk image and one loop device (/dev/loopx(Linux) or /dev/diskx(Darwin))
TEST_OPTIONS+=("${OPTS_BASE} -x vblk:${VBLK_IMG} -x vblk:${BLK_DEV}")
VBLK_EXPECT_CMDS='
expect "buildroot login:" { send "root\n" } timeout { exit 1 }
expect "# " { send "uname -a\n" } timeout { exit 2 }
expect "riscv32 GNU/Linux" { send "mkdir mnt && mount /dev/vda mnt\n" } timeout { exit 3 }
expect "# " { send "echo rv32emu > mnt/emu.txt\n" } timeout { exit 3 }
expect "# " { send "sync\n" } timeout { exit 3 }
expect "# " { send "umount mnt\n" } timeout { exit 3 }
expect "# " { send "mkdir mnt2 && mount /dev/vdb mnt2\n" } timeout { exit 3 }
expect "# " { send "echo rv32emu > mnt2/emu.txt\n" } timeout { exit 3 }
expect "# " { send "sync\n" } timeout { exit 3 }
expect "# " { send "umount mnt2\n" } timeout { exit 3 }
expect "# " { send "\x01"; send "x" } timeout { exit 3 }
'
EXPECT_CMDS+=("${VBLK_EXPECT_CMDS}")
fi

for i in "${!TEST_OPTIONS[@]}"; do
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ Mount the virtual block device and create a test file after booting, note that r
```
Reboot and re-mount the virtual block device, the written file should remain existing.

To specify multiple virtual block devices, pass multiple `-x vblk` options when launching the emulator. Each option can point to either a disk image or a hostOS block device, with optional read-only mode. For example:
```shell
$ build/rv32emu -k <kernel_img_path> -i <rootfs_img_path> -x vblk:disk.img -x vblk:/dev/loop22,readonly
```
Note that the /dev/vdx device order in guestOS is assigned in reverse: the first `-x vblk` argument corresponds to the device with the highest letter, while subsequent arguments receive lower-lettered device names.

#### Customize bootargs
Build and run with customized bootargs to boot the guestOS. Otherwise, the default bootargs defined in `src/devices/minimal.dts` will be used.
```shell
Expand Down
12 changes: 8 additions & 4 deletions src/devices/minimal.dts
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,14 @@
clock-frequency = <5000000>; /* the baudrate divisor is ignored */
};

blk0: virtio@4200000 {
/*
* Virtio block example subnode
* The actual subnode are generated dynamically depends on the CLI -x vblk option
*/
/*blk0: virtio@4100000 {
compatible = "virtio,mmio";
reg = <0x4200000 0x200>;
interrupts = <3>;
};
reg = <0x4100000 0x200>;
interrupts = <2>;
};*/
};
};
17 changes: 4 additions & 13 deletions src/devices/virtio-blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@

#define DISK_BLK_SIZE 512

/* TODO: Enable mutiple virtio-blk devices. */
#define VBLK_DEV_CNT_MAX 1

#define VBLK_FEATURES_0 0
#define VBLK_FEATURES_1 1 /* VIRTIO_F_VERSION_1 */
#define VBLK_QUEUE_NUM_MAX 1024
Expand Down Expand Up @@ -81,9 +78,6 @@ PACKED(struct vblk_req_header {
uint8_t status;
});

static struct virtio_blk_config vblk_configs[VBLK_DEV_CNT_MAX];
static int vblk_dev_cnt = 0;

static void virtio_blk_set_fail(virtio_blk_state_t *vblk)
{
vblk->status |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
Expand Down Expand Up @@ -401,20 +395,16 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk,
char *disk_file,
bool readonly)
{
if (vblk_dev_cnt >= VBLK_DEV_CNT_MAX) {
rv_log_error(
"Exceeded the number of virtio-blk devices that can be allocated");
exit(EXIT_FAILURE);
}

/*
* For mmap_fallback, if vblk is not specified, disk_fd should remain -1 and
* no fsync should be performed on exit.
*/

vblk->disk_fd = -1;

/* Allocate memory for the private member */
vblk->priv = &vblk_configs[vblk_dev_cnt++];
vblk->priv = calloc(1, sizeof(struct virtio_blk_config));
assert(vblk->priv);

/* No disk image is provided */
if (!disk_file) {
Expand Down Expand Up @@ -549,5 +539,6 @@ void vblk_delete(virtio_blk_state_t *vblk)
else
munmap(vblk->disk, VBLK_PRIV(vblk)->disk_size);
#endif
free(vblk->priv);
free(vblk);
}
3 changes: 1 addition & 2 deletions src/devices/virtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ struct virtq_desc {
uint16_t next;
};

#define IRQ_VBLK_SHIFT 3
#define IRQ_VBLK_BIT (1 << IRQ_VBLK_SHIFT)
#define IRQ_VBLK_BIT(base, i) (1 << (base + i))

typedef struct {
uint32_t queue_num;
Expand Down
21 changes: 16 additions & 5 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ static char *prof_out_file;
static char *opt_kernel_img;
static char *opt_rootfs_img;
static char *opt_bootargs;
static char *opt_virtio_blk_img;
/* FIXME: handle overflow */
#define VBLK_DEV_MAX 100
static char *opt_virtio_blk_img[VBLK_DEV_MAX];
static int opt_virtio_blk_idx = 0;
#endif

static void print_usage(const char *filename)
Expand All @@ -78,8 +81,10 @@ static void print_usage(const char *filename)
#if RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
" -k <image> : use <image> as kernel image\n"
" -i <image> : use <image> as rootfs\n"
" -x vblk:<image>[,readonly] : use <image> as virtio-blk disk image "
"(default read and write)\n"
" -x vblk:<image>[,readonly]: use "
"<image> as virtio-blk disk image "
"(default read and write). This option may be specified "
"multiple times for multiple block devices\n"
" -b <bootargs> : use customized <bootargs> for the kernel\n"
#endif
" -d [filename]: dump registers as JSON to the "
Expand Down Expand Up @@ -127,7 +132,8 @@ static bool parse_args(int argc, char **args)
break;
case 'x':
if (!strncmp("vblk:", optarg, 5))
opt_virtio_blk_img = optarg + 5; /* strlen("vblk:") */
opt_virtio_blk_img[opt_virtio_blk_idx++] =
optarg + 5; /* strlen("vblk:") */
else
return false;
emu_argc++;
Expand Down Expand Up @@ -273,7 +279,12 @@ int main(int argc, char **args)
attr.data.system.kernel = opt_kernel_img;
attr.data.system.initrd = opt_rootfs_img;
attr.data.system.bootargs = opt_bootargs;
attr.data.system.vblk_device = opt_virtio_blk_img;
if (opt_virtio_blk_idx) {
attr.data.system.vblk_device = opt_virtio_blk_img;
attr.data.system.vblk_device_cnt = opt_virtio_blk_idx;
} else {
attr.data.system.vblk_device = NULL;
}
#else
attr.data.user.elf_program = opt_prog_name;
#endif
Expand Down
Loading
Loading