Skip to content

Commit 50870fb

Browse files
Implement virtio-fs filesystem in semu
Implement virtio-fs filesystem with FUSE core operations in semu. Add key configs in /configs/linux.config to enable required features (e.g., virtio-fs) for kernel build. Add config options to generate /proc/config.gz for verifying kernel parameters 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 hash table 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".
1 parent 32cbd56 commit 50870fb

File tree

9 files changed

+1216
-12
lines changed

9 files changed

+1216
-12
lines changed

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ 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+
ifeq ($(call has, VIRTIOFS), 1)
48+
OBJS_EXTRA += virtio-fs.o
49+
OPTS += -s ./shared
50+
endif
51+
4452
NETDEV ?= tap
4553
# virtio-net
4654
ENABLE_VIRTIONET ?= 1

configs/linux.config

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ CONFIG_SRCU=y
102102
CONFIG_TINY_SRCU=y
103103
# end of RCU Subsystem
104104

105-
# CONFIG_IKCONFIG is not set
105+
CONFIG_IKCONFIG=y
106+
CONFIG_IKCONFIG_PROC=y
106107
# CONFIG_IKHEADERS is not set
107108
CONFIG_LOG_BUF_SHIFT=16
108109
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
@@ -947,6 +948,10 @@ CONFIG_SND=y
947948
CONFIG_SND_VIRTIO=y
948949
CONFIG_SND_HRTIMER=y
949950

951+
CONFIG_CUSE=y
952+
CONFIG_FUSE_FS=y
953+
CONFIG_VIRTIO_FS=y
954+
950955
#
951956
# HID support
952957
#
@@ -1257,7 +1262,7 @@ CONFIG_INOTIFY_USER=y
12571262
# CONFIG_QUOTA is not set
12581263
CONFIG_AUTOFS4_FS=y
12591264
CONFIG_AUTOFS_FS=y
1260-
# CONFIG_FUSE_FS is not set
1265+
12611266
# CONFIG_OVERLAY_FS is not set
12621267

12631268
#

device.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#if SEMU_HAS(VIRTIONET)
44
#include "netdev.h"
55
#endif
6+
#include <uthash.h>
67
#include "riscv.h"
78
#include "virtio.h"
89

@@ -357,6 +358,70 @@ void virtio_snd_write(hart_t *core,
357358
bool virtio_snd_init(virtio_snd_state_t *vsnd);
358359
#endif /* SEMU_HAS(VIRTIOSND) */
359360

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

386454
uint32_t peripheral_update_ctr;
387455

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

0 commit comments

Comments
 (0)