All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] fs: Add 9P filesystem support over virtio
@ 2026-07-06 21:54 Kuan-Wei Chiu
  2026-07-06 21:54 ` [PATCH 1/4] net: 9p: Add 9P2000 protocol support Kuan-Wei Chiu
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Kuan-Wei Chiu @ 2026-07-06 21:54 UTC (permalink / raw)
  To: trini, bmeng.cn, joe.hershberger, rfried.dev, jerome.forissier
  Cc: jserv, eleanor15x, marscheng, u-boot, Kuan-Wei Chiu

Add 9P network filesystem support to U-Boot.

It allows U-Boot to directly mount host directories in virtualization
environments via virtio.

The functionality has been verified on qemu arm64 by successfully
loading a Linux kernel image and an initramfs image via 9P, and booting
to the Linux shell.

To test with QEMU:
  -fsdev local,id=fsdev0,path=/path/to/host/dir,security_model=none \
  -device virtio-9p-device,fsdev=fsdev0,mount_tag=rootfs

U-Boot usage:
  => virtio scan
  => ls 9p - /
  => load 9p - $kernel_addr_r /Image
  => load 9p - $ramdisk_addr_r /initramfs.cpio
  => booti $kernel_addr_r $ramdisk_addr_r:$filesize $fdtcontroladdr

Kuan-Wei Chiu (4):
  net: 9p: Add 9P2000 protocol support
  fs: 9p: Add 9P filesystem support
  virtio: 9p: Add 9P transport driver
  MAINTAINERS: Add entry for 9PFS

 MAINTAINERS                    |   8 +
 drivers/virtio/Kconfig         |   7 +
 drivers/virtio/Makefile        |   1 +
 drivers/virtio/virtio-uclass.c |   1 +
 drivers/virtio/virtio_9p.c     |  75 +++++++++
 fs/9p/9p.c                     | 137 +++++++++++++++++
 fs/9p/Kconfig                  |   8 +
 fs/9p/Makefile                 |   5 +
 fs/Kconfig                     |   2 +
 fs/Makefile                    |   1 +
 fs/fs.c                        |  35 +++++
 include/9p.h                   |  82 ++++++++++
 include/fs.h                   |   1 +
 include/virtio.h               |   4 +-
 net/9p/Kconfig                 |   5 +
 net/9p/Makefile                |   5 +
 net/9p/client.c                | 272 +++++++++++++++++++++++++++++++++
 net/Kconfig                    |   2 +
 net/Makefile                   |   1 +
 19 files changed, 651 insertions(+), 1 deletion(-)
 create mode 100644 drivers/virtio/virtio_9p.c
 create mode 100644 fs/9p/9p.c
 create mode 100644 fs/9p/Kconfig
 create mode 100644 fs/9p/Makefile
 create mode 100644 include/9p.h
 create mode 100644 net/9p/Kconfig
 create mode 100644 net/9p/Makefile
 create mode 100644 net/9p/client.c

-- 
2.55.0.rc2.803.g1fd1e6609c-goog


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] net: 9p: Add 9P2000 protocol support
  2026-07-06 21:54 [PATCH 0/4] fs: Add 9P filesystem support over virtio Kuan-Wei Chiu
@ 2026-07-06 21:54 ` Kuan-Wei Chiu
  2026-07-06 21:54 ` [PATCH 2/4] fs: 9p: Add 9P filesystem support Kuan-Wei Chiu
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Kuan-Wei Chiu @ 2026-07-06 21:54 UTC (permalink / raw)
  To: trini, bmeng.cn, joe.hershberger, rfried.dev, jerome.forissier
  Cc: jserv, eleanor15x, marscheng, u-boot, Kuan-Wei Chiu

Introduce the core 9P network protocol client implementation.

9P is a network filesystem protocol originally developed for the
Plan 9 operating system. Add the baseline 9P2000.L protocol handling,
including message serialization, client registration, and basic
transport operations.

Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
---
 include/9p.h    |  82 +++++++++++++++
 net/9p/Kconfig  |   5 +
 net/9p/Makefile |   5 +
 net/9p/client.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/Kconfig     |   2 +
 net/Makefile    |   1 +
 6 files changed, 367 insertions(+)
 create mode 100644 include/9p.h
 create mode 100644 net/9p/Kconfig
 create mode 100644 net/9p/Makefile
 create mode 100644 net/9p/client.c

diff --git a/include/9p.h b/include/9p.h
new file mode 100644
index 00000000000..5e46daa3414
--- /dev/null
+++ b/include/9p.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026, Kuan-Wei Chiu <visitorckw@gmail.com>
+ */
+
+#ifndef __9P_H__
+#define __9P_H__
+
+#include <linux/types.h>
+
+#define P9_MSIZE            65536
+#define P9_NOFID            (~0U)
+#define P9_NOTAG            0xFFFF
+#define P9_REQ_TAG          1
+
+#define P9_RLERROR          7
+#define P9_TLOPEN           12
+#define P9_RLOPEN           13
+#define P9_TGETATTR         24
+#define P9_RGETATTR         25
+#define P9_TREADDIR         40
+#define P9_RREADDIR         41
+#define P9_TVERSION         100
+#define P9_RVERSION         101
+#define P9_TATTACH          104
+#define P9_RATTACH          105
+#define P9_TWALK            110
+#define P9_RWALK            111
+#define P9_TREAD            116
+#define P9_RREAD            117
+#define P9_TCLUNK           120
+#define P9_RCLUNK           121
+
+#define P9_O_RDONLY         00000000
+#define P9_GETATTR_SIZE     0x00000010ULL
+#define P9_GETATTR_SIZE_OFFSET  41
+#define P9_DIRENT_OFFSET    21
+#define P9_DT_DIR           4
+
+struct p9_header {
+	u32 size;
+	u8  id;
+	u16 tag;
+} __packed;
+
+struct p9_client;
+
+struct p9_trans_ops {
+	int (*request)(struct p9_client *c, void *tx, int tx_len, void *rx, int rx_len);
+};
+
+struct p9_client {
+	const struct p9_trans_ops *ops;
+	void *priv;
+	u8 *tx;
+	u8 *rx;
+	u32 next_fid;
+};
+
+void p9_register_client(struct p9_client *c);
+struct p9_client *p9_get_client(void);
+
+u32 p9_client_alloc_fid(struct p9_client *c);
+int p9_client_version(struct p9_client *c);
+int p9_client_attach(struct p9_client *c, u32 fid, const char *uname, const char *aname);
+int p9_client_walk(struct p9_client *c, u32 base_fid, u32 new_fid, const char *path);
+int p9_client_lopen(struct p9_client *c, u32 fid, u32 flags);
+int p9_client_clunk(struct p9_client *c, u32 fid);
+int p9_client_stat(struct p9_client *c, u32 fid, loff_t *size);
+int p9_client_read(struct p9_client *c, u32 fid, u64 offset, u32 count, void *buf, u32 *actread);
+int p9_client_readdir(struct p9_client *c, u32 fid, u64 offset, u32 count, void *buf, u32 *actread);
+
+struct blk_desc;
+struct disk_partition;
+
+int p9_fs_probe(struct blk_desc *fs_dev_desc, struct disk_partition *fs_partition);
+int p9_fs_ls(const char *dirname);
+int p9_fs_exists(const char *filename);
+int p9_fs_size(const char *filename, loff_t *size);
+int p9_fs_read(const char *filename, void *buf, loff_t offset, loff_t len, loff_t *actread);
+
+#endif /* __9P_H__ */
diff --git a/net/9p/Kconfig b/net/9p/Kconfig
new file mode 100644
index 00000000000..3681e0b6d6d
--- /dev/null
+++ b/net/9p/Kconfig
@@ -0,0 +1,5 @@
+config NET_9P
+	bool "9P protocol support"
+	help
+	  This enables support for the 9P network protocol (9P2000).
+	  It implements the core 9P client and protocol handling.
diff --git a/net/9p/Makefile b/net/9p/Makefile
new file mode 100644
index 00000000000..e9220b0826e
--- /dev/null
+++ b/net/9p/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026, Kuan-Wei Chiu <visitorckw@gmail.com>
+
+obj-y += client.o
diff --git a/net/9p/client.c b/net/9p/client.c
new file mode 100644
index 00000000000..038cb7a78c0
--- /dev/null
+++ b/net/9p/client.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026, Kuan-Wei Chiu <visitorckw@gmail.com>
+ */
+
+#include <9p.h>
+#include <config.h>
+#include <log.h>
+#include <malloc.h>
+#include <asm/cache.h>
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+static struct p9_client *current_client;
+
+void p9_register_client(struct p9_client *c)
+{
+	current_client = c;
+}
+
+struct p9_client *p9_get_client(void)
+{
+	return current_client;
+}
+
+u32 p9_client_alloc_fid(struct p9_client *c)
+{
+	if (c->next_fid >= 0xFFFF0000 || c->next_fid == 0)
+		c->next_fid = 2; /* fid 1 is reserved for root */
+	return c->next_fid++;
+}
+
+static void p9_put_u16(u8 **p, u16 v)
+{
+	put_unaligned_le16(v, *p);
+	*p += 2;
+}
+
+static void p9_put_u32(u8 **p, u32 v)
+{
+	put_unaligned_le32(v, *p);
+	*p += 4;
+}
+
+static void p9_put_u64(u8 **p, u64 v)
+{
+	put_unaligned_le64(v, *p); *p += 8;
+}
+
+static void p9_put_str(u8 **p, const char *s)
+{
+	u16 len = strlen(s);
+
+	put_unaligned_le16(len, *p);
+	*p += 2;
+	memcpy(*p, s, len);
+	*p += len;
+}
+
+static int p9_check_error(struct p9_client *c, int expected_id, const char *step)
+{
+	struct p9_header *rx_hdr = (struct p9_header *)c->rx;
+	u32 ecode;
+
+	if (rx_hdr->id == P9_RLERROR) {
+		ecode = get_unaligned_le32(c->rx + 7);
+		log_err("9P Error: %s failed (ecode=%u)\n", step, ecode);
+		return -EIO;
+	} else if (rx_hdr->id != expected_id) {
+		log_err("9P Error: %s got id %d (expected %d)\n", step, rx_hdr->id, expected_id);
+		return -EIO;
+	}
+	return 0;
+}
+
+int p9_client_version(struct p9_client *c)
+{
+	struct p9_header *hdr;
+	u8 *ptr;
+
+	if (!c->tx)
+		c->tx = memalign(ARCH_DMA_MINALIGN, P9_MSIZE);
+	if (!c->rx)
+		c->rx = memalign(ARCH_DMA_MINALIGN, P9_MSIZE);
+
+	hdr = (struct p9_header *)c->tx;
+	ptr = c->tx + sizeof(*hdr);
+	p9_put_u32(&ptr, P9_MSIZE);
+	p9_put_str(&ptr, "9P2000.L");
+
+	hdr->size = ptr - c->tx;
+	hdr->id = P9_TVERSION;
+	hdr->tag = P9_NOTAG;
+
+	if (c->ops->request(c, c->tx, hdr->size, c->rx, P9_MSIZE) < 0)
+		return -EIO;
+
+	return p9_check_error(c, P9_RVERSION, "Tversion");
+}
+
+int p9_client_attach(struct p9_client *c, u32 fid, const char *uname, const char *aname)
+{
+	struct p9_header *hdr = (struct p9_header *)c->tx;
+	u8 *ptr = c->tx + sizeof(*hdr);
+
+	p9_put_u32(&ptr, fid);
+	p9_put_u32(&ptr, P9_NOFID);
+	p9_put_str(&ptr, uname);
+	p9_put_str(&ptr, aname);
+	p9_put_u32(&ptr, 0);
+
+	hdr->size = ptr - c->tx;
+	hdr->id = P9_TATTACH;
+	hdr->tag = P9_REQ_TAG;
+
+	if (c->ops->request(c, c->tx, hdr->size, c->rx, P9_MSIZE) < 0)
+		return -EIO;
+
+	return p9_check_error(c, P9_RATTACH, "Tattach");
+}
+
+int p9_client_walk(struct p9_client *c, u32 base_fid, u32 new_fid, const char *path)
+{
+	struct p9_header *hdr = (struct p9_header *)c->tx;
+	u8 *ptr = c->tx + sizeof(*hdr);
+	char path_buf[128];
+	char *wnames[16];
+	char *token, *p = path_buf;
+	int nwname = 0, i;
+
+	strlcpy(path_buf, path, sizeof(path_buf));
+	while ((token = strsep(&p, "/")) != NULL) {
+		if (*token == '\0' || strcmp(token, ".") == 0)
+			continue;
+		if (nwname >= 16) {
+			log_err("9P: Path too deep (max 16 levels)\n");
+			return -EINVAL;
+		}
+		wnames[nwname++] = token;
+	}
+
+	p9_put_u32(&ptr, base_fid);
+	p9_put_u32(&ptr, new_fid);
+	p9_put_u16(&ptr, nwname);
+	for (i = 0; i < nwname; i++)
+		p9_put_str(&ptr, wnames[i]);
+
+	hdr->size = ptr - c->tx;
+	hdr->id = P9_TWALK;
+	hdr->tag = P9_REQ_TAG;
+
+	if (c->ops->request(c, c->tx, hdr->size, c->rx, P9_MSIZE) < 0)
+		return -EIO;
+
+	return p9_check_error(c, P9_RWALK, "Twalk");
+}
+
+int p9_client_lopen(struct p9_client *c, u32 fid, u32 flags)
+{
+	struct p9_header *hdr = (struct p9_header *)c->tx;
+	u8 *ptr = c->tx + sizeof(*hdr);
+
+	p9_put_u32(&ptr, fid);
+	p9_put_u32(&ptr, flags);
+
+	hdr->size = ptr - c->tx;
+	hdr->id = P9_TLOPEN;
+	hdr->tag = P9_REQ_TAG;
+
+	if (c->ops->request(c, c->tx, hdr->size, c->rx, P9_MSIZE) < 0)
+		return -EIO;
+
+	return p9_check_error(c, P9_RLOPEN, "Tlopen");
+}
+
+int p9_client_clunk(struct p9_client *c, u32 fid)
+{
+	struct p9_header *hdr = (struct p9_header *)c->tx;
+	u8 *ptr = c->tx + sizeof(*hdr);
+
+	p9_put_u32(&ptr, fid);
+	hdr->size = ptr - c->tx;
+	hdr->id = P9_TCLUNK;
+	hdr->tag = P9_REQ_TAG;
+
+	return c->ops->request(c, c->tx, hdr->size, c->rx, P9_MSIZE);
+}
+
+int p9_client_stat(struct p9_client *c, u32 fid, loff_t *size)
+{
+	struct p9_header *hdr = (struct p9_header *)c->tx;
+	u8 *ptr = c->tx + sizeof(*hdr);
+	u64 valid;
+
+	p9_put_u32(&ptr, fid);
+	p9_put_u64(&ptr, P9_GETATTR_SIZE);
+
+	hdr->size = ptr - c->tx;
+	hdr->id = P9_TGETATTR;
+	hdr->tag = P9_REQ_TAG;
+
+	if (c->ops->request(c, c->tx, hdr->size, c->rx, P9_MSIZE) < 0)
+		return -EIO;
+
+	if (p9_check_error(c, P9_RGETATTR, "Tgetattr") == 0) {
+		ptr = c->rx + sizeof(*hdr);
+		valid = get_unaligned_le64(ptr);
+		ptr += sizeof(valid);
+		ptr += P9_GETATTR_SIZE_OFFSET;
+		if (valid & P9_GETATTR_SIZE) {
+			*size = get_unaligned_le64(ptr);
+			return 0;
+		}
+	}
+	return -EIO;
+}
+
+int p9_client_read(struct p9_client *c, u32 fid, u64 offset, u32 count, void *buf, u32 *actread)
+{
+	struct p9_header *hdr = (struct p9_header *)c->tx;
+	u8 *ptr = c->tx + sizeof(*hdr);
+	u32 max_read = P9_MSIZE - 24;
+	u32 read_len = (count == 0 || count > max_read) ? max_read : count;
+
+	p9_put_u32(&ptr, fid);
+	p9_put_u64(&ptr, offset);
+	p9_put_u32(&ptr, read_len);
+
+	hdr->size = ptr - c->tx;
+	hdr->id = P9_TREAD;
+	hdr->tag = P9_REQ_TAG;
+
+	if (c->ops->request(c, c->tx, hdr->size, c->rx, P9_MSIZE) < 0)
+		return -EIO;
+
+	if (p9_check_error(c, P9_RREAD, "Tread") == 0) {
+		ptr = c->rx + sizeof(*hdr);
+		*actread = get_unaligned_le32(ptr);
+		ptr += 4;
+		memcpy(buf, ptr, *actread);
+		return 0;
+	}
+	return -EIO;
+}
+
+int p9_client_readdir(struct p9_client *c, u32 fid, u64 offset, u32 count, void *buf, u32 *actread)
+{
+	struct p9_header *hdr = (struct p9_header *)c->tx;
+	u8 *ptr = c->tx + sizeof(*hdr);
+
+	p9_put_u32(&ptr, fid);
+	p9_put_u64(&ptr, offset);
+	p9_put_u32(&ptr, count);
+
+	hdr->size = ptr - c->tx;
+	hdr->id = P9_TREADDIR;
+	hdr->tag = P9_REQ_TAG;
+
+	if (c->ops->request(c, c->tx, hdr->size, c->rx, P9_MSIZE) < 0)
+		return -EIO;
+
+	if (p9_check_error(c, P9_RREADDIR, "Treaddir") == 0) {
+		ptr = c->rx + sizeof(*hdr);
+		*actread = get_unaligned_le32(ptr);
+		ptr += 4;
+		memcpy(buf, ptr, *actread);
+		return 0;
+	}
+	return -EIO;
+}
diff --git a/net/Kconfig b/net/Kconfig
index 386376ce884..00448ab4cc6 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -236,6 +236,8 @@ endif   # if NET_LEGACY
 
 source "net/lwip/Kconfig"
 
+source "net/9p/Kconfig"
+
 config BOOTDEV_ETH
 	bool "Enable bootdev for ethernet"
 	depends on BOOTSTD
diff --git a/net/Makefile b/net/Makefile
index ceac6de6377..7745607248b 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -49,3 +49,4 @@ obj-y += net-common.o
 endif
 
 obj-$(CONFIG_NET_LWIP) += lwip/
+obj-$(CONFIG_NET_9P) += 9p/
-- 
2.55.0.rc2.803.g1fd1e6609c-goog


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/4] fs: 9p: Add 9P filesystem support
  2026-07-06 21:54 [PATCH 0/4] fs: Add 9P filesystem support over virtio Kuan-Wei Chiu
  2026-07-06 21:54 ` [PATCH 1/4] net: 9p: Add 9P2000 protocol support Kuan-Wei Chiu
