Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8ba07b7

Browse files
MikazukiHikariChinYikMing
andcommitted
Implement virtio filesystem in semu
Map MMIO region at 0xF48____ for virtio-fs device in semu. Introduce special-case logic for char tag in virtio_fs config handling in semu. Add inode_map linked list for mapping inodes to file paths. Implement FUSE core operations: - INIT - GETATTR - OPENDIR - READDIRPLUS - LOOKUP - FORGET - RELEASEDIR - OPEN - READ - RELEASE - FLUSH - DESTROY to make semu supports commands:`cd`, `cat`, `ls`. Set default mount tag to "myfs" and mount directory to "./shared". When `make check`, if MOUNT_DIRECTORY is not exist, then create a new one. If -s parameter is empty, virtio-fs is unused. Add the explanation about virtio-fs in `Usage` of README.md. Add the introduction of how to mount and unmount in semu. When the guest OS attempts an unsupported operation, it should receive a "operation not supported" response instead of hanging to improve the user experience. Co-authored-by: ChinYikMing <yikming2222@gmail.com>
1 parent 51dbf26 commit 8ba07b7

File tree

9 files changed

+1338
-16
lines changed

9 files changed

+1338
-16
lines changed

‎Makefile

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ ifeq ($(call has, VIRTIORNG), 1)
4141
OBJS_EXTRA += virtio-rng.o
4242
endif
4343

44+
# virtio-fs
45+
ENABLE_VIRTIOFS ?= 1
46+
$(call set-feature, VIRTIOFS)
47+
SHARED_DIRECTORY ?= ./shared
48+
ifeq ($(call has, VIRTIOFS), 1)
49+
OBJS_EXTRA += virtio-fs.o
50+
OPTS += -s $(SHARED_DIRECTORY)
51+
endif
52+
4453
NETDEV ?= tap
4554
# virtio-net
4655
ENABLE_VIRTIONET ?= 1
@@ -214,7 +223,14 @@ ext4.img:
214223
$(Q)dd if=/dev/zero of=$@ bs=4k count=600
215224
$(Q)$(MKFS_EXT4) -F $@
216225

217-
check: $(BIN) minimal.dtb $(KERNEL_DATA) $(INITRD_DATA) $(DISKIMG_FILE)
226+
.PHONY: $(DIRECTORY)
227+
$(SHARED_DIRECTORY):
228+
@if [ ! -d $@ ]; then \
229+
echo "Creating mount directory: $@"; \
230+
mkdir -p $@; \
231+
fi
232+
233+
check: $(BIN) minimal.dtb $(KERNEL_DATA) $(INITRD_DATA) $(DISKIMG_FILE) $(SHARED_DIRECTORY)
218234
@$(call notice, Ready to launch Linux kernel. Please be patient.)
219235
$(Q)./$(BIN) -k $(KERNEL_DATA) -c $(SMP) -b minimal.dtb -i $(INITRD_DATA) -n $(NETDEV) $(OPTS)
220236

