#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
#include <Protocol/VirtioDevice.h> // VIRTIO_DEVICE_PROTOCOL\r
#include <Uefi/UefiBaseType.h> // EFI_EVENT\r
\r
-#define VIRTIO_FS_SIG SIGNATURE_64 ('V', 'I', 'R', 'T', 'I', 'O', 'F', 'S')\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
//\r
// field init function init depth\r
// ----------- ------------------ ----------\r
- UINT64 Signature; // DriverBindingStart 0\r
- VIRTIO_DEVICE_PROTOCOL *Virtio; // DriverBindingStart 0\r
- VIRTIO_FS_LABEL Label; // VirtioFsInit 1\r
- UINT16 QueueSize; // VirtioFsInit 1\r
- VRING Ring; // VirtioRingInit 2\r
- VOID *RingMap; // VirtioRingMap 2\r
- UINT64 RequestId; // DriverBindingStart 0\r
- EFI_EVENT ExitBoot; // DriverBindingStart 0\r
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs; // DriverBindingStart 0\r
+ UINT64 Signature; // DriverBindingStart 0\r
+ VIRTIO_DEVICE_PROTOCOL *Virtio; // DriverBindingStart 0\r
+ VIRTIO_FS_LABEL Label; // VirtioFsInit 1\r
+ UINT16 QueueSize; // VirtioFsInit 1\r
+ VRING Ring; // VirtioRingInit 2\r
+ VOID *RingMap; // VirtioRingMap 2\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
#define VIRTIO_FS_FROM_SIMPLE_FS(SimpleFsReference) \\r
//\r
// The following fields originate from the owner of the buffer.\r
//\r
- VOID *Buffer;\r
- UINTN Size;\r
+ VOID *Buffer;\r
+ UINTN Size;\r
//\r
// All of the fields below, until the end of the structure, are\r
// zero-initialized when the structure is initially validated.\r
// for VirtioOperationBusMasterRead or VirtioOperationBusMasterWrite. They\r
// are again updated when the buffer is unmapped.\r
//\r
- BOOLEAN Mapped;\r
- EFI_PHYSICAL_ADDRESS MappedAddress;\r
- VOID *Mapping;\r
+ BOOLEAN Mapped;\r
+ EFI_PHYSICAL_ADDRESS MappedAddress;\r
+ VOID *Mapping;\r
//\r
// Transferred is updated after VirtioFlush() returns successfully:\r
// - for VirtioOperationBusMasterRead, Transferred is set to Size;\r
// - for VirtioOperationBusMasterWrite, Transferred is calculated from the\r
// UsedLen output parameter of VirtioFlush().\r
//\r
- UINTN Transferred;\r
+ UINTN Transferred;\r
} VIRTIO_FS_IO_VECTOR;\r
\r
//\r
//\r
// The following fields originate from the owner of the buffers.\r
//\r
- VIRTIO_FS_IO_VECTOR *IoVec;\r
- UINTN NumVec;\r
+ VIRTIO_FS_IO_VECTOR *IoVec;\r
+ UINTN NumVec;\r
//\r
// TotalSize is calculated when the scatter-gather list is initially\r
// validated.\r
//\r
- UINT32 TotalSize;\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
\r
EFI_STATUS\r
VirtioFsInit (\r
- IN OUT VIRTIO_FS *VirtioFs\r
+ IN OUT VIRTIO_FS *VirtioFs\r
);\r
\r
VOID\r
VirtioFsUninit (\r
- IN OUT VIRTIO_FS *VirtioFs\r
+ IN OUT VIRTIO_FS *VirtioFs\r
);\r
\r
VOID\r
EFIAPI\r
VirtioFsExitBoot (\r
- IN EFI_EVENT ExitBootEvent,\r
- IN VOID *VirtioFsAsVoid\r
+ IN EFI_EVENT ExitBootEvent,\r
+ IN VOID *VirtioFsAsVoid\r
);\r
\r
EFI_STATUS\r
VirtioFsSgListsValidate (\r
- IN VIRTIO_FS *VirtioFs,\r
- IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,\r
- IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL\r
+ IN VIRTIO_FS *VirtioFs,\r
+ IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,\r
+ IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL\r
);\r
\r
EFI_STATUS\r
VirtioFsSgListsSubmit (\r
- IN OUT VIRTIO_FS *VirtioFs,\r
- IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,\r
- IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,\r
+ IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL\r
);\r
\r
EFI_STATUS\r
VirtioFsFuseNewRequest (\r
IN OUT VIRTIO_FS *VirtioFs,\r
- OUT VIRTIO_FS_FUSE_REQUEST *Request,\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
EFI_STATUS\r
VirtioFsFuseCheckResponse (\r
- IN VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList,\r
- IN UINT64 RequestId,\r
- OUT UINTN *TailBufferFill\r
+ IN VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList,\r
+ IN UINT64 RequestId,\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_STATUS\r
EFIAPI\r
VirtioFsOpenVolume (\r
- IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
- OUT EFI_FILE_PROTOCOL **Root\r
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\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