@ 2026-07-06 21:54 ` Kuan-Wei Chiu
  2026-07-06 21:54 ` [PATCH 3/4] virtio: 9p: Add 9P transport driver Kuan-Wei Chiu
  2026-07-06 21:54 ` [PATCH 4/4] MAINTAINERS: Add entry for 9PFS Kuan-Wei Chiu
  3 siblings, 0 replies; 5+ messages in thread
From: Kuan-Wei Chiu @ 2026-07-06 21:54 UTC (permalink / raw)
  To: trini, bmeng.cn, joe.hershberger, rfried.dev, jerome.forissier
  Cc: jserv, eleanor15x, marscheng, u-boot, Kuan-Wei Chiu

Implement the VFS interface for the 9P filesystem.

Map the U-Boot filesystem operations to the underlying 9P protocol
client. It also registers the 9P filesystem type within the U-Boot
generic fs framework, allowing it to bypass standard block device
partition checks since 9P is a network/host-backed filesystem.

Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
---
 fs/9p/9p.c     | 137 +++++++++++++++++++++++++++++++++++++++++++++++++
 fs/9p/Kconfig  |   8 +++
 fs/9p/Makefile |   5 ++
 fs/Kconfig     |   2 +
 fs/Makefile    |   1 +
 fs/fs.c        |  35 +++++++++++++
 include/fs.h   |   1 +
 7 files changed, 189 insertions(+)
 create mode 100644 fs/9p/9p.c
 create mode 100644 fs/9p/Kconfig
 create mode 100644 fs/9p/Makefile

diff --git a/fs/9p/9p.c b/fs/9p/9p.c
new file mode 100644
index 00000000000..37d60c03891
--- /dev/null
+++ b/fs/9p/9p.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026, Kuan-Wei Chiu <visitorckw@gmail.com>
+ */
+
+#include <9p.h>
+#include <config.h>
+#include <log.h>
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+static u32 p9_root_fid = 1;
+
+int p9_fs_probe(struct blk_desc *fs_dev_desc, struct disk_partition *fs_partition)
+{
+	struct p9_client *c = p9_get_client();
+
+	if (!c) {
+		log_err("9P Error: No transport client registered\n");
+		return -ENODEV;
+	}
+
+	if (p9_client_version(c))
+		return -EIO;
+	if (p9_client_attach(c, p9_root_fid, "root", ""))
+		return -EIO;
+
+	return 0;
+}
+
+int p9_fs_ls(const char *dirname)
+{
+	struct p9_client *c = p9_get_client();
+	u32 fid = p9_client_alloc_fid(c);
+	u8 buf[4096];
+	u32 actread;
+	u8 *ptr, *end;
+	u16 name_len;
+	u8 d_type;
+
+	if (p9_client_walk(c, p9_root_fid, fid, dirname))
+		return -ENOENT;
+	if (p9_client_lopen(c, fid, P9_O_RDONLY))
+		return -EIO;
+
+	if (p9_client_readdir(c, fid, 0, sizeof(buf), buf, &actread)) {
+		p9_client_clunk(c, fid);
+		return -EIO;
+	}
+
+	if (actread == 0) {
+		printf("  (empty directory)\n");
+	} else {
+		ptr = buf;
+		end = buf + actread;
+		while (ptr < end) {
+			ptr += P9_DIRENT_OFFSET;
+			d_type = *ptr++;
+			name_len = get_unaligned_le16(ptr);
+			ptr += 2;
+			printf("  %s %.*s\n", (d_type == P9_DT_DIR) ? "<DIR> " : "      ",
+			       name_len, ptr);
+			ptr += name_len;
+		}
+	}
+
+	p9_client_clunk(c, fid);
+	return 0;
+}
+
+int p9_fs_size(const char *filename, loff_t *size)
+{
+	struct p9_client *c = p9_get_client();
+	u32 fid = p9_client_alloc_fid(c);
+	int ret;
+
+	if (p9_client_walk(c, p9_root_fid, fid, filename))
+		return -ENOENT;
+	ret = p9_client_stat(c, fid, size);
+	p9_client_clunk(c, fid);
+
+	return ret;
+}
+
+int p9_fs_exists(const char *filename)
+{
+	loff_t size;
+
+	return (p9_fs_size(filename, &size) == 0) ? 1 : 0;
+}
+
+int p9_fs_read(const char *filename, void *buf, loff_t offset, loff_t len, loff_t *actread)
+{
+	struct p9_client *c = p9_get_client();
+	u32 fid = p9_client_alloc_fid(c);
+	u32 read_bytes = 0;
+	loff_t total_read = 0;
+	loff_t remaining;
+	u32 req_len;
+	u8 *dst = (u8 *)buf;
+	int ret = 0;
+
+	if (p9_client_walk(c, p9_root_fid, fid, filename))
+		return -ENOENT;
+	if (p9_client_lopen(c, fid, P9_O_RDONLY)) {
+		p9_client_clunk(c, fid);
+		return -EIO;
+	}
+
+	while (1) {
+		if (len == 0) {
+			req_len = 0;
+		} else {
+			remaining = len - total_read;
+			if (remaining == 0)
+				break;
+
+			req_len = (remaining > 0xFFFFFFFF) ? 0xFFFFFFFF : (u32)remaining;
+		}
+
+		ret = p9_client_read(c, fid, offset, req_len, dst, &read_bytes);
+
+		if (ret != 0 || read_bytes == 0)
+			break;
+
+		total_read += read_bytes;
+		offset += read_bytes;
+		dst += read_bytes;
+	}
+
+	*actread = total_read;
+	p9_client_clunk(c, fid);
+
+	return (total_read > 0 || ret == 0) ? 0 : ret;
+}
diff --git a/fs/9p/Kconfig b/fs/9p/Kconfig
new file mode 100644
index 00000000000..bc6d4962288
--- /dev/null
+++ b/fs/9p/Kconfig
@@ -0,0 +1,8 @@
+config FS_9P
+	bool "9P filesystem support"
+	depends on NET_9P
+	help
+	  This provides support for the 9P2000.L filesystem.
+
+	  To use this filesystem, you also need to enable a 9P
+	  transport driver.
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
new file mode 100644
index 00000000000..c7f7553e8f4
--- /dev/null
+++ b/fs/9p/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2026, Kuan-Wei Chiu <visitorckw@gmail.com>
+
+obj-y += 9p.o
diff --git a/fs/Kconfig b/fs/Kconfig
index e0b0b901e1d..e4aa726ea35 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -26,4 +26,6 @@ source "fs/squashfs/Kconfig"
 
 source "fs/erofs/Kconfig"
 
+source "fs/9p/Kconfig"
+
 endmenu
diff --git a/fs/Makefile b/fs/Makefile
index ce5e74257a0..5aa34b39172 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_CMD_UBIFS) += ubifs/
 obj-$(CONFIG_CMD_ZFS) += zfs/
 obj-$(CONFIG_FS_SQUASHFS) += squashfs/
 obj-$(CONFIG_FS_EROFS) += erofs/
+obj-$(CONFIG_FS_9P) += 9p/
 endif
 obj-y += fs_internal.o
diff --git a/fs/fs.c b/fs/fs.c
index 8ea50a6c13c..0bb996dede5 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -32,6 +32,7 @@
 #include <squashfs.h>
 #include <erofs.h>
 #include <exfat.h>
+#include <9p.h>
 
 static struct blk_desc *fs_dev_desc;
 static int fs_dev_part;
@@ -398,6 +399,26 @@ static struct fstype_info fstypes[] = {
 		.mkdir = exfat_fs_mkdir,
 		.rename = exfat_fs_rename,
 	},
+#endif
+#if CONFIG_IS_ENABLED(FS_9P)
+	{
+		.fstype = FS_TYPE_9P,
+		.name = "9p",
+		.null_dev_desc_ok = true,
+		.probe = p9_fs_probe,
+		.close = fs_close_unsupported,
+		.ls = p9_fs_ls,
+		.exists = p9_fs_exists,
+		.size = p9_fs_size,
+		.read = p9_fs_read,
+		.write = fs_write_unsupported,
+		.uuid = fs_uuid_unsupported,
+		.opendir = fs_opendir_unsupported,
+		.unlink = fs_unlink_unsupported,
+		.mkdir = fs_mkdir_unsupported,
+		.ln = fs_ln_unsupported,
+		.rename = fs_rename_unsupported,
+	},
 #endif
 	{
 		.fstype = FS_TYPE_ANY,
@@ -464,6 +485,20 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
 	struct fstype_info *info;
 	int part, i;
 
+	/* Intercept 9p to bypass block device partition checks */
+	if (CONFIG_IS_ENABLED(FS_9P) && !strncmp(ifname, "9p", 2)) {
+		for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
+			if (info->fstype == FS_TYPE_9P) {
+				fs_dev_desc = NULL;
+				fs_type = FS_TYPE_9P;
+				if (info->probe(fs_dev_desc, NULL))
+					return -1;
+				return 0;
+			}
+		}
+		return -1;
+	}
+
 	part = part_get_info_by_dev_and_name_or_num(ifname, dev_part_str, &fs_dev_desc,
 						    &fs_partition, 1);
 	if (part < 0)
diff --git a/include/fs.h b/include/fs.h
index bec02117737..8afc81c0017 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -19,6 +19,7 @@ struct cmd_tbl;
 #define FS_TYPE_EROFS   7
 #define FS_TYPE_SEMIHOSTING 8
 #define FS_TYPE_EXFAT   9
+#define FS_TYPE_9P      10
 
 struct blk_desc;
 
-- 
2.55.0.rc2.803.g1fd1e6609c-goog


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/4] virtio: 9p: Add 9P transport driver
  2026-07-06 21:54 [PATCH 0/4] fs: Add 9P filesystem support over virtio Kuan-Wei Chiu
  2026-07-06 21:54 ` [PATCH 1/4] net: 9p: Add 9P2000 protocol support Kuan-Wei Chiu
  2026-07-06 21:54 ` [PATCH 2/4] fs: 9p: Add 9P filesystem support Kuan-Wei Chiu
@ 2026-07-06 21:54 ` Kuan-Wei Chiu
  2026-07-06 21:54 ` [PATCH 4/4] MAINTAINERS: Add entry for 9PFS Kuan-Wei Chiu
  3 siblings, 0 replies; 5+ messages in thread
From: Kuan-Wei Chiu @ 2026-07-06 21:54 UTC (permalink / raw)
  To: trini, bmeng.cn, joe.hershberger, rfried.dev, jerome.forissier
  Cc: jserv, eleanor15x, marscheng, u-boot, Kuan-Wei Chiu

Add virtio transport driver for the 9P filesystem.

This driver binds to the virtio-9p device exposed by the hypervisor and
registers the transport operations with the 9P client framework. It
implements the transmit and receive routines.

Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
---
 drivers/virtio/Kconfig         |  7 ++++
 drivers/virtio/Makefile        |  1 +
 drivers/virtio/virtio-uclass.c |  1 +
 drivers/virtio/virtio_9p.c     | 75 ++++++++++++++++++++++++++++++++++
 include/virtio.h               |  4 +-
 5 files changed, 87 insertions(+), 1 deletion(-)
 create mode 100644 drivers/virtio/virtio_9p.c

diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 512ac376f18..55b44428026 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -77,4 +77,11 @@ config VIRTIO_RNG
 	help
 	  This is the virtual random number generator driver. It can be used
 	  with QEMU based targets.
+
+config VIRTIO_9P
+	bool "virtio 9P transport driver"
+	depends on VIRTIO && NET_9P
+	help
+	  This enables the 9P transport driver over virtio.
+	  It can be used with QEMU based targets.
 endmenu
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 4c63a6c6904..6e7bcfc8eaa 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_VIRTIO_SANDBOX) += virtio_sandbox.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
 obj-$(CONFIG_VIRTIO_RNG) += virtio_rng.o
+obj-$(CONFIG_VIRTIO_9P) += virtio_9p.o
diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c
index a871a1439d4..c163b2fd7d5 100644
--- a/drivers/virtio/virtio-uclass.c
+++ b/drivers/virtio/virtio-uclass.c
@@ -30,6 +30,7 @@ static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = {
 	[VIRTIO_ID_NET]		= VIRTIO_NET_DRV_NAME,
 	[VIRTIO_ID_BLOCK]	= VIRTIO_BLK_DRV_NAME,
 	[VIRTIO_ID_RNG]		= VIRTIO_RNG_DRV_NAME,
+	[VIRTIO_ID_9P]		= VIRTIO_9P_DRV_NAME,
 };
 
 int virtio_get_config(struct udevice *vdev, unsigned int offset,
diff --git a/drivers/virtio/virtio_9p.c b/drivers/virtio/virtio_9p.c
new file mode 100644
index 00000000000..e37c9c37c4b
--- /dev/null
+++ b/drivers/virtio/virtio_9p.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026, Kuan-Wei Chiu <visitorckw@gmail.com>
+ */
+
+#include <9p.h>
+#include <dm.h>
+#include <cpu_func.h>
+#include <virtio.h>
+#include <virtio_ring.h>
+#include <virtio_types.h>
+#include <asm/cache.h>
+
+struct virtio_9p_priv {
+	struct virtqueue *vq;
+	struct p9_client client;
+};
+
+static int virtio_9p_request(struct p9_client *c, void *tx, int tx_len, void *rx, int rx_len)
+{
+	struct virtio_9p_priv *priv = c->priv;
+	struct virtio_sg sg[2];
+	struct virtio_sg *sgs[2];
+	int len;
+
+	sg[0].addr = tx;
+	sg[0].length = tx_len;
+	sgs[0] = &sg[0];
+
+	sg[1].addr = rx;
+	sg[1].length = rx_len;
+	sgs[1] = &sg[1];
+
+	flush_dcache_range((ulong)tx, ALIGN((ulong)tx + tx_len, ARCH_DMA_MINALIGN));
+	flush_dcache_range((ulong)rx, ALIGN((ulong)rx + rx_len, ARCH_DMA_MINALIGN));
+
+	if (virtqueue_add(priv->vq, sgs, 1, 1))
+		return -EIO;
+
+	virtqueue_kick(priv->vq);
+
+	while (!virtqueue_get_buf(priv->vq, &len))
+		;
+
+	invalidate_dcache_range((ulong)rx, ALIGN((ulong)rx + rx_len, ARCH_DMA_MINALIGN));
+
+	return 0;
+}
+
+static const struct p9_trans_ops virtio_9p_ops = {
+	.request = virtio_9p_request,
+};
+
+static int virtio_9p_probe(struct udevice *dev)
+{
+	struct virtio_9p_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = virtio_find_vqs(dev, 1, &priv->vq);
+	if (ret)
+		return ret;
+
+	priv->client.ops = &virtio_9p_ops;
+	priv->client.priv = priv;
+	p9_register_client(&priv->client);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(virtio_9p) = {
+	.name       = VIRTIO_9P_DRV_NAME,
+	.id         = UCLASS_MISC,
+	.probe      = virtio_9p_probe,
+	.priv_auto  = sizeof(struct virtio_9p_priv),
+};
diff --git a/include/virtio.h b/include/virtio.h
index 3edf023463d..7b3f466220f 100644
--- a/include/virtio.h
+++ b/include/virtio.h
@@ -31,11 +31,13 @@
 #define VIRTIO_ID_NET		1 /* virtio net */
 #define VIRTIO_ID_BLOCK		2 /* virtio block */
 #define VIRTIO_ID_RNG		4 /* virtio rng */
-#define VIRTIO_ID_MAX_NUM	5
+#define VIRTIO_ID_9P		9 /* virtio 9p */
+#define VIRTIO_ID_MAX_NUM	10
 
 #define VIRTIO_NET_DRV_NAME	"virtio-net"
 #define VIRTIO_BLK_DRV_NAME	"virtio-blk"
 #define VIRTIO_RNG_DRV_NAME	"virtio-rng"
+#define VIRTIO_9P_DRV_NAME	"virtio-9p"
 
 /* Status byte for guest to report progress, and synchronize features */
 
-- 
2.55.0.rc2.803.g1fd1e6609c-goog


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/4] MAINTAINERS: Add entry for 9PFS
  2026-07-06 21:54 [PATCH 0/4] fs: Add 9P filesystem support over virtio Kuan-Wei Chiu
                   ` (2 preceding siblings ...)
  2026-07-06 21:54 ` [PATCH 3/4] virtio: 9p: Add 9P transport driver Kuan-Wei Chiu
@ 2026-07-06 21:54 ` Kuan-Wei Chiu
  3 siblings, 0 replies; 5+ messages in thread
