/** @file | |
Type and macro definitions specific to the Virtio Filesystem device. | |
At the time of this writing, the latest released Virtio specification (v1.1) | |
does not include the virtio-fs device. The development version of the | |
specification defines it however; see the latest version at | |
<https://github.com/oasis-tcs/virtio-spec/blob/87fa6b5d8155/virtio-fs.tex>. | |
This header file is minimal, and only defines the types and macros that are | |
necessary for the OvmfPkg implementation. | |
Copyright (C) 2020, Red Hat, Inc. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#ifndef VIRTIO_FS_H_ | |
#define VIRTIO_FS_H_ | |
#include <IndustryStandard/Virtio.h> | |
// | |
// Lowest numbered queue for sending normal priority requests. | |
// | |
#define VIRTIO_FS_REQUEST_QUEUE 1 | |
// | |
// Number of bytes in the "VIRTIO_FS_CONFIG.Tag" field. | |
// | |
#define VIRTIO_FS_TAG_BYTES 36 | |
// | |
// Device configuration layout. | |
// | |
#pragma pack (1) | |
typedef struct { | |
// | |
// The Tag field can be considered the filesystem label, or a mount point | |
// hint. It is UTF-8 encoded, and padded to full size with NUL bytes. If the | |
// encoded bytes take up the entire Tag field, then there is no NUL | |
// terminator. | |
// | |
UINT8 Tag[VIRTIO_FS_TAG_BYTES]; | |
// | |
// The total number of request virtqueues exposed by the device (i.e., | |
// excluding the "hiprio" queue). | |
// | |
UINT32 NumReqQueues; | |
} VIRTIO_FS_CONFIG; | |
#pragma pack () | |
// | |
// FUSE-related definitions follow. | |
// | |
// From virtio-v1.1-cs01-87fa6b5d8155, 5.11 File System Device: "[...] The | |
// driver acts as the FUSE client mounting the file system. The virtio file | |
// system device provides the mechanism for transporting FUSE requests [...]" | |
// | |
// Unfortunately, the documentation of the FUSE wire protocol is lacking. The | |
// Virtio spec (as of this writing) simply defers to | |
// "include/uapi/linux/fuse.h" in the Linux kernel source -- see the reference | |
// in virtio spec file "introduction.tex", at commit 87fa6b5d8155. | |
// | |
// Of course, "include/uapi/linux/fuse.h" is a moving target (the virtio spec | |
// does not specify a particular FUSE interface version). The OvmfPkg code | |
// targets version 7.31, because that's the lowest version that the QEMU | |
// virtio-fs daemon supports at this time -- see QEMU commit 72c42e2d6551 | |
// ("virtiofsd: Trim out compatibility code", 2020-01-23). | |
// | |
// Correspondingly, Linux's "include/uapi/linux/fuse.h" is consulted as checked | |
// out at commit (c6ff213fe5b8^) = d78092e4937d ("fuse: fix page dereference | |
// after free", 2020-09-18); that is, right before commit c6ff213fe5b8 ("fuse: | |
// add submount support to <uapi/linux/fuse.h>", 2020-09-18) introduces FUSE | |
// interface version 7.32. | |
// | |
#define VIRTIO_FS_FUSE_MAJOR 7 | |
#define VIRTIO_FS_FUSE_MINOR 31 | |
// | |
// The inode number of the root directory. | |
// | |
#define VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID 1 | |
// | |
// Distinguished errno values. | |
// | |
#define VIRTIO_FS_FUSE_ERRNO_ENOENT (-2) | |
// | |
// File mode bitmasks. | |
// | |
#define VIRTIO_FS_FUSE_MODE_TYPE_MASK 0170000u | |
#define VIRTIO_FS_FUSE_MODE_TYPE_REG 0100000u | |
#define VIRTIO_FS_FUSE_MODE_TYPE_DIR 0040000u | |
#define VIRTIO_FS_FUSE_MODE_PERM_RWXU 0000700u | |
#define VIRTIO_FS_FUSE_MODE_PERM_RUSR 0000400u | |
#define VIRTIO_FS_FUSE_MODE_PERM_WUSR 0000200u | |
#define VIRTIO_FS_FUSE_MODE_PERM_XUSR 0000100u | |
#define VIRTIO_FS_FUSE_MODE_PERM_RWXG 0000070u | |
#define VIRTIO_FS_FUSE_MODE_PERM_RGRP 0000040u | |
#define VIRTIO_FS_FUSE_MODE_PERM_WGRP 0000020u | |
#define VIRTIO_FS_FUSE_MODE_PERM_XGRP 0000010u | |
#define VIRTIO_FS_FUSE_MODE_PERM_RWXO 0000007u | |
#define VIRTIO_FS_FUSE_MODE_PERM_ROTH 0000004u | |
#define VIRTIO_FS_FUSE_MODE_PERM_WOTH 0000002u | |
#define VIRTIO_FS_FUSE_MODE_PERM_XOTH 0000001u | |
// | |
// Flags for VirtioFsFuseOpSetAttr, in the VIRTIO_FS_FUSE_SETATTR_REQUEST.Valid | |
// field. | |
// | |
#define VIRTIO_FS_FUSE_SETATTR_REQ_F_MODE BIT0 | |
#define VIRTIO_FS_FUSE_SETATTR_REQ_F_SIZE BIT3 | |
#define VIRTIO_FS_FUSE_SETATTR_REQ_F_ATIME BIT4 | |
#define VIRTIO_FS_FUSE_SETATTR_REQ_F_MTIME BIT5 | |
// | |
// Flags for VirtioFsFuseOpOpen. | |
// | |
#define VIRTIO_FS_FUSE_OPEN_REQ_F_RDONLY 0 | |
#define VIRTIO_FS_FUSE_OPEN_REQ_F_RDWR 2 | |
// | |
// Flags for VirtioFsFuseOpInit. | |
// | |
#define VIRTIO_FS_FUSE_INIT_REQ_F_DO_READDIRPLUS BIT13 | |
/** | |
Macro for calculating the size of a directory stream entry. | |
The macro may evaluate Namelen multiple times. | |
The macro evaluates to a UINTN value that is safe to cast to UINT32. | |
@param[in] Namelen The size of the filename byte array that follows | |
VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE in the directory | |
stream, as reported by | |
VIRTIO_FS_FUSE_STATFS_RESPONSE.Namelen or | |
VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE.Namelen. The filename | |
byte array is not NUL-terminated. | |
@retval 0 Namelen was zero or greater than SIZE_4KB. | |
@return The number of bytes in the directory entry, including the | |
VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE header. | |
**/ | |
#define VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE_SIZE(Namelen) \ | |
((Namelen) == 0 || (Namelen) > SIZE_4KB ? \ | |
(UINTN)0 : \ | |
ALIGN_VALUE ( \ | |
sizeof (VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE) + (UINTN)(Namelen), \ | |
sizeof (UINT64) \ | |
) \ | |
) | |
// | |
// Flags for VirtioFsFuseOpRename2. | |
// | |
#define VIRTIO_FS_FUSE_RENAME2_REQ_F_NOREPLACE BIT0 | |
// | |
// FUSE operation codes. | |
// | |
typedef enum { | |
VirtioFsFuseOpLookup = 1, | |
VirtioFsFuseOpForget = 2, | |
VirtioFsFuseOpGetAttr = 3, | |
VirtioFsFuseOpSetAttr = 4, | |
VirtioFsFuseOpMkDir = 9, | |
VirtioFsFuseOpUnlink = 10, | |
VirtioFsFuseOpRmDir = 11, | |
VirtioFsFuseOpOpen = 14, | |
VirtioFsFuseOpRead = 15, | |
VirtioFsFuseOpWrite = 16, | |
VirtioFsFuseOpStatFs = 17, | |
VirtioFsFuseOpRelease = 18, | |
VirtioFsFuseOpFsync = 20, | |
VirtioFsFuseOpFlush = 25, | |
VirtioFsFuseOpInit = 26, | |
VirtioFsFuseOpOpenDir = 27, | |
VirtioFsFuseOpReleaseDir = 29, | |
VirtioFsFuseOpFsyncDir = 30, | |
VirtioFsFuseOpCreate = 35, | |
VirtioFsFuseOpReadDirPlus = 44, | |
VirtioFsFuseOpRename2 = 45, | |
} VIRTIO_FS_FUSE_OPCODE; | |
#pragma pack (1) | |
// | |
// Request-response headers common to all request types. | |
// | |
typedef struct { | |
UINT32 Len; | |
UINT32 Opcode; | |
UINT64 Unique; | |
UINT64 NodeId; | |
UINT32 Uid; | |
UINT32 Gid; | |
UINT32 Pid; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_REQUEST; | |
typedef struct { | |
UINT32 Len; | |
INT32 Error; | |
UINT64 Unique; | |
} VIRTIO_FS_FUSE_RESPONSE; | |
// | |
// Structure with which the Virtio Filesystem device reports a NodeId to the | |
// FUSE client (i.e., to the Virtio Filesystem driver). This structure is a | |
// part of the response headers for operations that inform the FUSE client of | |
// an inode. | |
// | |
typedef struct { | |
UINT64 NodeId; | |
UINT64 Generation; | |
UINT64 EntryValid; | |
UINT64 AttrValid; | |
UINT32 EntryValidNsec; | |
UINT32 AttrValidNsec; | |
} VIRTIO_FS_FUSE_NODE_RESPONSE; | |
// | |
// Structure describing the host-side attributes of an inode. This structure is | |
// a part of the response headers for operations that inform the FUSE client of | |
// an inode. | |
// | |
typedef struct { | |
UINT64 Ino; | |
UINT64 Size; | |
UINT64 Blocks; | |
UINT64 Atime; | |
UINT64 Mtime; | |
UINT64 Ctime; | |
UINT32 AtimeNsec; | |
UINT32 MtimeNsec; | |
UINT32 CtimeNsec; | |
UINT32 Mode; | |
UINT32 Nlink; | |
UINT32 Uid; | |
UINT32 Gid; | |
UINT32 Rdev; | |
UINT32 Blksize; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE; | |
// | |
// Header for VirtioFsFuseOpForget. | |
// | |
typedef struct { | |
UINT64 NumberOfLookups; | |
} VIRTIO_FS_FUSE_FORGET_REQUEST; | |
// | |
// Headers for VirtioFsFuseOpGetAttr (VIRTIO_FS_FUSE_GETATTR_RESPONSE is also | |
// for VirtioFsFuseOpSetAttr). | |
// | |
typedef struct { | |
UINT32 GetAttrFlags; | |
UINT32 Dummy; | |
UINT64 FileHandle; | |
} VIRTIO_FS_FUSE_GETATTR_REQUEST; | |
typedef struct { | |
UINT64 AttrValid; | |
UINT32 AttrValidNsec; | |
UINT32 Dummy; | |
} VIRTIO_FS_FUSE_GETATTR_RESPONSE; | |
// | |
// Header for VirtioFsFuseOpSetAttr. | |
// | |
typedef struct { | |
UINT32 Valid; | |
UINT32 Padding; | |
UINT64 FileHandle; | |
UINT64 Size; | |
UINT64 LockOwner; | |
UINT64 Atime; | |
UINT64 Mtime; | |
UINT64 Ctime; | |
UINT32 AtimeNsec; | |
UINT32 MtimeNsec; | |
UINT32 CtimeNsec; | |
UINT32 Mode; | |
UINT32 Unused4; | |
UINT32 Uid; | |
UINT32 Gid; | |
UINT32 Unused5; | |
} VIRTIO_FS_FUSE_SETATTR_REQUEST; | |
// | |
// Header for VirtioFsFuseOpMkDir. | |
// | |
typedef struct { | |
UINT32 Mode; | |
UINT32 Umask; | |
} VIRTIO_FS_FUSE_MKDIR_REQUEST; | |
// | |
// Headers for VirtioFsFuseOpOpen and VirtioFsFuseOpOpenDir. | |
// | |
typedef struct { | |
UINT32 Flags; | |
UINT32 Unused; | |
} VIRTIO_FS_FUSE_OPEN_REQUEST; | |
typedef struct { | |
UINT64 FileHandle; | |
UINT32 OpenFlags; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_OPEN_RESPONSE; | |
// | |
// Header for VirtioFsFuseOpRead and VirtioFsFuseOpReadDirPlus. | |
// | |
typedef struct { | |
UINT64 FileHandle; | |
UINT64 Offset; | |
UINT32 Size; | |
UINT32 ReadFlags; | |
UINT64 LockOwner; | |
UINT32 Flags; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_READ_REQUEST; | |
// | |
// Headers for VirtioFsFuseOpWrite. | |
// | |
typedef struct { | |
UINT64 FileHandle; | |
UINT64 Offset; | |
UINT32 Size; | |
UINT32 WriteFlags; | |
UINT64 LockOwner; | |
UINT32 Flags; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_WRITE_REQUEST; | |
typedef struct { | |
UINT32 Size; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_WRITE_RESPONSE; | |
// | |
// Header for VirtioFsFuseOpStatFs. | |
// | |
typedef struct { | |
UINT64 Blocks; | |
UINT64 Bfree; | |
UINT64 Bavail; | |
UINT64 Files; | |
UINT64 Ffree; | |
UINT32 Bsize; | |
UINT32 Namelen; | |
UINT32 Frsize; | |
UINT32 Padding; | |
UINT32 Spare[6]; | |
} VIRTIO_FS_FUSE_STATFS_RESPONSE; | |
// | |
// Header for VirtioFsFuseOpRelease and VirtioFsFuseOpReleaseDir. | |
// | |
typedef struct { | |
UINT64 FileHandle; | |
UINT32 Flags; | |
UINT32 ReleaseFlags; | |
UINT64 LockOwner; | |
} VIRTIO_FS_FUSE_RELEASE_REQUEST; | |
// | |
// Header for VirtioFsFuseOpFsync and VirtioFsFuseOpFsyncDir. | |
// | |
typedef struct { | |
UINT64 FileHandle; | |
UINT32 FsyncFlags; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_FSYNC_REQUEST; | |
// | |
// Header for VirtioFsFuseOpFlush. | |
// | |
typedef struct { | |
UINT64 FileHandle; | |
UINT32 Unused; | |
UINT32 Padding; | |
UINT64 LockOwner; | |
} VIRTIO_FS_FUSE_FLUSH_REQUEST; | |
// | |
// Headers for VirtioFsFuseOpInit. | |
// | |
typedef struct { | |
UINT32 Major; | |
UINT32 Minor; | |
UINT32 MaxReadahead; | |
UINT32 Flags; | |
} VIRTIO_FS_FUSE_INIT_REQUEST; | |
typedef struct { | |
UINT32 Major; | |
UINT32 Minor; | |
UINT32 MaxReadahead; | |
UINT32 Flags; | |
UINT16 MaxBackground; | |
UINT16 CongestionThreshold; | |
UINT32 MaxWrite; | |
UINT32 TimeGran; | |
UINT16 MaxPages; | |
UINT16 MapAlignment; | |
UINT32 Unused[8]; | |
} VIRTIO_FS_FUSE_INIT_RESPONSE; | |
// | |
// Header for VirtioFsFuseOpCreate. | |
// | |
typedef struct { | |
UINT32 Flags; | |
UINT32 Mode; | |
UINT32 Umask; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_CREATE_REQUEST; | |
// | |
// Header for VirtioFsFuseOpReadDirPlus. | |
// | |
// Diverging from the rest of the headers, this structure embeds other | |
// structures. The reason is that a scatter list cannot be used to receive | |
// NodeResp and AttrResp separately; the record below is followed by a variable | |
// size filename byte array, and then such pairs are repeated a number of | |
// times. Thus, later header start offsets depend on earlier filename array | |
// sizes. | |
// | |
typedef struct { | |
VIRTIO_FS_FUSE_NODE_RESPONSE NodeResp; | |
VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE AttrResp; | |
UINT64 NodeId; | |
UINT64 CookieForNextEntry; | |
UINT32 Namelen; | |
UINT32 Type; | |
} VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE; | |
// | |
// Header for VirtioFsFuseOpRename2. | |
// | |
typedef struct { | |
UINT64 NewDir; | |
UINT32 Flags; | |
UINT32 Padding; | |
} VIRTIO_FS_FUSE_RENAME2_REQUEST; | |
#pragma pack () | |
#endif // VIRTIO_FS_H_ |