#define VIRTIO_FS_DXE_H_\r
\r
#include <Base.h> // SIGNATURE_64()\r
+#include <Guid/FileInfo.h> // EFI_FILE_INFO\r
#include <IndustryStandard/VirtioFs.h> // VIRTIO_FS_TAG_BYTES\r
#include <Library/DebugLib.h> // CR()\r
#include <Protocol/SimpleFileSystem.h> // EFI_SIMPLE_FILE_SYSTEM_PROTOCOL\r
\r
#define VIRTIO_FS_SIG SIGNATURE_64 ('V', 'I', 'R', 'T', 'I', 'O', 'F', 'S')\r
\r
+#define VIRTIO_FS_FILE_SIG \\r
+ SIGNATURE_64 ('V', 'I', 'O', 'F', 'S', 'F', 'I', 'L')\r
+\r
+//\r
+// The following limit applies to two kinds of pathnames.\r
+//\r
+// - The length of a POSIX-style, canonical pathname *at rest* never exceeds\r
+// VIRTIO_FS_MAX_PATHNAME_LENGTH. (Length is defined as the number of CHAR8\r
+// elements in the canonical pathname, excluding the terminating '\0'.) This\r
+// is an invariant that is ensured for canonical pathnames created, and that\r
+// is assumed about canonical pathname inputs (which all originate\r
+// internally).\r
+//\r
+// - If the length of a UEFI-style pathname *argument*, originating directly or\r
+// indirectly from the EFI_FILE_PROTOCOL caller, exceeds\r
+// VIRTIO_FS_MAX_PATHNAME_LENGTH, then the argument is rejected. (Length is\r
+// defined as the number of CHAR16 elements in the UEFI-style pathname,\r
+// excluding the terminating L'\0'.) This is a restriction that's checked on\r
+// external UEFI-style pathname inputs.\r
+//\r
+// The limit is not expected to be a practical limitation; it's only supposed\r
+// to prevent attempts at overflowing size calculations. For both kinds of\r
+// pathnames, separate limits could be used; a common limit is used purely for\r
+// simplicity.\r
+//\r
+#define VIRTIO_FS_MAX_PATHNAME_LENGTH ((UINTN)65535)\r
+\r
+//\r
+// Maximum value for VIRTIO_FS_FILE.NumFileInfo.\r
+//\r
+#define VIRTIO_FS_FILE_MAX_FILE_INFO 256\r
+\r
//\r
// Filesystem label encoded in UCS-2, transformed from the UTF-8 representation\r
// in "VIRTIO_FS_CONFIG.Tag", and NUL-terminated. Only the printable ASCII code\r
UINT16 QueueSize; // VirtioFsInit 1\r
VRING Ring; // VirtioRingInit 2\r
VOID *RingMap; // VirtioRingMap 2\r
- UINT64 RequestId; // DriverBindingStart 0\r
+ UINT64 RequestId; // FuseInitSession 1\r
+ UINT32 MaxWrite; // FuseInitSession 1\r
EFI_EVENT ExitBoot; // DriverBindingStart 0\r
+ LIST_ENTRY OpenFiles; // DriverBindingStart 0\r
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs; // DriverBindingStart 0\r
} VIRTIO_FS;\r
\r
UINT32 TotalSize;\r
} VIRTIO_FS_SCATTER_GATHER_LIST;\r
\r
+//\r
+// Private context structure that exposes EFI_FILE_PROTOCOL on top of an open\r
+// FUSE file reference.\r
+//\r
+typedef struct {\r
+ UINT64 Signature;\r
+ EFI_FILE_PROTOCOL SimpleFile;\r
+ BOOLEAN IsDirectory;\r
+ BOOLEAN IsOpenForWriting;\r
+ VIRTIO_FS *OwnerFs;\r
+ LIST_ENTRY OpenFilesEntry;\r
+ CHAR8 *CanonicalPathname;\r
+ UINT64 FilePosition;\r
+ //\r
+ // In the FUSE wire protocol, every request except FUSE_INIT refers to a\r
+ // file, namely by the "VIRTIO_FS_FUSE_REQUEST.NodeId" field; that is, by the\r
+ // inode number of the file. However, some of the FUSE requests that we need\r
+ // for some of the EFI_FILE_PROTOCOL member functions require an open file\r
+ // handle *in addition* to the inode number. For simplicity, whenever a\r
+ // VIRTIO_FS_FILE object is created, primarily defined by its NodeId field,\r
+ // we also *open* the referenced file at once, and save the returned file\r
+ // handle in the FuseHandle field. This way, when an EFI_FILE_PROTOCOL member\r
+ // function must send a FUSE request that needs the file handle *in addition*\r
+ // to the inode number, FuseHandle will be at our disposal at once.\r
+ //\r
+ UINT64 NodeId;\r
+ UINT64 FuseHandle;\r
+ //\r
+ // EFI_FILE_INFO objects cached for an in-flight directory read.\r
+ //\r
+ // For reading through a directory stream with tolerable performance, we have\r
+ // to call FUSE_READDIRPLUS each time with such a buffer that can deliver a\r
+ // good number of variable size records (VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE\r
+ // elements). Every time we do that, we turn the whole bunch into an array of\r
+ // EFI_FILE_INFOs immediately. EFI_FILE_PROTOCOL.Read() invocations (on\r
+ // directories) will be served from this EFI_FILE_INFO cache.\r
+ //\r
+ UINT8 *FileInfoArray;\r
+ UINTN SingleFileInfoSize;\r
+ UINTN NumFileInfo;\r
+ UINTN NextFileInfo;\r
+} VIRTIO_FS_FILE;\r
+\r
+#define VIRTIO_FS_FILE_FROM_SIMPLE_FILE(SimpleFileReference) \\r
+ CR (SimpleFileReference, VIRTIO_FS_FILE, SimpleFile, VIRTIO_FS_FILE_SIG);\r
+\r
+#define VIRTIO_FS_FILE_FROM_OPEN_FILES_ENTRY(OpenFilesEntryReference) \\r
+ CR (OpenFilesEntryReference, VIRTIO_FS_FILE, OpenFilesEntry, \\r
+ VIRTIO_FS_FILE_SIG);\r
+\r
//\r
// Initialization and helper routines for the Virtio Filesystem device.\r
//\r
IN OUT VIRTIO_FS *VirtioFs,\r
OUT VIRTIO_FS_FUSE_REQUEST *Request,\r
IN UINT32 RequestSize,\r
- IN UINT32 Opcode,\r
+ IN VIRTIO_FS_FUSE_OPCODE Opcode,\r
IN UINT64 NodeId\r
);\r
\r
OUT UINTN *TailBufferFill\r
);\r
\r
+EFI_STATUS\r
+VirtioFsErrnoToEfiStatus (\r
+ IN INT32 Errno\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsAppendPath (\r
+ IN CHAR8 *LhsPath8,\r
+ IN CHAR16 *RhsPath16,\r
+ OUT CHAR8 **ResultPath8,\r
+ OUT BOOLEAN *RootEscape\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsLookupMostSpecificParentDir (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN OUT CHAR8 *Path,\r
+ OUT UINT64 *DirNodeId,\r
+ OUT CHAR8 **LastComponent\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsGetBasename (\r
+ IN CHAR8 *Path,\r
+ OUT CHAR16 *Basename OPTIONAL,\r
+ IN OUT UINTN *BasenameSize\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsComposeRenameDestination (\r
+ IN CHAR8 *LhsPath8,\r
+ IN CHAR16 *RhsPath16,\r
+ OUT CHAR8 **ResultPath8,\r
+ OUT BOOLEAN *RootEscape\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseAttrToEfiFileInfo (\r
+ IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr,\r
+ OUT EFI_FILE_INFO *FileInfo\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseDirentPlusToEfiFileInfo (\r
+ IN VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE *FuseDirent,\r
+ IN OUT EFI_FILE_INFO *FileInfo\r
+ );\r
+\r
+VOID\r
+VirtioFsGetFuseSizeUpdate (\r
+ IN EFI_FILE_INFO *Info,\r
+ IN EFI_FILE_INFO *NewInfo,\r
+ OUT BOOLEAN *Update,\r
+ OUT UINT64 *Size\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsGetFuseTimeUpdates (\r
+ IN EFI_FILE_INFO *Info,\r
+ IN EFI_FILE_INFO *NewInfo,\r
+ OUT BOOLEAN *UpdateAtime,\r
+ OUT BOOLEAN *UpdateMtime,\r
+ OUT UINT64 *Atime,\r
+ OUT UINT64 *Mtime\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsGetFuseModeUpdate (\r
+ IN EFI_FILE_INFO *Info,\r
+ IN EFI_FILE_INFO *NewInfo,\r
+ OUT BOOLEAN *Update,\r
+ OUT UINT32 *Mode\r
+ );\r
+\r
+//\r
+// Wrapper functions for FUSE commands (primitives).\r
+//\r
+\r
+EFI_STATUS\r
+VirtioFsFuseLookup (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 DirNodeId,\r
+ IN CHAR8 *Name,\r
+ OUT UINT64 *NodeId,\r
+ OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseForget (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseGetAttr (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseSetAttr (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ IN UINT64 *Size OPTIONAL,\r
+ IN UINT64 *Atime OPTIONAL,\r
+ IN UINT64 *Mtime OPTIONAL,\r
+ IN UINT32 *Mode OPTIONAL\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseMkDir (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 ParentNodeId,\r
+ IN CHAR8 *Name,\r
+ OUT UINT64 *NodeId\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseRemoveFileOrDir (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 ParentNodeId,\r
+ IN CHAR8 *Name,\r
+ IN BOOLEAN IsDir\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseOpen (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ IN BOOLEAN ReadWrite,\r
+ OUT UINT64 *FuseHandle\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseReadFileOrDir (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ IN UINT64 FuseHandle,\r
+ IN BOOLEAN IsDir,\r
+ IN UINT64 Offset,\r
+ IN OUT UINT32 *Size,\r
+ OUT VOID *Data\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseWrite (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ IN UINT64 FuseHandle,\r
+ IN UINT64 Offset,\r
+ IN OUT UINT32 *Size,\r
+ IN VOID *Data\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseStatFs (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ OUT VIRTIO_FS_FUSE_STATFS_RESPONSE *FilesysAttr\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseReleaseFileOrDir (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ IN UINT64 FuseHandle,\r
+ IN BOOLEAN IsDir\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseFsyncFileOrDir (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ IN UINT64 FuseHandle,\r
+ IN BOOLEAN IsDir\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseFlush (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ IN UINT64 FuseHandle\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseInitSession (\r
+ IN OUT VIRTIO_FS *VirtioFs\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseOpenDir (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 NodeId,\r
+ OUT UINT64 *FuseHandle\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseOpenOrCreate (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 ParentNodeId,\r
+ IN CHAR8 *Name,\r
+ OUT UINT64 *NodeId,\r
+ OUT UINT64 *FuseHandle\r
+ );\r
+\r
+EFI_STATUS\r
+VirtioFsFuseRename (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN UINT64 OldParentNodeId,\r
+ IN CHAR8 *OldName,\r
+ IN UINT64 NewParentNodeId,\r
+ IN CHAR8 *NewName\r
+ );\r
+\r
//\r
// EFI_SIMPLE_FILE_SYSTEM_PROTOCOL member functions for the Virtio Filesystem\r
// driver.\r
OUT EFI_FILE_PROTOCOL **Root\r
);\r
\r
+//\r
+// EFI_FILE_PROTOCOL member functions for the Virtio Filesystem driver.\r
+//\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileClose (\r
+ IN EFI_FILE_PROTOCOL *This\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileDelete (\r
+ IN EFI_FILE_PROTOCOL *This\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileFlush (\r
+ IN EFI_FILE_PROTOCOL *This\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileGetInfo (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN EFI_GUID *InformationType,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileGetPosition (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ OUT UINT64 *Position\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileOpen (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ OUT EFI_FILE_PROTOCOL **NewHandle,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileRead (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileSetInfo (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN EFI_GUID *InformationType,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileSetPosition (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN UINT64 Position\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VirtioFsSimpleFileWrite (\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
#endif // VIRTIO_FS_DXE_H_\r