3 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #define EMU_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'M', 'b', 'k')
22 EMU_IO_THUNK_PROTOCOL
*Thunk
;
30 BOOLEAN RemovableMedia
;
31 BOOLEAN WriteProtected
;
34 UINT64 NumberOfBlocks
;
37 EMU_BLOCK_IO_PROTOCOL EmuBlockIo
;
38 EFI_BLOCK_IO_MEDIA
*Media
;
40 } EMU_BLOCK_IO_PRIVATE
;
42 #define EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \
43 CR(a, EMU_BLOCK_IO_PRIVATE, EmuBlockIo, EMU_BLOCK_IO_PRIVATE_SIGNATURE)
49 IN EMU_BLOCK_IO_PROTOCOL
*This
,
50 IN BOOLEAN ExtendedVerification
56 This function extends the capability of SetFilePointer to accept 64 bit parameters
61 IN EMU_BLOCK_IO_PRIVATE
*Private
,
62 IN INT64 DistanceToMove
,
63 OUT UINT64
*NewFilePointer
,
71 res
= lseek (Private
->fd
, DistanceToMove
, MoveMethod
);
73 Status
= EFI_INVALID_PARAMETER
;
76 if (NewFilePointer
!= NULL
) {
77 *NewFilePointer
= res
;
85 EmuBlockIoOpenDevice (
86 IN EMU_BLOCK_IO_PRIVATE
*Private
95 // If the device is already opened, close it
97 if (Private
->fd
>= 0) {
98 EmuBlockIoReset (&Private
->EmuBlockIo
, FALSE
);
104 Private
->fd
= open (Private
->Filename
, Private
->Mode
, 0644);
105 if (Private
->fd
< 0) {
106 DEBUG ((EFI_D_INFO
, "EmuOpenBlock: Could not open %a\n", Private
->Filename
));
107 Private
->Media
->MediaPresent
= FALSE
;
108 Status
= EFI_NO_MEDIA
;
112 if (!Private
->Media
->MediaPresent
) {
114 // BugBug: try to emulate if a CD appears - notify drivers to check it out
116 Private
->Media
->MediaPresent
= TRUE
;
120 // get the size of the file
122 Status
= SetFilePointer64 (Private
, 0, &FileSize
, SEEK_END
);
123 if (EFI_ERROR (Status
)) {
124 FileSize
= MultU64x32 (Private
->NumberOfBlocks
, Private
->BlockSize
);
125 DEBUG ((EFI_D_ERROR
, "EmuOpenBlock: Could not get filesize of %a\n", Private
->Filename
));
126 Status
= EFI_UNSUPPORTED
;
130 if (Private
->NumberOfBlocks
== 0) {
131 Private
->NumberOfBlocks
= DivU64x32 (FileSize
, Private
->BlockSize
);
132 Private
->LastBlock
= Private
->NumberOfBlocks
- 1;
133 Private
->Media
->LastBlock
= Private
->LastBlock
;
136 EndOfFile
= MultU64x32 (Private
->NumberOfBlocks
, Private
->BlockSize
);
138 if (FileSize
!= EndOfFile
) {
140 // file is not the proper size, change it
142 DEBUG ((EFI_D_INIT
, "EmuOpenBlock: Initializing block device: %a\n", Private
->Filename
));
147 ftruncate (Private
->fd
, 0);
150 // then set it to the needed file size (OS will zero fill it)
152 ftruncate (Private
->fd
, EndOfFile
);
155 DEBUG ((EFI_D_INIT
, "%HEmuOpenBlock: opened %a%N\n", Private
->Filename
));
156 Status
= EFI_SUCCESS
;
159 if (EFI_ERROR (Status
)) {
160 if (Private
->fd
>= 0) {
161 EmuBlockIoReset (&Private
->EmuBlockIo
, FALSE
);
170 EmuBlockIoCreateMapping (
171 IN EMU_BLOCK_IO_PROTOCOL
*This
,
172 IN EFI_BLOCK_IO_MEDIA
*Media
176 EMU_BLOCK_IO_PRIVATE
*Private
;
178 Private
= EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
180 Private
->Media
= Media
;
183 Media
->RemovableMedia
= Private
->RemovableMedia
;
184 Media
->MediaPresent
= TRUE
;
185 Media
->LogicalPartition
= FALSE
;
186 Media
->ReadOnly
= Private
->WriteProtected
;
187 Media
->WriteCaching
= FALSE
;
188 Media
->BlockSize
= Private
->BlockSize
;
190 Media
->LastBlock
= 0; // Filled in by OpenDevice
192 // EFI_BLOCK_IO_PROTOCOL_REVISION2
193 Media
->LowestAlignedLba
= 0;
194 Media
->LogicalBlocksPerPhysicalBlock
= 0;
196 // EFI_BLOCK_IO_PROTOCOL_REVISION3
197 Media
->OptimalTransferLengthGranularity
= 0;
199 Status
= EmuBlockIoOpenDevice (Private
);
207 IN EMU_BLOCK_IO_PRIVATE
*Private
211 BOOLEAN ReinstallBlockIoFlag
;
217 Status
= EFI_NO_MEDIA
;
218 Private
->Media
->ReadOnly
= FALSE
;
219 Private
->Media
->MediaPresent
= FALSE
;
220 ReinstallBlockIoFlag
= FALSE
;
224 Private
->Media
->ReadOnly
= FALSE
;
225 Private
->Media
->MediaPresent
= TRUE
;
226 Private
->Media
->MediaId
+= 1;
227 ReinstallBlockIoFlag
= TRUE
;
228 Status
= EFI_MEDIA_CHANGED
;
232 Private
->Media
->ReadOnly
= TRUE
;
233 ReinstallBlockIoFlag
= FALSE
;
234 Status
= EFI_WRITE_PROTECTED
;
238 ReinstallBlockIoFlag
= FALSE
;
239 Status
= EFI_DEVICE_ERROR
;
243 if (ReinstallBlockIoFlag) {
244 Private->EmuBlockIo->Reset (&Private->EmuBlockIo, FALSE);
246 gBS->ReinstallProtocolInterface (
248 &gEfiBlockIoProtocolGuid,
258 EmuBlockIoReadWriteCommon (
259 IN EMU_BLOCK_IO_PRIVATE
*Private
,
270 INT64 DistanceToMove
;
271 UINT64 DistanceMoved
;
273 if (Private
->fd
< 0) {
274 Status
= EmuBlockIoOpenDevice (Private
);
275 if (EFI_ERROR (Status
)) {
280 if (!Private
->Media
->MediaPresent
) {
281 DEBUG ((EFI_D_INIT
, "%s: No Media\n", CallerName
));
285 if (Private
->Media
->MediaId
!= MediaId
) {
286 return EFI_MEDIA_CHANGED
;
289 if ((UINTN
) Buffer
% Private
->Media
->IoAlign
!= 0) {
290 return EFI_INVALID_PARAMETER
;
294 // Verify buffer size
296 BlockSize
= Private
->BlockSize
;
297 if (BufferSize
== 0) {
298 DEBUG ((EFI_D_INIT
, "%s: Zero length read\n", CallerName
));
302 if ((BufferSize
% BlockSize
) != 0) {
303 DEBUG ((EFI_D_INIT
, "%s: Invalid read size\n", CallerName
));
304 return EFI_BAD_BUFFER_SIZE
;
307 LastBlock
= Lba
+ (BufferSize
/ BlockSize
) - 1;
308 if (LastBlock
> Private
->LastBlock
) {
309 DEBUG ((EFI_D_INIT
, "ReadBlocks: Attempted to read off end of device\n"));
310 return EFI_INVALID_PARAMETER
;
313 // Seek to End of File
315 DistanceToMove
= MultU64x32 (Lba
, BlockSize
);
316 Status
= SetFilePointer64 (Private
, DistanceToMove
, &DistanceMoved
, SEEK_SET
);
318 if (EFI_ERROR (Status
)) {
319 DEBUG ((EFI_D_INIT
, "WriteBlocks: SetFilePointer failed\n"));
320 return EmuBlockIoError (Private
);
328 Read BufferSize bytes from Lba into Buffer.
330 This function reads the requested number of blocks from the device. All the
331 blocks are read, or an error is returned.
332 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
333 non-blocking I/O is being used, the Event associated with this request will
336 @param[in] This Indicates a pointer to the calling context.
337 @param[in] MediaId Id of the media, changes every time the media is
339 @param[in] Lba The starting Logical Block Address to read from.
340 @param[in, out] Token A pointer to the token associated with the transaction.
341 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
342 @param[out] Buffer A pointer to the destination buffer for the data. The
343 caller is responsible for either having implicit or
344 explicit ownership of the buffer.
346 @retval EFI_SUCCESS The read request was queued if Token->Event is
347 not NULL.The data was read correctly from the
348 device if the Token->Event is NULL.
349 @retval EFI_DEVICE_ERROR The device reported an error while performing
351 @retval EFI_NO_MEDIA There is no media in the device.
352 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
353 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
354 intrinsic block size of the device.
355 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
356 or the buffer is not on proper alignment.
357 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
361 EmuBlockIoReadBlocks (
362 IN EMU_BLOCK_IO_PROTOCOL
*This
,
365 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
371 EMU_BLOCK_IO_PRIVATE
*Private
;
374 Private
= EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
376 Status
= EmuBlockIoReadWriteCommon (Private
, MediaId
, LBA
, BufferSize
, Buffer
, "UnixReadBlocks");
377 if (EFI_ERROR (Status
)) {
381 len
= read (Private
->fd
, Buffer
, BufferSize
);
382 if (len
!= BufferSize
) {
383 DEBUG ((EFI_D_INIT
, "ReadBlocks: ReadFile failed.\n"));
384 Status
= EmuBlockIoError (Private
);
389 // If we read then media is present.
391 Private
->Media
->MediaPresent
= TRUE
;
392 Status
= EFI_SUCCESS
;
396 if (Token
->Event
!= NULL
) {
397 // Caller is responcible for signaling EFI Event
398 Token
->TransactionStatus
= Status
;
407 Write BufferSize bytes from Lba into Buffer.
409 This function writes the requested number of blocks to the device. All blocks
410 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
411 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
412 being used, the Event associated with this request will not be signaled.
414 @param[in] This Indicates a pointer to the calling context.
415 @param[in] MediaId The media ID that the write request is for.
416 @param[in] Lba The starting logical block address to be written. The
417 caller is responsible for writing to only legitimate
419 @param[in, out] Token A pointer to the token associated with the transaction.
420 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
421 @param[in] Buffer A pointer to the source buffer for the data.
423 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
424 The data was written correctly to the device if
426 @retval EFI_WRITE_PROTECTED The device can not be written to.
427 @retval EFI_NO_MEDIA There is no media in the device.
428 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
429 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
430 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
431 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
432 or the buffer is not on proper alignment.
433 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
438 EmuBlockIoWriteBlocks (
439 IN EMU_BLOCK_IO_PROTOCOL
*This
,
442 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
447 EMU_BLOCK_IO_PRIVATE
*Private
;
452 Private
= EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
454 Status
= EmuBlockIoReadWriteCommon (Private
, MediaId
, LBA
, BufferSize
, Buffer
, "UnixWriteBlocks");
455 if (EFI_ERROR (Status
)) {
459 len
= write (Private
->fd
, Buffer
, BufferSize
);
460 if (len
!= BufferSize
) {
461 DEBUG ((EFI_D_INIT
, "ReadBlocks: WriteFile failed.\n"));
462 Status
= EmuBlockIoError (Private
);
467 // If the write succeeded, we are not write protected and media is present.
469 Private
->Media
->MediaPresent
= TRUE
;
470 Private
->Media
->ReadOnly
= FALSE
;
471 Status
= EFI_SUCCESS
;
475 if (Token
->Event
!= NULL
) {
476 // Caller is responcible for signaling EFI Event
477 Token
->TransactionStatus
= Status
;
487 Flush the Block Device.
489 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
490 is returned and non-blocking I/O is being used, the Event associated with
491 this request will not be signaled.
493 @param[in] This Indicates a pointer to the calling context.
494 @param[in,out] Token A pointer to the token associated with the transaction
496 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
497 All outstanding data was written correctly to the
498 device if the Event is NULL.
499 @retval EFI_DEVICE_ERROR The device reported an error while writting back
501 @retval EFI_WRITE_PROTECTED The device cannot be written to.
502 @retval EFI_NO_MEDIA There is no media in the device.
503 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
504 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
509 EmuBlockIoFlushBlocks (
510 IN EMU_BLOCK_IO_PROTOCOL
*This
,
511 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
514 EMU_BLOCK_IO_PRIVATE
*Private
;
516 Private
= EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
518 if (Private
->fd
>= 0) {
520 Private
->fd
= open (Private
->Filename
, Private
->Mode
, 0644);
524 if (Token
->Event
!= NULL
) {
525 // Caller is responcible for signaling EFI Event
526 Token
->TransactionStatus
= EFI_SUCCESS
;
536 Reset the block device hardware.
538 @param[in] This Indicates a pointer to the calling context.
539 @param[in] ExtendedVerification Indicates that the driver may perform a more
540 exhausive verfication operation of the device
543 @retval EFI_SUCCESS The device was reset.
544 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
550 IN EMU_BLOCK_IO_PROTOCOL
*This
,
551 IN BOOLEAN ExtendedVerification
556 Reset the Block Device.
559 This - Protocol instance pointer.
560 ExtendedVerification - Driver may perform diagnostics on reset.
563 EFI_SUCCESS - The device was reset.
564 EFI_DEVICE_ERROR - The device is not functioning properly and could
569 EMU_BLOCK_IO_PRIVATE
*Private
;
571 Private
= EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
573 if (Private
->fd
>= 0) {
583 StdDupUnicodeToAscii (
591 Size
= StrLen (Str
) + 1;
592 Ascii
= malloc (Size
);
597 for (Ptr
= Ascii
; *Str
!= '\0'; Ptr
++, Str
++) {
606 EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol
= {
607 GasketEmuBlockIoReset
,
608 GasketEmuBlockIoReadBlocks
,
609 GasketEmuBlockIoWriteBlocks
,
610 GasketEmuBlockIoFlushBlocks
,
611 GasketEmuBlockIoCreateMapping
615 EmuBlockIoThunkOpen (
616 IN EMU_IO_THUNK_PROTOCOL
*This
619 EMU_BLOCK_IO_PRIVATE
*Private
;
622 if (This
->Private
!= NULL
) {
623 return EFI_ALREADY_STARTED
;
626 if (!CompareGuid (This
->Protocol
, &gEmuBlockIoProtocolGuid
)) {
627 return EFI_UNSUPPORTED
;
630 Private
= malloc (sizeof (EMU_BLOCK_IO_PRIVATE
));
631 if (Private
== NULL
) {
632 return EFI_OUT_OF_RESOURCES
;
636 Private
->Signature
= EMU_BLOCK_IO_PRIVATE_SIGNATURE
;
637 Private
->Thunk
= This
;
638 CopyMem (&Private
->EmuBlockIo
, &gEmuBlockIoProtocol
, sizeof (gEmuBlockIoProtocol
));
641 Private
->Filename
= StdDupUnicodeToAscii (This
->ConfigString
);
642 if (Private
->Filename
== NULL
) {
643 return EFI_OUT_OF_RESOURCES
;
646 Str
= strstr (Private
->Filename
, ":");
648 Private
->RemovableMedia
= FALSE
;
649 Private
->WriteProtected
= FALSE
;
651 for (*Str
++ = '\0'; *Str
!= 0; Str
++) {
652 if (*Str
== 'R' || *Str
== 'F') {
653 Private
->RemovableMedia
= (BOOLEAN
) (*Str
== 'R');
655 if (*Str
== 'O' || *Str
== 'W') {
656 Private
->WriteProtected
= (BOOLEAN
) (*Str
== 'O');
661 Private
->BlockSize
= 512;
663 This
->Interface
= &Private
->EmuBlockIo
;
664 This
->Private
= Private
;
670 EmuBlockIoThunkClose (
671 IN EMU_IO_THUNK_PROTOCOL
*This
674 EMU_BLOCK_IO_PRIVATE
*Private
;
676 if (!CompareGuid (This
->Protocol
, &gEmuBlockIoProtocolGuid
)) {
677 return EFI_UNSUPPORTED
;
680 Private
= This
->Private
;
682 if (This
->Private
!= NULL
) {
683 if (Private
->Filename
!= NULL
) {
684 free (Private
->Filename
);
686 free (This
->Private
);
694 EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo
= {
695 &gEmuBlockIoProtocolGuid
,
699 GasketBlockIoThunkOpen
,
700 GasketBlockIoThunkClose
,