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