\r
return Status;\r
}\r
+\r
+/**\r
+ Set up the fields of a new VIRTIO_FS_FUSE_REQUEST object.\r
+\r
+ The function may only be called after VirtioFsInit() returns successfully and\r
+ before VirtioFsUninit() is called.\r
+\r
+ @param[in,out] VirtioFs The Virtio Filesystem device that the request is\r
+ being prepared for. The "VirtioFs->RequestId" field\r
+ will be copied into "Request->Unique". On output (on\r
+ successful return), "VirtioFs->RequestId" will be\r
+ incremented.\r
+\r
+ @param[out] Request The VIRTIO_FS_FUSE_REQUEST object whose fields are to\r
+ be set.\r
+\r
+ @param[in] RequestSize The total size of the request, including\r
+ sizeof(VIRTIO_FS_FUSE_REQUEST).\r
+\r
+ @param[in] Opcode The VIRTIO_FS_FUSE_OPCODE that identifies the command\r
+ to send.\r
+\r
+ @param[in] NodeId The inode number of the file that the request refers\r
+ to. When Opcode is VirtioFsFuseOpInit, NodeId is\r
+ ignored by the Virtio Filesystem device.\r
+\r
+ @retval EFI_INVALID_PARAMETER RequestSize is smaller than\r
+ sizeof(VIRTIO_FS_FUSE_REQUEST).\r
+\r
+ @retval EFI_OUT_OF_RESOURCES "VirtioFs->RequestId" is MAX_UINT64, and can\r
+ be incremented no more.\r
+\r
+ @retval EFI_SUCCESS Request has been populated,\r
+ "VirtioFs->RequestId" has been incremented.\r
+**/\r
+EFI_STATUS\r
+VirtioFsFuseNewRequest (\r
+ IN OUT VIRTIO_FS *VirtioFs,\r
+ OUT VIRTIO_FS_FUSE_REQUEST *Request,\r
+ IN UINT32 RequestSize,\r
+ IN VIRTIO_FS_FUSE_OPCODE Opcode,\r
+ IN UINT64 NodeId\r
+ )\r
+{\r
+ if (RequestSize < sizeof *Request) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (VirtioFs->RequestId == MAX_UINT64) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Request->Len = RequestSize;\r
+ Request->Opcode = Opcode;\r
+ Request->Unique = VirtioFs->RequestId++;\r
+ Request->NodeId = NodeId;\r
+ Request->Uid = 0;\r
+ Request->Gid = 0;\r
+ Request->Pid = 1;\r
+ Request->Padding = 0;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check the common FUSE response format.\r
+\r
+ The first buffer in the response scatter-gather list is assumed a\r
+ VIRTIO_FS_FUSE_RESPONSE structure. Subsequent response buffers, if any, up to\r
+ and excluding the last one, are assumed fixed size. The last response buffer\r
+ may or may not be fixed size, as specified by the caller.\r
+\r
+ This function may only be called after VirtioFsSgListsSubmit() returns\r
+ successfully.\r
+\r
+ @param[in] ResponseSgList The scatter-gather list that describes the\r
+ response part of the exchange -- the buffers that\r
+ the Virtio Filesystem device filled in during the\r
+ virtio transfer.\r
+\r
+ @param[in] RequestId The request identifier to which the response is\r
+ expected to belong.\r
+\r
+ @param[out] TailBufferFill If NULL, then the last buffer in ResponseSgList\r
+ is considered fixed size. Otherwise, the last\r
+ buffer is considered variable size, and on\r
+ successful return, TailBufferFill reports the\r
+ number of bytes in the last buffer.\r
+\r
+ @retval EFI_INVALID_PARAMETER TailBufferFill is not NULL (i.e., the last\r
+ buffer is considered variable size), and\r
+ ResponseSgList->NumVec is 1.\r
+\r
+ @retval EFI_INVALID_PARAMETER The allocated size of the first buffer does\r
+ not match sizeof(VIRTIO_FS_FUSE_RESPONSE).\r
+\r
+ @retval EFI_PROTOCOL_ERROR The VIRTIO_FS_FUSE_RESPONSE structure in the\r
+ first buffer has not been fully populated.\r
+\r
+ @retval EFI_PROTOCOL_ERROR "VIRTIO_FS_FUSE_RESPONSE.Len" in the first\r
+ buffer does not equal the sum of the\r
+ individual buffer sizes (as populated).\r
+\r
+ @retval EFI_PROTOCOL_ERROR "VIRTIO_FS_FUSE_RESPONSE.Unique" in the first\r
+ buffer does not equal RequestId.\r
+\r
+ @retval EFI_PROTOCOL_ERROR "VIRTIO_FS_FUSE_RESPONSE.Error" in the first\r
+ buffer is zero, but a subsequent fixed size\r
+ buffer has not been fully populated.\r
+\r
+ @retval EFI_DEVICE_ERROR "VIRTIO_FS_FUSE_RESPONSE.Error" in the first\r
+ buffer is nonzero. The caller may investigate\r
+ "VIRTIO_FS_FUSE_RESPONSE.Error". Note that the\r
+ completeness of the subsequent fixed size\r
+ buffers is not verified in this case.\r
+\r
+ @retval EFI_SUCCESS Verification successful.\r
+**/\r
+EFI_STATUS\r
+VirtioFsFuseCheckResponse (\r
+ IN VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList,\r
+ IN UINT64 RequestId,\r
+ OUT UINTN *TailBufferFill\r
+ )\r
+{\r
+ UINTN NumFixedSizeVec;\r
+ VIRTIO_FS_FUSE_RESPONSE *CommonResp;\r
+ UINT32 TotalTransferred;\r
+ UINTN Idx;\r
+\r
+ //\r
+ // Ensured by VirtioFsSgListsValidate().\r
+ //\r
+ ASSERT (ResponseSgList->NumVec > 0);\r
+\r
+ if (TailBufferFill == NULL) {\r
+ //\r
+ // All buffers are considered fixed size.\r
+ //\r
+ NumFixedSizeVec = ResponseSgList->NumVec;\r
+ } else {\r
+ //\r
+ // If the last buffer is variable size, then we need that buffer to be\r
+ // different from the first buffer, which is considered a\r
+ // VIRTIO_FS_FUSE_RESPONSE (fixed size) structure.\r
+ //\r
+ if (ResponseSgList->NumVec == 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ NumFixedSizeVec = ResponseSgList->NumVec - 1;\r
+ }\r
+\r
+ //\r
+ // The first buffer is supposed to carry a (fully populated)\r
+ // VIRTIO_FS_FUSE_RESPONSE structure.\r
+ //\r
+ if (ResponseSgList->IoVec[0].Size != sizeof *CommonResp) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (ResponseSgList->IoVec[0].Transferred != ResponseSgList->IoVec[0].Size) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ //\r
+ // FUSE must report the same number of bytes, written by the Virtio\r
+ // Filesystem device, as the virtio transport does.\r
+ //\r
+ CommonResp = ResponseSgList->IoVec[0].Buffer;\r
+ TotalTransferred = 0;\r
+ for (Idx = 0; Idx < ResponseSgList->NumVec; Idx++) {\r
+ //\r
+ // Integer overflow and truncation are not possible, based on\r
+ // VirtioFsSgListsValidate() and VirtioFsSgListsSubmit().\r
+ //\r
+ TotalTransferred += (UINT32)ResponseSgList->IoVec[Idx].Transferred;\r
+ }\r
+ if (CommonResp->Len != TotalTransferred) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ //\r
+ // Enforce that FUSE match our request ID in the response.\r
+ //\r
+ if (CommonResp->Unique != RequestId) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+\r
+ //\r
+ // If there is an explicit error report, skip checking the transfer\r
+ // counts for the rest of the fixed size buffers.\r
+ //\r
+ if (CommonResp->Error != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // There was no error reported, so we require that the Virtio Filesystem\r
+ // device populate all fixed size buffers. We checked this for the very first\r
+ // buffer above; let's check the rest (if any).\r
+ //\r
+ ASSERT (NumFixedSizeVec >= 1);\r
+ for (Idx = 1; Idx < NumFixedSizeVec; Idx++) {\r
+ if (ResponseSgList->IoVec[Idx].Transferred !=\r
+ ResponseSgList->IoVec[Idx].Size) {\r
+ return EFI_PROTOCOL_ERROR;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If the last buffer is considered variable size, report its filled size.\r
+ //\r
+ if (TailBufferFill != NULL) {\r
+ *TailBufferFill = ResponseSgList->IoVec[NumFixedSizeVec].Transferred;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ An ad-hoc function for mapping FUSE (well, Linux) "errno" values to\r
+ EFI_STATUS.\r
+\r
+ @param[in] Errno The "VIRTIO_FS_FUSE_RESPONSE.Error" value, returned by the\r
+ Virtio Filesystem device. The value is expected to be\r
+ negative.\r
+\r
+ @return An EFI_STATUS error code that's deemed a passable\r
+ mapping for the Errno value.\r
+\r
+ @retval EFI_DEVICE_ERROR Fallback EFI_STATUS code for unrecognized Errno\r
+ values.\r
+**/\r
+EFI_STATUS\r
+VirtioFsErrnoToEfiStatus (\r
+ IN INT32 Errno\r
+ )\r
+{\r
+ switch (Errno) {\r
+ case -1: // EPERM Operation not permitted\r
+ return EFI_SECURITY_VIOLATION;\r
+\r
+ case -2: // ENOENT No such file or directory\r
+ case -3: // ESRCH No such process\r
+ case -6: // ENXIO No such device or address\r
+ case -10: // ECHILD No child processes\r
+ case -19: // ENODEV No such device\r
+ case -49: // EUNATCH Protocol driver not attached\r
+ case -65: // ENOPKG Package not installed\r
+ case -79: // ELIBACC Can not access a needed shared library\r
+ case -126: // ENOKEY Required key not available\r
+ return EFI_NOT_FOUND;\r
+\r
+ case -4: // EINTR Interrupted system call\r
+ case -11: // EAGAIN, EWOULDBLOCK Resource temporarily unavailable\r
+ case -16: // EBUSY Device or resource busy\r
+ case -26: // ETXTBSY Text file busy\r
+ case -35: // EDEADLK, EDEADLOCK Resource deadlock avoided\r
+ case -39: // ENOTEMPTY Directory not empty\r
+ case -42: // ENOMSG No message of desired type\r
+ case -61: // ENODATA No data available\r
+ case -85: // ERESTART Interrupted system call should be restarted\r
+ return EFI_NOT_READY;\r
+\r
+ case -5: // EIO Input/output error\r
+ case -45: // EL2NSYNC Level 2 not synchronized\r
+ case -46: // EL3HLT Level 3 halted\r
+ case -47: // EL3RST Level 3 reset\r
+ case -51: // EL2HLT Level 2 halted\r
+ case -121: // EREMOTEIO Remote I/O error\r
+ case -133: // EHWPOISON Memory page has hardware error\r
+ return EFI_DEVICE_ERROR;\r
+\r
+ case -7: // E2BIG Argument list too long\r
+ case -36: // ENAMETOOLONG File name too long\r
+ case -90: // EMSGSIZE Message too long\r
+ return EFI_BAD_BUFFER_SIZE;\r
+\r
+ case -8: // ENOEXEC Exec format error\r
+ case -15: // ENOTBLK Block device required\r
+ case -18: // EXDEV Invalid cross-device link\r
+ case -20: // ENOTDIR Not a directory\r
+ case -21: // EISDIR Is a directory\r
+ case -25: // ENOTTY Inappropriate ioctl for device\r
+ case -27: // EFBIG File too large\r
+ case -29: // ESPIPE Illegal seek\r
+ case -38: // ENOSYS Function not implemented\r
+ case -59: // EBFONT Bad font file format\r
+ case -60: // ENOSTR Device not a stream\r
+ case -83: // ELIBEXEC Cannot exec a shared library directly\r
+ case -88: // ENOTSOCK Socket operation on non-socket\r
+ case -91: // EPROTOTYPE Protocol wrong type for socket\r
+ case -92: // ENOPROTOOPT Protocol not available\r
+ case -93: // EPROTONOSUPPORT Protocol not supported\r
+ case -94: // ESOCKTNOSUPPORT Socket type not supported\r
+ case -95: // ENOTSUP, EOPNOTSUPP Operation not supported\r
+ case -96: // EPFNOSUPPORT Protocol family not supported\r
+ case -97: // EAFNOSUPPORT Address family not supported by protocol\r
+ case -99: // EADDRNOTAVAIL Cannot assign requested address\r
+ case -118: // ENOTNAM Not a XENIX named type file\r
+ case -120: // EISNAM Is a named type file\r
+ case -124: // EMEDIUMTYPE Wrong medium type\r
+ return EFI_UNSUPPORTED;\r
+\r
+ case -9: // EBADF Bad file descriptor\r
+ case -14: // EFAULT Bad address\r
+ case -44: // ECHRNG Channel number out of range\r
+ case -48: // ELNRNG Link number out of range\r
+ case -53: // EBADR Invalid request descriptor\r
+ case -56: // EBADRQC Invalid request code\r
+ case -57: // EBADSLT Invalid slot\r
+ case -76: // ENOTUNIQ Name not unique on network\r
+ case -84: // EILSEQ Invalid or incomplete multibyte or wide character\r
+ return EFI_NO_MAPPING;\r
+\r
+ case -12: // ENOMEM Cannot allocate memory\r
+ case -23: // ENFILE Too many open files in system\r
+ case -24: // EMFILE Too many open files\r
+ case -31: // EMLINK Too many links\r
+ case -37: // ENOLCK No locks available\r
+ case -40: // ELOOP Too many levels of symbolic links\r
+ case -50: // ENOCSI No CSI structure available\r
+ case -55: // ENOANO No anode\r
+ case -63: // ENOSR Out of streams resources\r
+ case -82: // ELIBMAX Attempting to link in too many shared libraries\r
+ case -87: // EUSERS Too many users\r
+ case -105: // ENOBUFS No buffer space available\r
+ case -109: // ETOOMANYREFS Too many references: cannot splice\r
+ case -119: // ENAVAIL No XENIX semaphores available\r
+ case -122: // EDQUOT Disk quota exceeded\r
+ return EFI_OUT_OF_RESOURCES;\r
+\r
+ case -13: // EACCES Permission denied\r
+ return EFI_ACCESS_DENIED;\r
+\r
+ case -17: // EEXIST File exists\r
+ case -98: // EADDRINUSE Address already in use\r
+ case -106: // EISCONN Transport endpoint is already connected\r
+ case -114: // EALREADY Operation already in progress\r
+ case -115: // EINPROGRESS Operation now in progress\r
+ return EFI_ALREADY_STARTED;\r
+\r
+ case -22: // EINVAL Invalid argument\r
+ case -33: // EDOM Numerical argument out of domain\r
+ return EFI_INVALID_PARAMETER;\r
+\r
+ case -28: // ENOSPC No space left on device\r
+ case -54: // EXFULL Exchange full\r
+ return EFI_VOLUME_FULL;\r
+\r
+ case -30: // EROFS Read-only file system\r
+ return EFI_WRITE_PROTECTED;\r
+\r
+ case -32: // EPIPE Broken pipe\r
+ case -43: // EIDRM Identifier removed\r
+ case -67: // ENOLINK Link has been severed\r
+ case -68: // EADV Advertise error\r
+ case -69: // ESRMNT Srmount error\r
+ case -70: // ECOMM Communication error on send\r
+ case -73: // EDOTDOT RFS specific error\r
+ case -78: // EREMCHG Remote address changed\r
+ case -86: // ESTRPIPE Streams pipe error\r
+ case -102: // ENETRESET Network dropped connection on reset\r
+ case -103: // ECONNABORTED Software caused connection abort\r
+ case -104: // ECONNRESET Connection reset by peer\r
+ case -116: // ESTALE Stale file handle\r
+ case -125: // ECANCELED Operation canceled\r
+ case -128: // EKEYREVOKED Key has been revoked\r
+ case -129: // EKEYREJECTED Key was rejected by service\r
+ case -130: // EOWNERDEAD Owner died\r
+ case -131: // ENOTRECOVERABLE State not recoverable\r
+ return EFI_ABORTED;\r
+\r
+ case -34: // ERANGE Numerical result out of range\r
+ case -75: // EOVERFLOW Value too large for defined data type\r
+ return EFI_BUFFER_TOO_SMALL;\r
+\r
+ case -52: // EBADE Invalid exchange\r
+ case -108: // ESHUTDOWN Cannot send after transport endpoint shutdown\r
+ case -111: // ECONNREFUSED Connection refused\r
+ return EFI_END_OF_FILE;\r
+\r
+ case -62: // ETIME Timer expired\r
+ case -110: // ETIMEDOUT Connection timed out\r
+ case -127: // EKEYEXPIRED Key has expired\r
+ return EFI_TIMEOUT;\r
+\r
+ case -64: // ENONET Machine is not on the network\r
+ case -66: // EREMOTE Object is remote\r
+ case -72: // EMULTIHOP Multihop attempted\r
+ case -100: // ENETDOWN Network is down\r
+ case -101: // ENETUNREACH Network is unreachable\r
+ case -112: // EHOSTDOWN Host is down\r
+ case -113: // EHOSTUNREACH No route to host\r
+ case -123: // ENOMEDIUM No medium found\r
+ case -132: // ERFKILL Operation not possible due to RF-kill\r
+ return EFI_NO_MEDIA;\r
+\r
+ case -71: // EPROTO Protocol error\r
+ return EFI_PROTOCOL_ERROR;\r
+\r
+ case -74: // EBADMSG Bad message\r
+ case -77: // EBADFD File descriptor in bad state\r
+ case -80: // ELIBBAD Accessing a corrupted shared library\r
+ case -81: // ELIBSCN .lib section in a.out corrupted\r
+ case -117: // EUCLEAN Structure needs cleaning\r
+ return EFI_VOLUME_CORRUPTED;\r
+\r
+ case -89: // EDESTADDRREQ Destination address required\r
+ case -107: // ENOTCONN Transport endpoint is not connected\r
+ return EFI_NOT_STARTED;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return EFI_DEVICE_ERROR;\r
+}\r