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