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