‎README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,33 @@ You can exit the emulator using: \<Ctrl-a x\>. (press Ctrl+A, leave it, afterwar
7777
## Usage
7878

7979
```shell
80-
./semu -k linux-image [-b dtb-file] [-i initrd-image] [-d disk-image]
80+
./semu -k linux-image [-b dtb-file] [-i initrd-image] [-d disk-image] [-s shared-directory]
8181
```
8282

8383
* `linux-image` is the path to the Linux kernel `Image`.
8484
* `dtb-file` is optional, as it specifies the user-specified device tree blob.
8585
* `initrd-image` is optional, as it specifies the user-specified initial RAM disk image.
8686
* `disk-image` is optional, as it specifies the path of a disk image in ext4 file system for the virtio-blk device.
87+
* `shared-directory` is optional, as it specifies the path of a directory on the host that will be shared with the guest operating system through virtio-fs, enabling file access from the guest via a virtual filesystem mount.
88+
89+
## Mount and unmount a directory in semu
90+
91+
To mount the directory in semu:
92+
93+
```shell
94+
$ mount -t virtiofs myfs [shared-directory]
95+
```
96+
97+
* `shared-directory` is the path of a directory you want to mount in semu.
98+
99+
To unmount the directory in semu:
100+
101+
```shell
102+
$ umount [shared-directory]
103+
```
104+
105+
* `shared-directory` is the path of a directory you want to unmount in semu.
106+
87107

88108
## Build Linux kernel image and root file system
89109

‎device.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,70 @@ void virtio_snd_write(hart_t *core,
357357
bool virtio_snd_init(virtio_snd_state_t *vsnd);
358358
#endif /* SEMU_HAS(VIRTIOSND) */
359359

360+
/* VirtIO-File-System */
361+
362+
#if SEMU_HAS(VIRTIOFS)
363+
#define IRQ_VFS 6
364+
#define IRQ_VFS_BIT (1 << IRQ_VFS)
365+
366+
typedef struct inode_map_entry {
367+
uint64_t ino;
368+
char *path;
369+
struct inode_map_entry *next;
370+
} inode_map_entry;
371+
372+
typedef struct {
373+
uint32_t QueueNum;
374+
uint32_t QueueDesc;
375+
uint32_t QueueAvail;
376+
uint32_t QueueUsed;
377+
uint16_t last_avail;
378+
bool ready;
379+
} virtio_fs_queue_t;
380+
381+
typedef struct {
382+
/* feature negotiation */
383+
uint32_t DeviceFeaturesSel;
384+
uint32_t DriverFeatures;
385+
uint32_t DriverFeaturesSel;
386+
387+
/* queue config */
388+
uint32_t QueueSel;
389+
virtio_fs_queue_t queues[3];
390+
391+
/* status */
392+
uint32_t Status;
393+
uint32_t InterruptStatus;
394+
395+
/* guest memory base */
396+
uint32_t *ram;
397+
398+
char *mount_tag; /* guest sees this tag */
399+
char *shared_dir;
400+
401+
inode_map_entry *inode_map;
402+
403+
/* optional implementation-specific */
404+
void *priv;
405+
} virtio_fs_state_t;
406+
407+
/* MMIO read/write */
408+
void virtio_fs_read(hart_t *core,
409+
virtio_fs_state_t *vfs,
410+
uint32_t addr,
411+
uint8_t width,
412+
uint32_t *value);
413+
414+
void virtio_fs_write(hart_t *core,
415+
virtio_fs_state_t *vfs,
416+
uint32_t addr,
417+
uint8_t width,
418+
uint32_t value);
419+
420+
bool virtio_fs_init(virtio_fs_state_t *vfs, char *mtag, char *dir);
421+
422+
#endif /* SEMU_HAS(VIRTIOFS) */
423+
360424
/* memory mapping */
361425
typedef struct {
362426
bool debug;
@@ -382,6 +446,9 @@ typedef struct {
382446
#if SEMU_HAS(VIRTIOSND)
383447
virtio_snd_state_t vsnd;
384448
#endif
449+
#if SEMU_HAS(VIRTIOFS)
450+
virtio_fs_state_t vfs;
451+
#endif
385452

386453
uint32_t peripheral_update_ctr;
387454

‎feature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,10 @@
1717
#define SEMU_FEATURE_VIRTIOSND 1
1818
#endif
1919

20+
/* virtio-fs */
21+
#ifndef SEMU_FEATURE_VIRTIOFS
22+
#define SEMU_FEATURE_VIRTIOFS 1
23+
#endif
24+
2025
/* Feature test macro */
2126
#define SEMU_HAS(x) SEMU_FEATURE_##x

‎fuse.h

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#include "riscv.h"
2+
#include "virtio.h"
3+
4+
#define FUSE_REC_ALIGN(x) \
5+
(((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
6+
#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x)
7+
8+
struct fuse_in_header {
9+
uint32_t len;
10+
uint32_t opcode;
11+
uint64_t unique;
12+
uint64_t nodeid;
13+
uint32_t uid;
14+
uint32_t gid;
15+
uint32_t pid;
16+
uint32_t padding;
17+
};
18+
19+
struct fuse_out_header {
20+
uint32_t len;
21+
int32_t error;
22+
uint64_t unique;
23+
};
24+
25+
struct vfs_req_header {
26+
struct fuse_in_header in;
27+
};
28+
29+
struct vfs_resp_header {
30+
struct fuse_out_header out;
31+
};
32+
33+
struct fuse_init_in {
34+
/* FUSE major version supported by the guest (typically 7) */
35+
uint32_t major;
36+
/* FUSE minor version supported by the guest (e.g., 31, 26) */
37+
uint32_t minor;
38+
uint32_t max_readahead; /* Maximum readahead size supported by the guest */
39+
uint32_t flags; /* Flags requested by the guest */
40+
};
41+
42+
struct fuse_init_out {
43+
uint32_t major; /* FUSE major version supported by the device */
44+
uint32_t minor; /* FUSE minor version supported by the device */
45+
uint32_t max_readahead; /* Maximum readahead size accepted by the device */
46+
/* Flags supported by the device (negotiated with the guest) */
47+
uint32_t flags;
48+
uint16_t max_background; /* Maximum number of background requests */
49+
uint16_t congestion_threshold;
50+
uint32_t max_write; /* Maximum write size the device can handle */
51+
uint32_t time_gran; /* Time granularity (in nanoseconds) */
52+
uint32_t unused[11]; /* Reserved */
53+
};
54+
55+
struct fuse_getattr_in {
56+
/* bitmask for valid fields (e.g. FUSE_GETATTR_FH) */
57+
uint32_t getattr_flags;
58+
uint32_t padding; /* unused, reserved for alignment */
59+
uint64_t fh; /* optional: file handle (used when getattr_flags has */
60+
};
61+
62+
struct fuse_attr {
63+
uint64_t ino; /* inode number */
64+
uint64_t size; /* file size in bytes */
65+
uint64_t blocks; /* number of 512B blocks allocated */
66+
uint64_t atime; /* last access time (UNIX time) */
67+
uint64_t mtime; /* last modification time */
68+
uint64_t ctime; /* last status change time */
69+
uint32_t atimensec; /* nanoseconds part */
70+
uint32_t mtimensec;
71+
uint32_t ctimensec;
72+
uint32_t mode; /* file mode (e.g. S_IFDIR | 0755) */
73+
uint32_t nlink; /* number of hard links */
74+
uint32_t uid; /* owner uid */
75+
uint32_t gid; /* owner gid */
76+
uint32_t rdev; /* device ID (if special file) */
77+
uint32_t blksize; /* block size */
78+
uint32_t flags; /* reserved */
79+
};
80+
81+
struct fuse_attr_out {
82+
uint64_t attr_valid; /* seconds the attributes are valid */
83+
uint32_t attr_valid_nsec; /* nanoseconds part of attr_valid */
84+
uint32_t dummy; /* padding for alignment */
85+
struct fuse_attr attr; /* actual attributes */
86+
};
87+
88+
struct fuse_open_in {
89+
uint32_t flags;
90+
uint32_t open_flags;
91+
};
92+
93+
struct fuse_open_out {
94+
uint64_t fh;
95+
uint32_t open_flags;
96+
int32_t backing_id;
97+
};
98+
99+
struct fuse_read_in {
100+
uint64_t fh;
101+
uint64_t offset;
102+
uint32_t size;
103+
uint32_t read_flags;
104+
uint64_t lock_owner;
105+
uint32_t flags;
106+
uint32_t padding;
107+
};
108+
109+
struct fuse_entry_out {
110+
uint64_t nodeid; /* inode number */
111+
uint64_t generation; /* inode generation */
112+
uint64_t entry_valid; /* cache timeout (sec) */
113+
uint64_t attr_valid; /* attr cache timeout (sec) */
114+
uint32_t entry_valid_nsec; /* cache timeout (nsec) */
115+
uint32_t attr_valid_nsec; /* attr cache timeout (nsec) */
116+
struct fuse_attr attr; /* file attributes */
117+
};
118+
119+
struct fuse_dirent {
120+
uint64_t ino; /* inode number */
121+
uint64_t off; /* offset to next entry */
122+
uint32_t namelen; /* length of the entry name */
123+
uint32_t type; /* file type (DT_REG, DT_DIR, etc.) */
124+
char name[]; /* name (not null-terminated) */
125+
};
126+
127+
struct fuse_direntplus {
128+
struct fuse_entry_out entry_out;
129+
struct fuse_dirent dirent;
130+
};
131+
132+
struct fuse_lookup_in {
133+
uint64_t parent; /* inode of parent dir */
134+
};
135+
136+
struct fuse_forget_in {
137+
uint64_t nlookup;
138+
};
139+
140+
struct fuse_create_in {
141+
uint32_t flags;
142+
uint32_t mode;
143+
uint32_t umask;
144+
uint32_t open_flags;
145+
};
146+
147+
struct fuse_release_in {
148+
uint64_t fh;
149+
uint32_t flags;
150+
uint32_t release_flags;
151+
uint64_t lock_owner;
152+
};
153+
154+
struct fuse_flush_in {
155+
uint64_t fh;
156+
uint32_t unused;
157+
uint32_t padding;
158+
uint64_t lock_owner;
159+
};

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /