--- /dev/null
+/**@file\r
+\r
+Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "SecMain.h"\r
+\r
+#define EMU_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'M', 'b', 'k')\r
+typedef struct {\r
+ UINTN Signature;\r
+\r
+ EMU_IO_THUNK_PROTOCOL *Thunk;\r
+\r
+ char *Filename;\r
+ UINTN ReadMode;\r
+ UINTN Mode;\r
+\r
+ int fd;\r
+\r
+ BOOLEAN RemovableMedia;\r
+ BOOLEAN WriteProtected;\r
+\r
+ UINT64 NumberOfBlocks;\r
+ UINT32 BlockSize;\r
+\r
+ EMU_BLOCK_IO_PROTOCOL EmuBlockIo;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+\r
+} EMU_BLOCK_IO_PRIVATE;\r
+\r
+#define EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \\r
+ CR(a, EMU_BLOCK_IO_PRIVATE, EmuBlockIo, EMU_BLOCK_IO_PRIVATE_SIGNATURE)\r
+\r
+\r
+\r
+EFI_STATUS\r
+EmuBlockIoReset (\r
+ IN EMU_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ );\r
+\r
+\r
+/*++\r
+\r
+This function extends the capability of SetFilePointer to accept 64 bit parameters\r
+\r
+**/\r
+EFI_STATUS\r
+SetFilePointer64 (\r
+ IN EMU_BLOCK_IO_PRIVATE *Private,\r
+ IN INT64 DistanceToMove,\r
+ OUT UINT64 *NewFilePointer,\r
+ IN INT32 MoveMethod\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ off_t res;\r
+ off_t offset = DistanceToMove;\r
+\r
+ Status = EFI_SUCCESS;\r
+ res = lseek (Private->fd, offset, (int)MoveMethod);\r
+ if (res == -1) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ } \r
+\r
+ if (NewFilePointer != NULL) {\r
+ *NewFilePointer = res;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EmuBlockIoOpenDevice (\r
+ IN EMU_BLOCK_IO_PRIVATE *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 FileSize;\r
+ struct statfs buf;\r
+\r
+\r
+ //\r
+ // If the device is already opened, close it\r
+ //\r
+ if (Private->fd >= 0) {\r
+ EmuBlockIoReset (&Private->EmuBlockIo, FALSE);\r
+ }\r
+\r
+ //\r
+ // Open the device\r
+ //\r
+ Private->fd = open (Private->Filename, Private->Mode, 0644);\r
+ if (Private->fd < 0) {\r
+ printf ("EmuOpenBlock: Could not open %s: %s\n", Private->Filename, strerror(errno));\r
+ Private->Media->MediaPresent = FALSE;\r
+ Status = EFI_NO_MEDIA;\r
+ goto Done;\r
+ }\r
+\r
+ if (!Private->Media->MediaPresent) {\r
+ //\r
+ // BugBug: try to emulate if a CD appears - notify drivers to check it out\r
+ //\r
+ Private->Media->MediaPresent = TRUE;\r
+ }\r
+\r
+ //\r
+ // get the size of the file\r
+ //\r
+ Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);\r
+ if (EFI_ERROR (Status)) {\r
+ printf ("EmuOpenBlock: Could not get filesize of %s\n", Private->Filename);\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+ \r
+ if (FileSize == 0) {\r
+ // lseek fails on a real device. ioctl calls are OS specific\r
+#if __APPLE__\r
+ {\r
+ UINT32 BlockSize;\r
+ \r
+ if (ioctl (Private->fd, DKIOCGETBLOCKSIZE, &BlockSize) == 0) {\r
+ Private->Media->BlockSize = BlockSize;\r
+ }\r
+ if (ioctl (Private->fd, DKIOCGETBLOCKCOUNT, &Private->NumberOfBlocks) == 0) {\r
+ if ((Private->NumberOfBlocks == 0) && (BlockSize == 0x800)) {\r
+ // A DVD is ~ 4.37 GB so make up a number\r
+ Private->Media->LastBlock = (0x100000000ULL/0x800) - 1;\r
+ } else {\r
+ Private->Media->LastBlock = Private->NumberOfBlocks - 1;\r
+ }\r
+ }\r
+ ioctl (Private->fd, DKIOCGETMAXBLOCKCOUNTWRITE, &Private->Media->OptimalTransferLengthGranularity); \r
+ }\r
+#else \r
+ {\r
+ size_t BlockSize;\r
+ UINT64 DiskSize;\r
+ \r
+ if (ioctl (Private->fd, BLKSSZGET, &BlockSize) == 0) {\r
+ Private->Media->BlockSize = BlockSize;\r
+ }\r
+ if (ioctl (Private->fd, BLKGETSIZE64, &DiskSize) == 0) {\r
+ Private->NumberOfBlocks = DivU64x32 (DiskSize, (UINT32)BlockSize);\r
+ Private->Media->LastBlock = Private->NumberOfBlocks - 1;\r
+ }\r
+ }\r
+#endif\r
+ \r
+ } else {\r
+ Private->Media->BlockSize = Private->BlockSize;\r
+ Private->NumberOfBlocks = DivU64x32 (FileSize, Private->Media->BlockSize);\r
+ Private->Media->LastBlock = Private->NumberOfBlocks - 1;\r
+ \r
+ if (fstatfs (Private->fd, &buf) == 0) {\r
+#if __APPLE__\r
+ Private->Media->OptimalTransferLengthGranularity = buf.f_iosize/buf.f_bsize;\r
+#else\r
+ Private->Media->OptimalTransferLengthGranularity = buf.f_bsize/buf.f_bsize;\r
+#endif\r
+ }\r
+ } \r
+\r
+ DEBUG ((EFI_D_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));\r
+ Status = EFI_SUCCESS;\r
+\r
+Done:\r
+ if (EFI_ERROR (Status)) {\r
+ if (Private->fd >= 0) {\r
+ EmuBlockIoReset (&Private->EmuBlockIo, FALSE);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EmuBlockIoCreateMapping (\r
+ IN EMU_BLOCK_IO_PROTOCOL *This,\r
+ IN EFI_BLOCK_IO_MEDIA *Media\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMU_BLOCK_IO_PRIVATE *Private;\r
+\r
+ Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ Private->Media = Media;\r
+ \r
+ Media->MediaId = 0;\r
+ Media->RemovableMedia = Private->RemovableMedia;\r
+ Media->MediaPresent = TRUE;\r
+ Media->LogicalPartition = FALSE;\r
+ Media->ReadOnly = Private->WriteProtected;\r
+ Media->WriteCaching = FALSE;\r
+ Media->IoAlign = 1;\r
+ Media->LastBlock = 0; // Filled in by OpenDevice\r
+ \r
+ // EFI_BLOCK_IO_PROTOCOL_REVISION2\r
+ Media->LowestAlignedLba = 0;\r
+ Media->LogicalBlocksPerPhysicalBlock = 0; \r
+ \r
+\r
+ // EFI_BLOCK_IO_PROTOCOL_REVISION3\r
+ Media->OptimalTransferLengthGranularity = 0;\r
+ \r
+ Status = EmuBlockIoOpenDevice (Private);\r
+\r
+ \r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EmuBlockIoError (\r
+ IN EMU_BLOCK_IO_PRIVATE *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN ReinstallBlockIoFlag;\r
+\r
+\r
+ switch (errno) {\r
+\r
+ case EAGAIN:\r
+ Status = EFI_NO_MEDIA;\r
+ Private->Media->ReadOnly = FALSE;\r
+ Private->Media->MediaPresent = FALSE;\r
+ ReinstallBlockIoFlag = FALSE;\r
+ break;\r
+\r
+ case EACCES:\r
+ Private->Media->ReadOnly = FALSE;\r
+ Private->Media->MediaPresent = TRUE;\r
+ Private->Media->MediaId += 1;\r
+ ReinstallBlockIoFlag = TRUE;\r
+ Status = EFI_MEDIA_CHANGED;\r
+ break;\r
+\r
+ case EROFS:\r
+ Private->Media->ReadOnly = TRUE;\r
+ ReinstallBlockIoFlag = FALSE;\r
+ Status = EFI_WRITE_PROTECTED;\r
+ break;\r
+\r
+ default:\r
+ ReinstallBlockIoFlag = FALSE;\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EmuBlockIoReadWriteCommon (\r
+ IN EMU_BLOCK_IO_PRIVATE *Private,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer,\r
+ IN CHAR8 *CallerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BlockSize;\r
+ UINT64 LastBlock;\r
+ INT64 DistanceToMove;\r
+ UINT64 DistanceMoved;\r
+\r
+ if (Private->fd < 0) {\r
+ Status = EmuBlockIoOpenDevice (Private);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if (!Private->Media->MediaPresent) {\r
+ DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));\r
+ return EFI_NO_MEDIA;\r
+ }\r
+\r
+ if (Private->Media->MediaId != MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if ((UINTN) Buffer % Private->Media->IoAlign != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Verify buffer size\r
+ //\r
+ BlockSize = Private->Media->BlockSize;\r
+ if (BufferSize == 0) {\r
+ DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ LastBlock = Lba + (BufferSize / BlockSize) - 1;\r
+ if (LastBlock > Private->Media->LastBlock) {\r
+ DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Seek to End of File\r
+ //\r
+ DistanceToMove = MultU64x32 (Lba, BlockSize);\r
+ Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));\r
+ return EmuBlockIoError (Private);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+ \r
+ This function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned.\r
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r
+ non-blocking I/O is being used, the Event associated with this request will\r
+ not be signaled.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId Id of the media, changes every time the media is \r
+ replaced.\r
+ @param[in] Lba The starting Logical Block Address to read from.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size. \r
+ @param[out] Buffer A pointer to the destination buffer for the data. The \r
+ caller is responsible for either having implicit or \r
+ explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The read request was queued if Token->Event is\r
+ not NULL.The data was read correctly from the\r
+ device if the Token->Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
+ intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
+ or the buffer is not on proper alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+**/\r
+EFI_STATUS\r
+EmuBlockIoReadBlocks (\r
+ IN EMU_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EMU_BLOCK_IO_PRIVATE *Private;\r
+ ssize_t len;\r
+\r
+ Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ len = read (Private->fd, Buffer, BufferSize);\r
+ if (len != BufferSize) {\r
+ DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));\r
+ Status = EmuBlockIoError (Private);\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // If we read then media is present.\r
+ //\r
+ Private->Media->MediaPresent = TRUE;\r
+ Status = EFI_SUCCESS;\r
+\r
+Done:\r
+ if (Token != NULL) {\r
+ if (Token->Event != NULL) {\r
+ // Caller is responcible for signaling EFI Event\r
+ Token->TransactionStatus = Status;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ This function writes the requested number of blocks to the device. All blocks\r
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r
+ being used, the Event associated with this request will not be signaled.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId The media ID that the write request is for.\r
+ @param[in] Lba The starting logical block address to be written. The\r
+ caller is responsible for writing to only legitimate\r
+ locations.\r
+ @param[in, out] Token A pointer to the token associated with the transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param[in] Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The write request was queued if Event is not NULL.\r
+ The data was written correctly to the device if\r
+ the Event is NULL.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
+ or the buffer is not on proper alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EmuBlockIoWriteBlocks (\r
+ IN EMU_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EMU_BLOCK_IO_PRIVATE *Private;\r
+ ssize_t len;\r
+ EFI_STATUS Status;\r
+\r
+\r
+ Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ len = write (Private->fd, Buffer, BufferSize);\r
+ if (len != BufferSize) {\r
+ DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));\r
+ Status = EmuBlockIoError (Private);\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // If the write succeeded, we are not write protected and media is present.\r
+ //\r
+ Private->Media->MediaPresent = TRUE;\r
+ Private->Media->ReadOnly = FALSE;\r
+ Status = EFI_SUCCESS;\r
+\r
+Done:\r
+ if (Token != NULL) {\r
+ if (Token->Event != NULL) {\r
+ // Caller is responcible for signaling EFI Event\r
+ Token->TransactionStatus = Status;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Flush the Block Device.\r
+ \r
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r
+ is returned and non-blocking I/O is being used, the Event associated with\r
+ this request will not be signaled. \r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in,out] Token A pointer to the token associated with the transaction\r
+\r
+ @retval EFI_SUCCESS The flush request was queued if Event is not NULL.\r
+ All outstanding data was written correctly to the\r
+ device if the Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back\r
+ the data.\r
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EmuBlockIoFlushBlocks (\r
+ IN EMU_BLOCK_IO_PROTOCOL *This,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EMU_BLOCK_IO_PRIVATE *Private;\r
+\r
+ Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Private->fd >= 0) {\r
+ fsync (Private->fd);\r
+#if __APPLE__\r
+ fcntl (Private->fd, F_FULLFSYNC);\r
+#endif\r
+ }\r
+ \r
+ \r
+ if (Token != NULL) {\r
+ if (Token->Event != NULL) {\r
+ // Caller is responcible for signaling EFI Event\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Reset the block device hardware.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Indicates that the driver may perform a more\r
+ exhausive verfication operation of the device\r
+ during reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EmuBlockIoReset (\r
+ IN EMU_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EMU_BLOCK_IO_PRIVATE *Private;\r
+\r
+ Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Private->fd >= 0) {\r
+ close (Private->fd);\r
+ Private->fd = -1;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+char *\r
+StdDupUnicodeToAscii (\r
+ IN CHAR16 *Str\r
+ )\r
+{\r
+ UINTN Size;\r
+ char *Ascii;\r
+ char *Ptr;\r
+ \r
+ Size = StrLen (Str) + 1;\r
+ Ascii = malloc (Size);\r
+ if (Ascii == NULL) {\r
+ return NULL;\r
+ }\r
+ \r
+ for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {\r
+ *Ptr = *Str;\r
+ }\r
+ *Ptr = 0;\r
+ \r
+ return Ascii;\r
+}\r
+\r
+\r
+EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {\r
+ GasketEmuBlockIoReset,\r
+ GasketEmuBlockIoReadBlocks,\r
+ GasketEmuBlockIoWriteBlocks,\r
+ GasketEmuBlockIoFlushBlocks,\r
+ GasketEmuBlockIoCreateMapping\r
+};\r
+\r
+EFI_STATUS\r
+EmuBlockIoThunkOpen (\r
+ IN EMU_IO_THUNK_PROTOCOL *This\r
+ )\r
+{\r
+ EMU_BLOCK_IO_PRIVATE *Private;\r
+ char *Str;\r
+ \r
+ if (This->Private != NULL) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+ \r
+ if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ Private = malloc (sizeof (EMU_BLOCK_IO_PRIVATE));\r
+ if (Private == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ \r
+ Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;\r
+ Private->Thunk = This;\r
+ CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));\r
+ Private->fd = -1;\r
+ Private->BlockSize = 512;\r
+ \r
+ Private->Filename = StdDupUnicodeToAscii (This->ConfigString);\r
+ if (Private->Filename == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ Str = strstr (Private->Filename, ":");\r
+ if (Str == NULL) {\r
+ Private->RemovableMedia = FALSE;\r
+ Private->WriteProtected = FALSE;\r
+ } else {\r
+ for (*Str++ = '\0'; *Str != 0; Str++) {\r
+ if (*Str == 'R' || *Str == 'F') {\r
+ Private->RemovableMedia = (BOOLEAN) (*Str == 'R');\r
+ }\r
+ if (*Str == 'O' || *Str == 'W') {\r
+ Private->WriteProtected = (BOOLEAN) (*Str == 'O');\r
+ }\r
+ if (*Str == ':') {\r
+ Private->BlockSize = strtol (++Str, NULL, 0);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ This->Interface = &Private->EmuBlockIo;\r
+ This->Private = Private;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EmuBlockIoThunkClose (\r
+ IN EMU_IO_THUNK_PROTOCOL *This\r
+ )\r
+{\r
+ EMU_BLOCK_IO_PRIVATE *Private;\r
+\r
+ if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ Private = This->Private;\r
+ \r
+ if (This->Private != NULL) {\r
+ if (Private->Filename != NULL) {\r
+ free (Private->Filename);\r
+ } \r
+ free (This->Private);\r
+ This->Private = NULL;\r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {\r
+ &gEmuBlockIoProtocolGuid,\r
+ NULL,\r
+ NULL,\r
+ 0,\r
+ GasketBlockIoThunkOpen,\r
+ GasketBlockIoThunkClose,\r
+ NULL\r
+};\r
+\r
+\r