]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/BlockIo.c
InOsEmuPkg: Update code to support BerkeleyPacketFilter, and add a template for Linux...
[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
033d0e5f 258/*\r
d59326d3 259 if (ReinstallBlockIoFlag) {\r
033d0e5f 260 Private->EmuBlockIo->Reset (&Private->EmuBlockIo, FALSE);\r
d59326d3 261\r
262 gBS->ReinstallProtocolInterface (\r
263 Private->EfiHandle,\r
264 &gEfiBlockIoProtocolGuid,\r
265 BlockIo,\r
266 BlockIo\r
267 );\r
268 }\r
033d0e5f 269*/\r
d59326d3 270 return Status;\r
d59326d3 271}\r
272\r
273EFI_STATUS\r
033d0e5f 274EmuBlockIoReadWriteCommon (\r
275 IN EMU_BLOCK_IO_PRIVATE *Private,\r
d59326d3 276 IN UINT32 MediaId,\r
277 IN EFI_LBA Lba,\r
278 IN UINTN BufferSize,\r
279 IN VOID *Buffer,\r
280 IN CHAR8 *CallerName\r
281 )\r
282{\r
283 EFI_STATUS Status;\r
284 UINTN BlockSize;\r
285 UINT64 LastBlock;\r
286 INT64 DistanceToMove;\r
287 UINT64 DistanceMoved;\r
288\r
289 if (Private->fd < 0) {\r
033d0e5f 290 Status = EmuBlockIoOpenDevice (Private);\r
d59326d3 291 if (EFI_ERROR (Status)) {\r
292 return Status;\r
293 }\r
294 }\r
295\r
033d0e5f 296 if (!Private->Media->MediaPresent) {\r
d59326d3 297 DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));\r
298 return EFI_NO_MEDIA;\r
299 }\r
300\r
033d0e5f 301 if (Private->Media->MediaId != MediaId) {\r
d59326d3 302 return EFI_MEDIA_CHANGED;\r
303 }\r
304\r
033d0e5f 305 if ((UINTN) Buffer % Private->Media->IoAlign != 0) {\r
d59326d3 306 return EFI_INVALID_PARAMETER;\r
307 }\r
308 \r
309 //\r
310 // Verify buffer size\r
311 //\r
63947cc4 312 BlockSize = Private->Media->BlockSize;\r
d59326d3 313 if (BufferSize == 0) {\r
314 DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));\r
315 return EFI_SUCCESS;\r
316 }\r
317\r
318 if ((BufferSize % BlockSize) != 0) {\r
319 DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));\r
320 return EFI_BAD_BUFFER_SIZE;\r
321 }\r
322\r
323 LastBlock = Lba + (BufferSize / BlockSize) - 1;\r
63947cc4 324 if (LastBlock > Private->Media->LastBlock) {\r
d59326d3 325 DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));\r
326 return EFI_INVALID_PARAMETER;\r
327 }\r
328 //\r
329 // Seek to End of File\r
330 //\r
331 DistanceToMove = MultU64x32 (Lba, BlockSize);\r
332 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);\r
333\r
334 if (EFI_ERROR (Status)) {\r
335 DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));\r
033d0e5f 336 return EmuBlockIoError (Private);\r
d59326d3 337 }\r
338\r
339 return EFI_SUCCESS;\r
340}\r
341\r
d59326d3 342\r
033d0e5f 343/**\r
344 Read BufferSize bytes from Lba into Buffer.\r
345 \r
346 This function reads the requested number of blocks from the device. All the\r
347 blocks are read, or an error is returned.\r
348 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r
349 non-blocking I/O is being used, the Event associated with this request will\r
350 not be signaled.\r
351\r
352 @param[in] This Indicates a pointer to the calling context.\r
353 @param[in] MediaId Id of the media, changes every time the media is \r
354 replaced.\r
355 @param[in] Lba The starting Logical Block Address to read from.\r
356 @param[in, out] Token A pointer to the token associated with the transaction.\r
357 @param[in] BufferSize Size of Buffer, must be a multiple of device block size. \r
358 @param[out] Buffer A pointer to the destination buffer for the data. The \r
359 caller is responsible for either having implicit or \r
360 explicit ownership of the buffer.\r
361\r
362 @retval EFI_SUCCESS The read request was queued if Token->Event is\r
363 not NULL.The data was read correctly from the\r
364 device if the Token->Event is NULL.\r
365 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
366 the read.\r
367 @retval EFI_NO_MEDIA There is no media in the device.\r
368 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
369 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
370 intrinsic block size of the device.\r
371 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
372 or the buffer is not on proper alignment.\r
373 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
374 of resources.\r
d59326d3 375**/\r
033d0e5f 376EFI_STATUS\r
377EmuBlockIoReadBlocks (\r
378 IN EMU_BLOCK_IO_PROTOCOL *This,\r
379 IN UINT32 MediaId,\r
380 IN EFI_LBA LBA,\r
381 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
382 IN UINTN BufferSize,\r
383 OUT VOID *Buffer\r
384 )\r
d59326d3 385{\r
d59326d3 386 EFI_STATUS Status;\r
033d0e5f 387 EMU_BLOCK_IO_PRIVATE *Private;\r
388 ssize_t len;\r
d59326d3 389\r
390 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
391\r
033d0e5f 392 Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");\r
d59326d3 393 if (EFI_ERROR (Status)) {\r
394 goto Done;\r
395 }\r
396\r
033d0e5f 397 len = read (Private->fd, Buffer, BufferSize);\r
d59326d3 398 if (len != BufferSize) {\r
399 DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));\r
033d0e5f 400 Status = EmuBlockIoError (Private);\r
d59326d3 401 goto Done;\r
402 }\r
403\r
404 //\r
033d0e5f 405 // If we read then media is present.\r
d59326d3 406 //\r
033d0e5f 407 Private->Media->MediaPresent = TRUE;\r
d59326d3 408 Status = EFI_SUCCESS;\r
409\r
410Done:\r
033d0e5f 411 if (Token != NULL) {\r
412 if (Token->Event != NULL) {\r
413 // Caller is responcible for signaling EFI Event\r
414 Token->TransactionStatus = Status;\r
415 return EFI_SUCCESS;\r
416 }\r
417 }\r
d59326d3 418 return Status;\r
419}\r
420\r
d59326d3 421\r
033d0e5f 422/**\r
423 Write BufferSize bytes from Lba into Buffer.\r
424\r
425 This function writes the requested number of blocks to the device. All blocks\r
426 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r
427 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r
428 being used, the Event associated with this request will not be signaled.\r
429\r
430 @param[in] This Indicates a pointer to the calling context.\r
431 @param[in] MediaId The media ID that the write request is for.\r
432 @param[in] Lba The starting logical block address to be written. The\r
433 caller is responsible for writing to only legitimate\r
434 locations.\r
435 @param[in, out] Token A pointer to the token associated with the transaction.\r
436 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
437 @param[in] Buffer A pointer to the source buffer for the data.\r
438\r
439 @retval EFI_SUCCESS The write request was queued if Event is not NULL.\r
440 The data was written correctly to the device if\r
441 the Event is NULL.\r
442 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
443 @retval EFI_NO_MEDIA There is no media in the device.\r
444 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
445 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
446 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
447 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
448 or the buffer is not on proper alignment.\r
449 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
450 of resources.\r
d59326d3 451\r
452**/\r
033d0e5f 453EFI_STATUS\r
454EmuBlockIoWriteBlocks (\r
455 IN EMU_BLOCK_IO_PROTOCOL *This,\r
456 IN UINT32 MediaId,\r
457 IN EFI_LBA LBA,\r
458 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
459 IN UINTN BufferSize,\r
460 IN VOID *Buffer\r
461 )\r
d59326d3 462{\r
033d0e5f 463 EMU_BLOCK_IO_PRIVATE *Private;\r
d59326d3 464 ssize_t len;\r
465 EFI_STATUS Status;\r
d59326d3 466\r
d59326d3 467\r
468 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
469\r
033d0e5f 470 Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");\r
d59326d3 471 if (EFI_ERROR (Status)) {\r
472 goto Done;\r
473 }\r
474\r
033d0e5f 475 len = write (Private->fd, Buffer, BufferSize);\r
d59326d3 476 if (len != BufferSize) {\r
477 DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));\r
033d0e5f 478 Status = EmuBlockIoError (Private);\r
d59326d3 479 goto Done;\r
480 }\r
481\r
482 //\r
483 // If the write succeeded, we are not write protected and media is present.\r
484 //\r
033d0e5f 485 Private->Media->MediaPresent = TRUE;\r
486 Private->Media->ReadOnly = FALSE;\r
d59326d3 487 Status = EFI_SUCCESS;\r
488\r
489Done:\r
033d0e5f 490 if (Token != NULL) {\r
491 if (Token->Event != NULL) {\r
492 // Caller is responcible for signaling EFI Event\r
493 Token->TransactionStatus = Status;\r
494 return EFI_SUCCESS;\r
495 }\r
496 }\r
497\r
d59326d3 498 return Status;\r
499}\r
500\r
d59326d3 501\r
033d0e5f 502/**\r
503 Flush the Block Device.\r
504 \r
505 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r
506 is returned and non-blocking I/O is being used, the Event associated with\r
507 this request will not be signaled. \r
508\r
509 @param[in] This Indicates a pointer to the calling context.\r
510 @param[in,out] Token A pointer to the token associated with the transaction\r
511\r
512 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.\r
513 All outstanding data was written correctly to the\r
514 device if the Event is NULL.\r
515 @retval EFI_DEVICE_ERROR The device reported an error while writting back\r
516 the data.\r
517 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
518 @retval EFI_NO_MEDIA There is no media in the device.\r
519 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
520 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
521 of resources.\r
d59326d3 522\r
523**/\r
033d0e5f 524EFI_STATUS\r
525EmuBlockIoFlushBlocks (\r
526 IN EMU_BLOCK_IO_PROTOCOL *This,\r
527 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
528 )\r
d59326d3 529{\r
033d0e5f 530 EMU_BLOCK_IO_PRIVATE *Private;\r
63947cc4 531 int Res;\r
033d0e5f 532\r
533 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
534\r
535 if (Private->fd >= 0) {\r
63947cc4 536 Res = fcntl (Private->fd, F_FULLFSYNC);\r
033d0e5f 537 }\r
538 \r
63947cc4 539 \r
033d0e5f 540 if (Token != NULL) {\r
541 if (Token->Event != NULL) {\r
542 // Caller is responcible for signaling EFI Event\r
543 Token->TransactionStatus = EFI_SUCCESS;\r
544 return EFI_SUCCESS;\r
545 }\r
546 }\r
547 \r
d59326d3 548 return EFI_SUCCESS;\r
549}\r
550\r
033d0e5f 551\r
552/**\r
553 Reset the block device hardware.\r
554\r
555 @param[in] This Indicates a pointer to the calling context.\r
556 @param[in] ExtendedVerification Indicates that the driver may perform a more\r
557 exhausive verfication operation of the device\r
558 during reset.\r
559\r
560 @retval EFI_SUCCESS The device was reset.\r
561 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
562 not be reset.\r
563\r
564**/\r
d59326d3 565EFI_STATUS\r
033d0e5f 566EmuBlockIoReset (\r
567 IN EMU_BLOCK_IO_PROTOCOL *This,\r
568 IN BOOLEAN ExtendedVerification\r
d59326d3 569 )\r
570/*++\r
571\r
572 Routine Description:\r
573 Reset the Block Device.\r
574\r
575 Arguments:\r
576 This - Protocol instance pointer.\r
577 ExtendedVerification - Driver may perform diagnostics on reset.\r
578\r
579 Returns:\r
580 EFI_SUCCESS - The device was reset.\r
581 EFI_DEVICE_ERROR - The device is not functioning properly and could \r
582 not be reset.\r
583\r
584**/\r
585{\r
586 EMU_BLOCK_IO_PRIVATE *Private;\r
d59326d3 587\r
d59326d3 588 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
589\r
590 if (Private->fd >= 0) {\r
033d0e5f 591 close (Private->fd);\r
d59326d3 592 Private->fd = -1;\r
593 }\r
594\r
d59326d3 595 return EFI_SUCCESS;\r
596}\r
597\r
d59326d3 598\r
033d0e5f 599char *\r
600StdDupUnicodeToAscii (\r
601 IN CHAR16 *Str\r
602 )\r
603{\r
604 UINTN Size;\r
605 char *Ascii;\r
606 char *Ptr;\r
607 \r
608 Size = StrLen (Str) + 1;\r
609 Ascii = malloc (Size);\r
610 if (Ascii == NULL) {\r
611 return NULL;\r
612 }\r
613 \r
614 for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {\r
615 *Ptr = *Str;\r
616 }\r
617 *Ptr = 0;\r
618 \r
619 return Ascii;\r
620}\r
d59326d3 621\r
d59326d3 622\r
033d0e5f 623EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {\r
624 GasketEmuBlockIoReset,\r
625 GasketEmuBlockIoReadBlocks,\r
626 GasketEmuBlockIoWriteBlocks,\r
627 GasketEmuBlockIoFlushBlocks,\r
628 GasketEmuBlockIoCreateMapping\r
629};\r
d59326d3 630\r
033d0e5f 631EFI_STATUS\r
632EmuBlockIoThunkOpen (\r
633 IN EMU_IO_THUNK_PROTOCOL *This\r
634 )\r
d59326d3 635{\r
033d0e5f 636 EMU_BLOCK_IO_PRIVATE *Private;\r
637 char *Str;\r
638 \r
639 if (This->Private != NULL) {\r
640 return EFI_ALREADY_STARTED;\r
d59326d3 641 }\r
033d0e5f 642 \r
643 if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r
644 return EFI_UNSUPPORTED;\r
645 }\r
646 \r
647 Private = malloc (sizeof (EMU_BLOCK_IO_PRIVATE));\r
648 if (Private == NULL) {\r
649 return EFI_OUT_OF_RESOURCES;\r
d59326d3 650 }\r
651\r
033d0e5f 652 \r
653 Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;\r
654 Private->Thunk = This;\r
655 CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));\r
656 Private->fd = -1;\r
657 \r
658 Private->Filename = StdDupUnicodeToAscii (This->ConfigString);\r
659 if (Private->Filename == NULL) {\r
660 return EFI_OUT_OF_RESOURCES;\r
661 }\r
662 \r
663 Str = strstr (Private->Filename, ":");\r
664 if (Str == NULL) {\r
665 Private->RemovableMedia = FALSE;\r
666 Private->WriteProtected = FALSE;\r
667 } else {\r
668 for (*Str++ = '\0'; *Str != 0; Str++) {\r
669 if (*Str == 'R' || *Str == 'F') {\r
670 Private->RemovableMedia = (BOOLEAN) (*Str == 'R');\r
671 }\r
672 if (*Str == 'O' || *Str == 'W') {\r
673 Private->WriteProtected = (BOOLEAN) (*Str == 'O');\r
674 }\r
675 }\r
676 }\r
677 \r
033d0e5f 678 This->Interface = &Private->EmuBlockIo;\r
679 This->Private = Private;\r
680 return EFI_SUCCESS;\r
d59326d3 681}\r
682\r
683\r
d59326d3 684EFI_STATUS\r
033d0e5f 685EmuBlockIoThunkClose (\r
686 IN EMU_IO_THUNK_PROTOCOL *This\r
d59326d3 687 )\r
688{\r
033d0e5f 689 EMU_BLOCK_IO_PRIVATE *Private;\r
d59326d3 690\r
033d0e5f 691 if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r
692 return EFI_UNSUPPORTED;\r
d59326d3 693 }\r
033d0e5f 694 \r
695 Private = This->Private;\r
696 \r
697 if (This->Private != NULL) {\r
698 if (Private->Filename != NULL) {\r
699 free (Private->Filename);\r
700 } \r
701 free (This->Private);\r
21ce7a41 702 This->Private = NULL;\r
d59326d3 703 }\r
033d0e5f 704 \r
705 return EFI_SUCCESS;\r
d59326d3 706}\r
033d0e5f 707\r
708\r
709\r
710EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {\r
711 &gEmuBlockIoProtocolGuid,\r
712 NULL,\r
713 NULL,\r
714 0,\r
715 GasketBlockIoThunkOpen,\r
716 GasketBlockIoThunkClose,\r
717 NULL\r
718};\r
719\r
720\r