| /** @file | |
| Internal macro definitions, type definitions, and function declarations for | |
| the Virtio Filesystem device driver. | |
| Copyright (C) 2020, Red Hat, Inc. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #ifndef VIRTIO_FS_DXE_H_ | |
| #define VIRTIO_FS_DXE_H_ | |
| #include <Base.h> // SIGNATURE_64() | |
| #include <Guid/FileInfo.h> // EFI_FILE_INFO | |
| #include <IndustryStandard/VirtioFs.h> // VIRTIO_FS_TAG_BYTES | |
| #include <Library/DebugLib.h> // CR() | |
| #include <Protocol/SimpleFileSystem.h> // EFI_SIMPLE_FILE_SYSTEM_PROTOCOL | |
| #include <Protocol/VirtioDevice.h> // VIRTIO_DEVICE_PROTOCOL | |
| #include <Uefi/UefiBaseType.h> // EFI_EVENT | |
| #define VIRTIO_FS_SIG SIGNATURE_64 ('V', 'I', 'R', 'T', 'I', 'O', 'F', 'S') | |
| #define VIRTIO_FS_FILE_SIG \ | |
| SIGNATURE_64 ('V', 'I', 'O', 'F', 'S', 'F', 'I', 'L') | |
| // | |
| // The following limit applies to two kinds of pathnames. | |
| // | |
| // - The length of a POSIX-style, canonical pathname *at rest* never exceeds | |
| // VIRTIO_FS_MAX_PATHNAME_LENGTH. (Length is defined as the number of CHAR8 | |
| // elements in the canonical pathname, excluding the terminating '\0'.) This | |
| // is an invariant that is ensured for canonical pathnames created, and that | |
| // is assumed about canonical pathname inputs (which all originate | |
| // internally). | |
| // | |
| // - If the length of a UEFI-style pathname *argument*, originating directly or | |
| // indirectly from the EFI_FILE_PROTOCOL caller, exceeds | |
| // VIRTIO_FS_MAX_PATHNAME_LENGTH, then the argument is rejected. (Length is | |
| // defined as the number of CHAR16 elements in the UEFI-style pathname, | |
| // excluding the terminating L'\0'.) This is a restriction that's checked on | |
| // external UEFI-style pathname inputs. | |
| // | |
| // The limit is not expected to be a practical limitation; it's only supposed | |
| // to prevent attempts at overflowing size calculations. For both kinds of | |
| // pathnames, separate limits could be used; a common limit is used purely for | |
| // simplicity. | |
| // | |
| #define VIRTIO_FS_MAX_PATHNAME_LENGTH ((UINTN)65535) | |
| // | |
| // Maximum value for VIRTIO_FS_FILE.NumFileInfo. | |
| // | |
| #define VIRTIO_FS_FILE_MAX_FILE_INFO 256 | |
| // | |
| // Filesystem label encoded in UCS-2, transformed from the UTF-8 representation | |
| // in "VIRTIO_FS_CONFIG.Tag", and NUL-terminated. Only the printable ASCII code | |
| // points (U+0020 through U+007E) are supported. | |
| // | |
| typedef CHAR16 VIRTIO_FS_LABEL[VIRTIO_FS_TAG_BYTES + 1]; | |
| // | |
| // Main context structure, expressing an EFI_SIMPLE_FILE_SYSTEM_PROTOCOL | |
| // interface on top of the Virtio Filesystem device. | |
| // | |
| typedef struct { | |
| // | |
| // Parts of this structure are initialized / torn down in various functions | |
| // at various call depths. The table to the right should make it easier to | |
| // track them. | |
| // | |
| // field init function init depth | |
| // ----------- ------------------ ---------- | |
| UINT64 Signature; // DriverBindingStart 0 | |
| VIRTIO_DEVICE_PROTOCOL *Virtio; // DriverBindingStart 0 | |
| VIRTIO_FS_LABEL Label; // VirtioFsInit 1 | |
| UINT16 QueueSize; // VirtioFsInit 1 | |
| VRING Ring; // VirtioRingInit 2 | |
| VOID *RingMap; // VirtioRingMap 2 | |
| UINT64 RequestId; // FuseInitSession 1 | |
| UINT32 MaxWrite; // FuseInitSession 1 | |
| EFI_EVENT ExitBoot; // DriverBindingStart 0 | |
| LIST_ENTRY OpenFiles; // DriverBindingStart 0 | |
| EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs; // DriverBindingStart 0 | |
| } VIRTIO_FS; | |
| #define VIRTIO_FS_FROM_SIMPLE_FS(SimpleFsReference) \ | |
| CR (SimpleFsReference, VIRTIO_FS, SimpleFs, VIRTIO_FS_SIG); | |
| // | |
| // Structure for describing a contiguous buffer, potentially mapped for Virtio | |
| // transfer. | |
| // | |
| typedef struct { | |
| // | |
| // The following fields originate from the owner of the buffer. | |
| // | |
| VOID *Buffer; | |
| UINTN Size; | |
| // | |
| // All of the fields below, until the end of the structure, are | |
| // zero-initialized when the structure is initially validated. | |
| // | |
| // Mapped, MappedAddress and Mapping are updated when the buffer is mapped | |
| // for VirtioOperationBusMasterRead or VirtioOperationBusMasterWrite. They | |
| // are again updated when the buffer is unmapped. | |
| // | |
| BOOLEAN Mapped; | |
| EFI_PHYSICAL_ADDRESS MappedAddress; | |
| VOID *Mapping; | |
| // | |
| // Transferred is updated after VirtioFlush() returns successfully: | |
| // - for VirtioOperationBusMasterRead, Transferred is set to Size; | |
| // - for VirtioOperationBusMasterWrite, Transferred is calculated from the | |
| // UsedLen output parameter of VirtioFlush(). | |
| // | |
| UINTN Transferred; | |
| } VIRTIO_FS_IO_VECTOR; | |
| // | |
| // Structure for describing a list of IO Vectors. | |
| // | |
| typedef struct { | |
| // | |
| // The following fields originate from the owner of the buffers. | |
| // | |
| VIRTIO_FS_IO_VECTOR *IoVec; | |
| UINTN NumVec; | |
| // | |
| // TotalSize is calculated when the scatter-gather list is initially | |
| // validated. | |
| // | |
| UINT32 TotalSize; | |
| } VIRTIO_FS_SCATTER_GATHER_LIST; | |
| // | |
| // Private context structure that exposes EFI_FILE_PROTOCOL on top of an open | |
| // FUSE file reference. | |
| // | |
| typedef struct { | |
| UINT64 Signature; | |
| EFI_FILE_PROTOCOL SimpleFile; | |
| BOOLEAN IsDirectory; | |
| BOOLEAN IsOpenForWriting; | |
| VIRTIO_FS *OwnerFs; | |
| LIST_ENTRY OpenFilesEntry; | |
| CHAR8 *CanonicalPathname; | |
| UINT64 FilePosition; | |
| // | |
| // In the FUSE wire protocol, every request except FUSE_INIT refers to a | |
| // file, namely by the "VIRTIO_FS_FUSE_REQUEST.NodeId" field; that is, by the | |
| // inode number of the file. However, some of the FUSE requests that we need | |
| // for some of the EFI_FILE_PROTOCOL member functions require an open file | |
| // handle *in addition* to the inode number. For simplicity, whenever a | |
| // VIRTIO_FS_FILE object is created, primarily defined by its NodeId field, | |
| // we also *open* the referenced file at once, and save the returned file | |
| // handle in the FuseHandle field. This way, when an EFI_FILE_PROTOCOL member | |
| // function must send a FUSE request that needs the file handle *in addition* | |
| // to the inode number, FuseHandle will be at our disposal at once. | |
| // | |
| UINT64 NodeId; | |
| UINT64 FuseHandle; | |
| // | |
| // EFI_FILE_INFO objects cached for an in-flight directory read. | |
| // | |
| // For reading through a directory stream with tolerable performance, we have | |
| // to call FUSE_READDIRPLUS each time with such a buffer that can deliver a | |
| // good number of variable size records (VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE | |
| // elements). Every time we do that, we turn the whole bunch into an array of | |
| // EFI_FILE_INFOs immediately. EFI_FILE_PROTOCOL.Read() invocations (on | |
| // directories) will be served from this EFI_FILE_INFO cache. | |
| // | |
| UINT8 *FileInfoArray; | |
| UINTN SingleFileInfoSize; | |
| UINTN NumFileInfo; | |
| UINTN NextFileInfo; | |
| } VIRTIO_FS_FILE; | |
| #define VIRTIO_FS_FILE_FROM_SIMPLE_FILE(SimpleFileReference) \ | |
| CR (SimpleFileReference, VIRTIO_FS_FILE, SimpleFile, VIRTIO_FS_FILE_SIG); | |
| #define VIRTIO_FS_FILE_FROM_OPEN_FILES_ENTRY(OpenFilesEntryReference) \ | |
| CR (OpenFilesEntryReference, VIRTIO_FS_FILE, OpenFilesEntry, \ | |
| VIRTIO_FS_FILE_SIG); | |
| // | |
| // Initialization and helper routines for the Virtio Filesystem device. | |
| // | |
| EFI_STATUS | |
| VirtioFsInit ( | |
| IN OUT VIRTIO_FS *VirtioFs | |
| ); | |
| VOID | |
| VirtioFsUninit ( | |
| IN OUT VIRTIO_FS *VirtioFs | |
| ); | |
| VOID | |
| EFIAPI | |
| VirtioFsExitBoot ( | |
| IN EFI_EVENT ExitBootEvent, | |
| IN VOID *VirtioFsAsVoid | |
| ); | |
| EFI_STATUS | |
| VirtioFsSgListsValidate ( | |
| IN VIRTIO_FS *VirtioFs, | |
| IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList, | |
| IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL | |
| ); | |
| EFI_STATUS | |
| VirtioFsSgListsSubmit ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList, | |
| IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseNewRequest ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| OUT VIRTIO_FS_FUSE_REQUEST *Request, | |
| IN UINT32 RequestSize, | |
| IN VIRTIO_FS_FUSE_OPCODE Opcode, | |
| IN UINT64 NodeId | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseCheckResponse ( | |
| IN VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList, | |
| IN UINT64 RequestId, | |
| OUT UINTN *TailBufferFill | |
| ); | |
| EFI_STATUS | |
| VirtioFsErrnoToEfiStatus ( | |
| IN INT32 Errno | |
| ); | |
| EFI_STATUS | |
| VirtioFsAppendPath ( | |
| IN CHAR8 *LhsPath8, | |
| IN CHAR16 *RhsPath16, | |
| OUT CHAR8 **ResultPath8, | |
| OUT BOOLEAN *RootEscape | |
| ); | |
| EFI_STATUS | |
| VirtioFsLookupMostSpecificParentDir ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN OUT CHAR8 *Path, | |
| OUT UINT64 *DirNodeId, | |
| OUT CHAR8 **LastComponent | |
| ); | |
| EFI_STATUS | |
| VirtioFsGetBasename ( | |
| IN CHAR8 *Path, | |
| OUT CHAR16 *Basename OPTIONAL, | |
| IN OUT UINTN *BasenameSize | |
| ); | |
| EFI_STATUS | |
| VirtioFsComposeRenameDestination ( | |
| IN CHAR8 *LhsPath8, | |
| IN CHAR16 *RhsPath16, | |
| OUT CHAR8 **ResultPath8, | |
| OUT BOOLEAN *RootEscape | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseAttrToEfiFileInfo ( | |
| IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr, | |
| OUT EFI_FILE_INFO *FileInfo | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseDirentPlusToEfiFileInfo ( | |
| IN VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE *FuseDirent, | |
| IN OUT EFI_FILE_INFO *FileInfo | |
| ); | |
| VOID | |
| VirtioFsGetFuseSizeUpdate ( | |
| IN EFI_FILE_INFO *Info, | |
| IN EFI_FILE_INFO *NewInfo, | |
| OUT BOOLEAN *Update, | |
| OUT UINT64 *Size | |
| ); | |
| EFI_STATUS | |
| VirtioFsGetFuseTimeUpdates ( | |
| IN EFI_FILE_INFO *Info, | |
| IN EFI_FILE_INFO *NewInfo, | |
| OUT BOOLEAN *UpdateAtime, | |
| OUT BOOLEAN *UpdateMtime, | |
| OUT UINT64 *Atime, | |
| OUT UINT64 *Mtime | |
| ); | |
| EFI_STATUS | |
| VirtioFsGetFuseModeUpdate ( | |
| IN EFI_FILE_INFO *Info, | |
| IN EFI_FILE_INFO *NewInfo, | |
| OUT BOOLEAN *Update, | |
| OUT UINT32 *Mode | |
| ); | |
| // | |
| // Wrapper functions for FUSE commands (primitives). | |
| // | |
| EFI_STATUS | |
| VirtioFsFuseLookup ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 DirNodeId, | |
| IN CHAR8 *Name, | |
| OUT UINT64 *NodeId, | |
| OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseForget ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseGetAttr ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseSetAttr ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| IN UINT64 *Size OPTIONAL, | |
| IN UINT64 *Atime OPTIONAL, | |
| IN UINT64 *Mtime OPTIONAL, | |
| IN UINT32 *Mode OPTIONAL | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseMkDir ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 ParentNodeId, | |
| IN CHAR8 *Name, | |
| OUT UINT64 *NodeId | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseRemoveFileOrDir ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 ParentNodeId, | |
| IN CHAR8 *Name, | |
| IN BOOLEAN IsDir | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseOpen ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| IN BOOLEAN ReadWrite, | |
| OUT UINT64 *FuseHandle | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseReadFileOrDir ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| IN UINT64 FuseHandle, | |
| IN BOOLEAN IsDir, | |
| IN UINT64 Offset, | |
| IN OUT UINT32 *Size, | |
| OUT VOID *Data | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseWrite ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| IN UINT64 FuseHandle, | |
| IN UINT64 Offset, | |
| IN OUT UINT32 *Size, | |
| IN VOID *Data | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseStatFs ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| OUT VIRTIO_FS_FUSE_STATFS_RESPONSE *FilesysAttr | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseReleaseFileOrDir ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| IN UINT64 FuseHandle, | |
| IN BOOLEAN IsDir | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseFsyncFileOrDir ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| IN UINT64 FuseHandle, | |
| IN BOOLEAN IsDir | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseFlush ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| IN UINT64 FuseHandle | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseInitSession ( | |
| IN OUT VIRTIO_FS *VirtioFs | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseOpenDir ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 NodeId, | |
| OUT UINT64 *FuseHandle | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseOpenOrCreate ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 ParentNodeId, | |
| IN CHAR8 *Name, | |
| OUT UINT64 *NodeId, | |
| OUT UINT64 *FuseHandle | |
| ); | |
| EFI_STATUS | |
| VirtioFsFuseRename ( | |
| IN OUT VIRTIO_FS *VirtioFs, | |
| IN UINT64 OldParentNodeId, | |
| IN CHAR8 *OldName, | |
| IN UINT64 NewParentNodeId, | |
| IN CHAR8 *NewName | |
| ); | |
| // | |
| // EFI_SIMPLE_FILE_SYSTEM_PROTOCOL member functions for the Virtio Filesystem | |
| // driver. | |
| // | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsOpenVolume ( | |
| IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, | |
| OUT EFI_FILE_PROTOCOL **Root | |
| ); | |
| // | |
| // EFI_FILE_PROTOCOL member functions for the Virtio Filesystem driver. | |
| // | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileClose ( | |
| IN EFI_FILE_PROTOCOL *This | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileDelete ( | |
| IN EFI_FILE_PROTOCOL *This | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileFlush ( | |
| IN EFI_FILE_PROTOCOL *This | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileGetInfo ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN EFI_GUID *InformationType, | |
| IN OUT UINTN *BufferSize, | |
| OUT VOID *Buffer | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileGetPosition ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| OUT UINT64 *Position | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileOpen ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| OUT EFI_FILE_PROTOCOL **NewHandle, | |
| IN CHAR16 *FileName, | |
| IN UINT64 OpenMode, | |
| IN UINT64 Attributes | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileRead ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN OUT UINTN *BufferSize, | |
| OUT VOID *Buffer | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileSetInfo ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN EFI_GUID *InformationType, | |
| IN UINTN BufferSize, | |
| IN VOID *Buffer | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileSetPosition ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN UINT64 Position | |
| ); | |
| EFI_STATUS | |
| EFIAPI | |
| VirtioFsSimpleFileWrite ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN OUT UINTN *BufferSize, | |
| IN VOID *Buffer | |
| ); | |
| #endif // VIRTIO_FS_DXE_H_ |