From: Kuan-Wei Chiu @ 2026-07-06 21:54 UTC (permalink / raw)
  To: trini, bmeng.cn, joe.hershberger, rfried.dev, jerome.forissier
  Cc: jserv, eleanor15x, marscheng, u-boot, Kuan-Wei Chiu

Add maintainer entry for the newly introduced 9P filesystem
subsystem, including the protocol core, vfs integration, and
virtio transport driver.

Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index f4eb2c13a43..2deb6b37420 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -50,6 +50,14 @@ so much easier [Ed]
 Maintainers List (try to look for most precise areas first)
 
 		-----------------------------------
+9PFS
+M:	Kuan-Wei Chiu <visitorckw@gmail.com>
+S:	Maintained
+F:	drivers/virtio/virtio_9p.c
+F:	fs/9p/
+F:	include/9p.h
+F:	net/9p/
+
 ACPI
 M:	Simon Glass <sjg@chromium.org>
 S:	Maintained
-- 
2.55.0.rc2.803.g1fd1e6609c-goog


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-07-06 21:55 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06 21:54 [PATCH 0/4] fs: Add 9P filesystem support over virtio Kuan-Wei Chiu
2026-07-06 21:54 ` [PATCH 1/4] net: 9p: Add 9P2000 protocol support Kuan-Wei Chiu
2026-07-06 21:54 ` [PATCH 2/4] fs: 9p: Add 9P filesystem support Kuan-Wei Chiu
2026-07-06 21:54 ` [PATCH 3/4] virtio: 9p: Add 9P transport driver Kuan-Wei Chiu
2026-07-06 21:54 ` [PATCH 4/4] MAINTAINERS: Add entry for 9PFS Kuan-Wei Chiu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.