1 /**@file
2 
3 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 **/
13 
14 #include "Host.h"
15 
16 #define EMU_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'M', 'b', 'k')
17 typedef struct {
18   UINTN                       Signature;
19 
20   EMU_IO_THUNK_PROTOCOL       *Thunk;
21 
22   char                        *Filename;
23   UINTN                       ReadMode;
24   UINTN                       Mode;
25 
26   int                         fd;
27 
28   BOOLEAN                     RemovableMedia;
29   BOOLEAN                     WriteProtected;
30 
31   UINT64                      NumberOfBlocks;
32   UINT32                      BlockSize;
33 
34   EMU_BLOCK_IO_PROTOCOL       EmuBlockIo;
35   EFI_BLOCK_IO_MEDIA          *Media;
36 
37 } EMU_BLOCK_IO_PRIVATE;
38 
39 #define EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \
40          CR(a, EMU_BLOCK_IO_PRIVATE, EmuBlockIo, EMU_BLOCK_IO_PRIVATE_SIGNATURE)
41 
42 
43 
44 EFI_STATUS
45 EmuBlockIoReset (
46   IN EMU_BLOCK_IO_PROTOCOL    *This,
47   IN BOOLEAN                  ExtendedVerification
48   );
49 
50 
51 /*++
52 
53 This function extends the capability of SetFilePointer to accept 64 bit parameters
54 
55 **/
56 EFI_STATUS
SetFilePointer64(IN EMU_BLOCK_IO_PRIVATE * Private,IN INT64 DistanceToMove,OUT UINT64 * NewFilePointer,IN INT32 MoveMethod)57 SetFilePointer64 (
58   IN  EMU_BLOCK_IO_PRIVATE        *Private,
59   IN  INT64                      DistanceToMove,
60   OUT UINT64                     *NewFilePointer,
61   IN  INT32                      MoveMethod
62   )
63 {
64   EFI_STATUS    Status;
65   off_t         res;
66   off_t         offset = DistanceToMove;
67 
68   Status = EFI_SUCCESS;
69   res = lseek (Private->fd, offset, (int)MoveMethod);
70   if (res == -1) {
71     Status = EFI_INVALID_PARAMETER;
72   }
73 
74   if (NewFilePointer != NULL) {
75     *NewFilePointer = res;
76   }
77 
78   return Status;
79 }
80 
81 
82 EFI_STATUS
EmuBlockIoOpenDevice(IN EMU_BLOCK_IO_PRIVATE * Private)83 EmuBlockIoOpenDevice (
84   IN EMU_BLOCK_IO_PRIVATE   *Private
85   )
86 {
87   EFI_STATUS            Status;
88   UINT64                FileSize;
89   struct statfs         buf;
90 
91 
92   //
93   // If the device is already opened, close it
94   //
95   if (Private->fd >= 0) {
96     EmuBlockIoReset (&Private->EmuBlockIo, FALSE);
97   }
98 
99   //
100   // Open the device
101   //
102   Private->fd = open (Private->Filename, Private->Mode, 0644);
103   if (Private->fd < 0) {
104     printf ("EmuOpenBlock: Could not open %s: %s\n", Private->Filename, strerror(errno));
105     Private->Media->MediaPresent  = FALSE;
106     Status                        = EFI_NO_MEDIA;
107     goto Done;
108   }
109 
110   if (!Private->Media->MediaPresent) {
111     //
112     // BugBug: try to emulate if a CD appears - notify drivers to check it out
113     //
114     Private->Media->MediaPresent = TRUE;
115   }
116 
117   //
118   // get the size of the file
119   //
120   Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);
121   if (EFI_ERROR (Status)) {
122     printf ("EmuOpenBlock: Could not get filesize of %s\n", Private->Filename);
123     Status = EFI_UNSUPPORTED;
124     goto Done;
125   }
126 
127   if (FileSize == 0) {
128     // lseek fails on a real device. ioctl calls are OS specific
129 #if __APPLE__
130     {
131       UINT32 BlockSize;
132 
133       if (ioctl (Private->fd, DKIOCGETBLOCKSIZE, &BlockSize) == 0) {
134         Private->Media->BlockSize = BlockSize;
135       }
136       if (ioctl (Private->fd, DKIOCGETBLOCKCOUNT, &Private->NumberOfBlocks) == 0) {
137         if ((Private->NumberOfBlocks == 0) && (BlockSize == 0x800)) {
138           // A DVD is ~ 4.37 GB so make up a number
139           Private->Media->LastBlock = (0x100000000ULL/0x800) - 1;
140         } else {
141           Private->Media->LastBlock = Private->NumberOfBlocks - 1;
142         }
143       }
144       ioctl (Private->fd, DKIOCGETMAXBLOCKCOUNTWRITE, &Private->Media->OptimalTransferLengthGranularity);
145     }
146 #else
147     {
148       size_t BlockSize;
149       UINT64 DiskSize;
150 
151       if (ioctl (Private->fd, BLKSSZGET, &BlockSize) == 0) {
152         Private->Media->BlockSize = BlockSize;
153       }
154       if (ioctl (Private->fd, BLKGETSIZE64, &DiskSize) == 0) {
155         Private->NumberOfBlocks = DivU64x32 (DiskSize, (UINT32)BlockSize);
156         Private->Media->LastBlock = Private->NumberOfBlocks - 1;
157       }
158     }
159 #endif
160 
161   } else {
162     Private->Media->BlockSize = Private->BlockSize;
163     Private->NumberOfBlocks = DivU64x32 (FileSize, Private->Media->BlockSize);
164     Private->Media->LastBlock = Private->NumberOfBlocks - 1;
165 
166     if (fstatfs (Private->fd, &buf) == 0) {
167 #if __APPLE__
168       Private->Media->OptimalTransferLengthGranularity = buf.f_iosize/buf.f_bsize;
169 #else
170       Private->Media->OptimalTransferLengthGranularity = buf.f_bsize/buf.f_bsize;
171 #endif
172     }
173   }
174 
175   DEBUG ((EFI_D_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));
176   Status = EFI_SUCCESS;
177 
178 Done:
179   if (EFI_ERROR (Status)) {
180     if (Private->fd >= 0) {
181       EmuBlockIoReset (&Private->EmuBlockIo, FALSE);
182     }
183   }
184 
185   return Status;
186 }
187 
188 
189 EFI_STATUS
EmuBlockIoCreateMapping(IN EMU_BLOCK_IO_PROTOCOL * This,IN EFI_BLOCK_IO_MEDIA * Media)190 EmuBlockIoCreateMapping (
191   IN     EMU_BLOCK_IO_PROTOCOL    *This,
192   IN     EFI_BLOCK_IO_MEDIA       *Media
193   )
194 {
195   EFI_STATUS              Status;
196   EMU_BLOCK_IO_PRIVATE    *Private;
197 
198   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
199 
200   Private->Media = Media;
201 
202   Media->MediaId          = 0;
203   Media->RemovableMedia   = Private->RemovableMedia;
204   Media->MediaPresent     = TRUE;
205   Media->LogicalPartition = FALSE;
206   Media->ReadOnly         = Private->WriteProtected;
207   Media->WriteCaching     = FALSE;
208   Media->IoAlign          = 1;
209   Media->LastBlock        = 0; // Filled in by OpenDevice
210 
211   // EFI_BLOCK_IO_PROTOCOL_REVISION2
212   Media->LowestAlignedLba              = 0;
213   Media->LogicalBlocksPerPhysicalBlock = 0;
214 
215 
216   // EFI_BLOCK_IO_PROTOCOL_REVISION3
217   Media->OptimalTransferLengthGranularity = 0;
218 
219   Status = EmuBlockIoOpenDevice (Private);
220 
221 
222   return Status;
223 }
224 
225 
226 EFI_STATUS
EmuBlockIoError(IN EMU_BLOCK_IO_PRIVATE * Private)227 EmuBlockIoError (
228   IN EMU_BLOCK_IO_PRIVATE      *Private
229   )
230 {
231   EFI_STATUS            Status;
232   BOOLEAN               ReinstallBlockIoFlag;
233 
234 
235   switch (errno) {
236 
237   case EAGAIN:
238     Status                        = EFI_NO_MEDIA;
239     Private->Media->ReadOnly      = FALSE;
240     Private->Media->MediaPresent  = FALSE;
241     ReinstallBlockIoFlag          = FALSE;
242     break;
243 
244   case EACCES:
245     Private->Media->ReadOnly      = FALSE;
246     Private->Media->MediaPresent  = TRUE;
247     Private->Media->MediaId += 1;
248     ReinstallBlockIoFlag  = TRUE;
249     Status                = EFI_MEDIA_CHANGED;
250     break;
251 
252   case EROFS:
253     Private->Media->ReadOnly  = TRUE;
254     ReinstallBlockIoFlag      = FALSE;
255     Status                    = EFI_WRITE_PROTECTED;
256     break;
257 
258   default:
259     ReinstallBlockIoFlag  = FALSE;
260     Status                = EFI_DEVICE_ERROR;
261     break;
262   }
263   return Status;
264 }
265 
266 
267 EFI_STATUS
EmuBlockIoReadWriteCommon(IN EMU_BLOCK_IO_PRIVATE * Private,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer,IN CHAR8 * CallerName)268 EmuBlockIoReadWriteCommon (
269   IN  EMU_BLOCK_IO_PRIVATE        *Private,
270   IN UINT32                       MediaId,
271   IN EFI_LBA                      Lba,
272   IN UINTN                        BufferSize,
273   IN VOID                         *Buffer,
274   IN CHAR8                        *CallerName
275   )
276 {
277   EFI_STATUS  Status;
278   UINTN       BlockSize;
279   UINT64      LastBlock;
280   INT64       DistanceToMove;
281   UINT64      DistanceMoved;
282 
283   if (Private->fd < 0) {
284     Status = EmuBlockIoOpenDevice (Private);
285     if (EFI_ERROR (Status)) {
286       return Status;
287     }
288   }
289 
290   if (!Private->Media->MediaPresent) {
291     DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
292     return EFI_NO_MEDIA;
293   }
294 
295   if (Private->Media->MediaId != MediaId) {
296     return EFI_MEDIA_CHANGED;
297   }
298 
299   if ((UINTN) Buffer % Private->Media->IoAlign != 0) {
300     return EFI_INVALID_PARAMETER;
301   }
302 
303   //
304   // Verify buffer size
305   //
306   BlockSize = Private->Media->BlockSize;
307   if (BufferSize == 0) {
308     DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
309     return EFI_SUCCESS;
310   }
311 
312   if ((BufferSize % BlockSize) != 0) {
313     DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
314     return EFI_BAD_BUFFER_SIZE;
315   }
316 
317   LastBlock = Lba + (BufferSize / BlockSize) - 1;
318   if (LastBlock > Private->Media->LastBlock) {
319     DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
320     return EFI_INVALID_PARAMETER;
321   }
322   //
323   // Seek to End of File
324   //
325   DistanceToMove = MultU64x32 (Lba, BlockSize);
326   Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);
327 
328   if (EFI_ERROR (Status)) {
329     DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
330     return EmuBlockIoError (Private);
331   }
332 
333   return EFI_SUCCESS;
334 }
335 
336 
337 /**
338   Read BufferSize bytes from Lba into Buffer.
339 
340   This function reads the requested number of blocks from the device. All the
341   blocks are read, or an error is returned.
342   If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
343   non-blocking I/O is being used, the Event associated with this request will
344   not be signaled.
345 
346   @param[in]       This       Indicates a pointer to the calling context.
347   @param[in]       MediaId    Id of the media, changes every time the media is
348                               replaced.
349   @param[in]       Lba        The starting Logical Block Address to read from.
350   @param[in, out]  Token	    A pointer to the token associated with the transaction.
351   @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
352   @param[out]      Buffer     A pointer to the destination buffer for the data. The
353                               caller is responsible for either having implicit or
354                               explicit ownership of the buffer.
355 
356   @retval EFI_SUCCESS           The read request was queued if Token->Event is
357                                 not NULL.The data was read correctly from the
358                                 device if the Token->Event is NULL.
359   @retval EFI_DEVICE_ERROR      The device reported an error while performing
360                                 the read.
361   @retval EFI_NO_MEDIA          There is no media in the device.
362   @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.
363   @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the
364                                 intrinsic block size of the device.
365   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
366                                 or the buffer is not on proper alignment.
367   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
368                                 of resources.
369 **/
370 EFI_STATUS
EmuBlockIoReadBlocks(IN EMU_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN OUT EFI_BLOCK_IO2_TOKEN * Token,IN UINTN BufferSize,OUT VOID * Buffer)371 EmuBlockIoReadBlocks (
372   IN     EMU_BLOCK_IO_PROTOCOL  *This,
373   IN     UINT32                 MediaId,
374   IN     EFI_LBA                LBA,
375   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
376   IN     UINTN                  BufferSize,
377      OUT VOID                   *Buffer
378   )
379 {
380   EFI_STATUS              Status;
381   EMU_BLOCK_IO_PRIVATE    *Private;
382   ssize_t                 len;
383 
384   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
385 
386   Status  = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");
387   if (EFI_ERROR (Status)) {
388     goto Done;
389   }
390 
391   len = read (Private->fd, Buffer, BufferSize);
392   if (len != BufferSize) {
393     DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));
394     Status = EmuBlockIoError (Private);
395     goto Done;
396   }
397 
398   //
399   // If we read then media is present.
400   //
401   Private->Media->MediaPresent = TRUE;
402   Status = EFI_SUCCESS;
403 
404 Done:
405   if (Token != NULL) {
406     if (Token->Event != NULL) {
407       // Caller is responcible for signaling EFI Event
408       Token->TransactionStatus = Status;
409       return EFI_SUCCESS;
410     }
411   }
412   return Status;
413 }
414 
415 
416 /**
417   Write BufferSize bytes from Lba into Buffer.
418 
419   This function writes the requested number of blocks to the device. All blocks
420   are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
421   EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
422   being used, the Event associated with this request will not be signaled.
423 
424   @param[in]       This       Indicates a pointer to the calling context.
425   @param[in]       MediaId    The media ID that the write request is for.
426   @param[in]       Lba        The starting logical block address to be written. The
427                               caller is responsible for writing to only legitimate
428                               locations.
429   @param[in, out]  Token      A pointer to the token associated with the transaction.
430   @param[in]       BufferSize Size of Buffer, must be a multiple of device block size.
431   @param[in]       Buffer     A pointer to the source buffer for the data.
432 
433   @retval EFI_SUCCESS           The write request was queued if Event is not NULL.
434                                 The data was written correctly to the device if
435                                 the Event is NULL.
436   @retval EFI_WRITE_PROTECTED   The device can not be written to.
437   @retval EFI_NO_MEDIA          There is no media in the device.
438   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
439   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
440   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
441   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
442                                 or the buffer is not on proper alignment.
443   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack
444                                 of resources.
445 
446 **/
447 EFI_STATUS
EmuBlockIoWriteBlocks(IN EMU_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA LBA,IN OUT EFI_BLOCK_IO2_TOKEN * Token,IN UINTN BufferSize,IN VOID * Buffer)448 EmuBlockIoWriteBlocks (
449   IN     EMU_BLOCK_IO_PROTOCOL  *This,
450   IN     UINT32                 MediaId,
451   IN     EFI_LBA                LBA,
452   IN OUT EFI_BLOCK_IO2_TOKEN    *Token,
453   IN     UINTN                  BufferSize,
454   IN     VOID                   *Buffer
455   )
456 {
457   EMU_BLOCK_IO_PRIVATE    *Private;
458   ssize_t                 len;
459   EFI_STATUS              Status;
460 
461 
462   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
463 
464   Status  = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");
465   if (EFI_ERROR (Status)) {
466     goto Done;
467   }
468 
469   len = write (Private->fd, Buffer, BufferSize);
470   if (len != BufferSize) {
471     DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));
472     Status = EmuBlockIoError (Private);
473     goto Done;
474   }
475 
476   //
477   // If the write succeeded, we are not write protected and media is present.
478   //
479   Private->Media->MediaPresent = TRUE;
480   Private->Media->ReadOnly     = FALSE;
481   Status = EFI_SUCCESS;
482 
483 Done:
484   if (Token != NULL) {
485     if (Token->Event != NULL) {
486       // Caller is responcible for signaling EFI Event
487       Token->TransactionStatus = Status;
488       return EFI_SUCCESS;
489     }
490   }
491 
492   return Status;
493 }
494 
495 
496 /**
497   Flush the Block Device.
498 
499   If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
500   is returned and non-blocking I/O is being used, the Event associated with
501   this request will not be signaled.
502 
503   @param[in]      This     Indicates a pointer to the calling context.
504   @param[in,out]  Token    A pointer to the token associated with the transaction
505 
506   @retval EFI_SUCCESS          The flush request was queued if Event is not NULL.
507                                All outstanding data was written correctly to the
508                                device if the Event is NULL.
509   @retval EFI_DEVICE_ERROR     The device reported an error while writting back
510                                the data.
511   @retval EFI_WRITE_PROTECTED  The device cannot be written to.
512   @retval EFI_NO_MEDIA         There is no media in the device.
513   @retval EFI_MEDIA_CHANGED    The MediaId is not for the current media.
514   @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
515                                of resources.
516 
517 **/
518 EFI_STATUS
EmuBlockIoFlushBlocks(IN EMU_BLOCK_IO_PROTOCOL * This,IN OUT EFI_BLOCK_IO2_TOKEN * Token)519 EmuBlockIoFlushBlocks (
520   IN     EMU_BLOCK_IO_PROTOCOL    *This,
521   IN OUT EFI_BLOCK_IO2_TOKEN      *Token
522   )
523 {
524   EMU_BLOCK_IO_PRIVATE *Private;
525 
526   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
527 
528   if (Private->fd >= 0) {
529     fsync (Private->fd);
530 #if __APPLE__
531     fcntl (Private->fd, F_FULLFSYNC);
532 #endif
533   }
534 
535 
536   if (Token != NULL) {
537     if (Token->Event != NULL) {
538       // Caller is responcible for signaling EFI Event
539       Token->TransactionStatus = EFI_SUCCESS;
540       return EFI_SUCCESS;
541     }
542   }
543 
544   return EFI_SUCCESS;
545 }
546 
547 
548 /**
549   Reset the block device hardware.
550 
551   @param[in]  This                 Indicates a pointer to the calling context.
552   @param[in]  ExtendedVerification Indicates that the driver may perform a more
553                                    exhausive verfication operation of the device
554                                    during reset.
555 
556   @retval EFI_SUCCESS          The device was reset.
557   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
558                                not be reset.
559 
560 **/
561 EFI_STATUS
EmuBlockIoReset(IN EMU_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)562 EmuBlockIoReset (
563   IN EMU_BLOCK_IO_PROTOCOL    *This,
564   IN BOOLEAN                  ExtendedVerification
565   )
566 {
567   EMU_BLOCK_IO_PRIVATE *Private;
568 
569   Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
570 
571   if (Private->fd >= 0) {
572     close (Private->fd);
573     Private->fd = -1;
574   }
575 
576   return EFI_SUCCESS;
577 }
578 
579 
580 char *
StdDupUnicodeToAscii(IN CHAR16 * Str)581 StdDupUnicodeToAscii (
582   IN  CHAR16 *Str
583   )
584 {
585   UINTN   Size;
586   char    *Ascii;
587   char    *Ptr;
588 
589   Size = StrLen (Str) + 1;
590   Ascii = malloc (Size);
591   if (Ascii == NULL) {
592     return NULL;
593   }
594 
595   for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {
596     *Ptr = *Str;
597   }
598   *Ptr = 0;
599 
600   return Ascii;
601 }
602 
603 
604 EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {
605   GasketEmuBlockIoReset,
606   GasketEmuBlockIoReadBlocks,
607   GasketEmuBlockIoWriteBlocks,
608   GasketEmuBlockIoFlushBlocks,
609   GasketEmuBlockIoCreateMapping
610 };
611 
612 EFI_STATUS
EmuBlockIoThunkOpen(IN EMU_IO_THUNK_PROTOCOL * This)613 EmuBlockIoThunkOpen (
614   IN  EMU_IO_THUNK_PROTOCOL   *This
615   )
616 {
617   EMU_BLOCK_IO_PRIVATE  *Private;
618   char                  *Str;
619 
620   if (This->Private != NULL) {
621     return EFI_ALREADY_STARTED;
622   }
623 
624   if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {
625     return EFI_UNSUPPORTED;
626   }
627 
628   Private = malloc (sizeof (EMU_BLOCK_IO_PRIVATE));
629   if (Private == NULL) {
630     return EFI_OUT_OF_RESOURCES;
631   }
632 
633 
634   Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;
635   Private->Thunk     = This;
636   CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));
637   Private->fd        = -1;
638   Private->BlockSize = 512;
639 
640   Private->Filename = StdDupUnicodeToAscii (This->ConfigString);
641   if (Private->Filename == NULL) {
642     return EFI_OUT_OF_RESOURCES;
643   }
644 
645   Str = strstr (Private->Filename, ":");
646   if (Str == NULL) {
647     Private->RemovableMedia = FALSE;
648     Private->WriteProtected = FALSE;
649   } else {
650     for (*Str++ = '\0'; *Str != 0; Str++) {
651       if (*Str == 'R' || *Str == 'F') {
652         Private->RemovableMedia = (BOOLEAN) (*Str == 'R');
653       }
654       if (*Str == 'O' || *Str == 'W') {
655         Private->WriteProtected  = (BOOLEAN) (*Str == 'O');
656       }
657       if (*Str == ':') {
658         Private->BlockSize = strtol (++Str, NULL, 0);
659         break;
660       }
661     }
662   }
663 
664   Private->Mode = Private->WriteProtected ? O_RDONLY : O_RDWR;
665 
666   This->Interface = &Private->EmuBlockIo;
667   This->Private   = Private;
668   return EFI_SUCCESS;
669 }
670 
671 
672 EFI_STATUS
EmuBlockIoThunkClose(IN EMU_IO_THUNK_PROTOCOL * This)673 EmuBlockIoThunkClose (
674   IN  EMU_IO_THUNK_PROTOCOL   *This
675   )
676 {
677   EMU_BLOCK_IO_PRIVATE  *Private;
678 
679   if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {
680     return EFI_UNSUPPORTED;
681   }
682 
683   Private = This->Private;
684 
685   if (This->Private != NULL) {
686     if (Private->Filename != NULL) {
687       free (Private->Filename);
688     }
689     free (This->Private);
690     This->Private = NULL;
691   }
692 
693   return EFI_SUCCESS;
694 }
695 
696 
697 
698 EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {
699   &gEmuBlockIoProtocolGuid,
700   NULL,
701   NULL,
702   0,
703   GasketBlockIoThunkOpen,
704   GasketBlockIoThunkClose,
705   NULL
706 };
707 
708 
709