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