+++ /dev/null
-/** @file\r
- DiskIo driver that layers it's self on every Block IO protocol in the system.\r
- DiskIo converts a block oriented device to a byte oriented device.\r
-\r
- ReadDisk may have to do reads that are not aligned on sector boundaries.\r
- There are three cases:\r
- UnderRun - The first byte is not on a sector boundary or the read request is\r
- less than a sector in length.\r
- Aligned - A read of N contiguous sectors.\r
- OverRun - The last byte is not on a sector boundary.\r
-\r
- Copyright (c) 2006 - 2007, Intel Corporation \r
- All rights reserved. This program and the accompanying materials \r
- are licensed and made available under the terms and conditions of the BSD License \r
- which accompanies this distribution. The full text of the license may be found at \r
- http://opensource.org/licenses/bsd-license.php \r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
-\r
-**/\r
-\r
-#include "DiskIo.h"\r
-\r
-EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {\r
- DiskIoDriverBindingSupported,\r
- DiskIoDriverBindingStart,\r
- DiskIoDriverBindingStop,\r
- 0xa,\r
- NULL,\r
- NULL\r
-};\r
-\r
-DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {\r
- DISK_IO_PRIVATE_DATA_SIGNATURE,\r
- {\r
- EFI_DISK_IO_PROTOCOL_REVISION,\r
- DiskIoReadDisk,\r
- DiskIoWriteDisk\r
- },\r
- NULL\r
-};\r
-\r
-\r
-/**\r
- Test to see if this driver supports ControllerHandle. \r
-\r
- @param This Protocol instance pointer.\r
- @param ControllerHandle Handle of device to test\r
- @param RemainingDevicePath Optional parameter use to pick a specific child\r
- device to start.\r
-\r
- @retval EFI_SUCCESS This driver supports this device\r
- @retval EFI_ALREADY_STARTED This driver is already running on this device\r
- @retval other This driver does not support this device\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DiskIoDriverBindingSupported (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
-\r
- //\r
- // Open the IO Abstraction(s) needed to perform the supported test.\r
- //\r
- Status = gBS->OpenProtocol (\r
- ControllerHandle,\r
- &gEfiBlockIoProtocolGuid,\r
- (VOID **) &BlockIo,\r
- This->DriverBindingHandle,\r
- ControllerHandle,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Close the I/O Abstraction(s) used to perform the supported test.\r
- //\r
- gBS->CloseProtocol (\r
- ControllerHandle,\r
- &gEfiBlockIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- ControllerHandle\r
- );\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Start this driver on ControllerHandle by opening a Block IO protocol and\r
- installing a Disk IO protocol on ControllerHandle.\r
-\r
- @param This Protocol instance pointer.\r
- @param ControllerHandle Handle of device to bind driver to\r
- @param RemainingDevicePath Optional parameter use to pick a specific child\r
- device to start.\r
-\r
- @retval EFI_SUCCESS This driver is added to ControllerHandle\r
- @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
- @retval other This driver does not support this device\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DiskIoDriverBindingStart (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- DISK_IO_PRIVATE_DATA *Private;\r
-\r
- Private = NULL;\r
-\r
- //\r
- // Connect to the Block IO interface on ControllerHandle.\r
- //\r
- Status = gBS->OpenProtocol (\r
- ControllerHandle,\r
- &gEfiBlockIoProtocolGuid,\r
- (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,\r
- This->DriverBindingHandle,\r
- ControllerHandle,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- \r
- //\r
- // Initialize the Disk IO device instance.\r
- //\r
- Private = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);\r
- if (Private == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ErrorExit;\r
- }\r
- \r
- //\r
- // Install protocol interfaces for the Disk IO device.\r
- //\r
- Status = gBS->InstallProtocolInterface (\r
- &ControllerHandle,\r
- &gEfiDiskIoProtocolGuid,\r
- EFI_NATIVE_INTERFACE,\r
- &Private->DiskIo\r
- );\r
-\r
-ErrorExit:\r
- if (EFI_ERROR (Status)) {\r
-\r
- if (Private != NULL) {\r
- FreePool (Private);\r
- }\r
-\r
- gBS->CloseProtocol (\r
- ControllerHandle,\r
- &gEfiBlockIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- ControllerHandle\r
- );\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Stop this driver on ControllerHandle by removing Disk IO protocol and closing\r
- the Block IO protocol on ControllerHandle.\r
-\r
- @param This Protocol instance pointer.\r
- @param ControllerHandle Handle of device to stop driver on\r
- @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
- children is zero stop the entire bus driver.\r
- @param ChildHandleBuffer List of Child Handles to Stop.\r
-\r
- @retval EFI_SUCCESS This driver is removed ControllerHandle\r
- @retval other This driver was not removed from this device\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DiskIoDriverBindingStop (\r
- IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
- IN EFI_HANDLE ControllerHandle,\r
- IN UINTN NumberOfChildren,\r
- IN EFI_HANDLE *ChildHandleBuffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_DISK_IO_PROTOCOL *DiskIo;\r
- DISK_IO_PRIVATE_DATA *Private;\r
-\r
- //\r
- // Get our context back.\r
- //\r
- Status = gBS->OpenProtocol (\r
- ControllerHandle,\r
- &gEfiDiskIoProtocolGuid,\r
- (VOID **) &DiskIo,\r
- This->DriverBindingHandle,\r
- ControllerHandle,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- Private = DISK_IO_PRIVATE_DATA_FROM_THIS (DiskIo);\r
-\r
- Status = gBS->UninstallProtocolInterface (\r
- ControllerHandle,\r
- &gEfiDiskIoProtocolGuid,\r
- &Private->DiskIo\r
- );\r
- if (!EFI_ERROR (Status)) {\r
-\r
- Status = gBS->CloseProtocol (\r
- ControllerHandle,\r
- &gEfiBlockIoProtocolGuid,\r
- This->DriverBindingHandle,\r
- ControllerHandle\r
- );\r
- }\r
-\r
- if (!EFI_ERROR (Status)) {\r
- FreePool (Private);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-\r
-/**\r
- Read BufferSize bytes from Offset into Buffer.\r
- Reads may support reads that are not aligned on\r
- sector boundaries. There are three cases:\r
- UnderRun - The first byte is not on a sector boundary or the read request is\r
- less than a sector in length.\r
- Aligned - A read of N contiguous sectors.\r
- OverRun - The last byte is not on a sector boundary.\r
-\r
- @param This Protocol instance pointer.\r
- @param MediaId Id of the media, changes every time the media is replaced.\r
- @param Offset The starting byte offset to read from\r
- @param BufferSize Size of Buffer\r
- @param Buffer Buffer containing read data\r
-\r
- @retval EFI_SUCCESS The data was read correctly from the device.\r
- @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
- @retval EFI_NO_MEDIA There is no media in the device.\r
- @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
- @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not\r
- valid for the device.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DiskIoReadDisk (\r
- IN EFI_DISK_IO_PROTOCOL *This,\r
- IN UINT32 MediaId,\r
- IN UINT64 Offset,\r
- IN UINTN BufferSize,\r
- OUT VOID *Buffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- DISK_IO_PRIVATE_DATA *Private;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
- EFI_BLOCK_IO_MEDIA *Media;\r
- UINT32 BlockSize;\r
- UINT64 Lba;\r
- UINT64 OverRunLba;\r
- UINT32 UnderRun;\r
- UINT32 OverRun;\r
- BOOLEAN TransactionComplete;\r
- UINTN WorkingBufferSize;\r
- UINT8 *WorkingBuffer;\r
- UINTN Length;\r
- UINT8 *Data;\r
- UINT8 *PreData;\r
- UINTN IsBufferAligned;\r
- UINTN DataBufferSize;\r
- BOOLEAN LastRead;\r
-\r
- Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This);\r
-\r
- BlockIo = Private->BlockIo;\r
- Media = BlockIo->Media;\r
- BlockSize = Media->BlockSize;\r
-\r
- if (Media->MediaId != MediaId) {\r
- return EFI_MEDIA_CHANGED;\r
- }\r
-\r
- WorkingBuffer = Buffer;\r
- WorkingBufferSize = BufferSize;\r
-\r
- //\r
- // Allocate a temporary buffer for operation\r
- //\r
- DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;\r
-\r
- if (Media->IoAlign > 1) {\r
- PreData = AllocatePool (DataBufferSize + Media->IoAlign);\r
- Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;\r
- } else {\r
- PreData = AllocatePool (DataBufferSize);\r
- Data = PreData;\r
- }\r
-\r
- if (PreData == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
-\r
- Length = BlockSize - UnderRun;\r
- TransactionComplete = FALSE;\r
-\r
- Status = EFI_SUCCESS;\r
- if (UnderRun != 0) {\r
- //\r
- // Offset starts in the middle of an Lba, so read the entire block.\r
- //\r
- Status = BlockIo->ReadBlocks (\r
- BlockIo,\r
- MediaId,\r
- Lba,\r
- BlockSize,\r
- Data\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- if (Length > BufferSize) {\r
- Length = BufferSize;\r
- TransactionComplete = TRUE;\r
- }\r
-\r
- CopyMem (WorkingBuffer, Data + UnderRun, Length);\r
-\r
- WorkingBuffer += Length;\r
-\r
- WorkingBufferSize -= Length;\r
- if (WorkingBufferSize == 0) {\r
- goto Done;\r
- }\r
-\r
- Lba += 1;\r
- }\r
-\r
- OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);\r
-\r
- if (!TransactionComplete && WorkingBufferSize >= BlockSize) {\r
- //\r
- // If the DiskIo maps directly to a BlockIo device do the read.\r
- //\r
- if (OverRun != 0) {\r
- WorkingBufferSize -= OverRun;\r
- }\r
- //\r
- // Check buffer alignment\r
- //\r
- IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);\r
-\r
- if (Media->IoAlign <= 1 || IsBufferAligned == 0) {\r
- //\r
- // Alignment is satisfied, so read them together\r
- //\r
- Status = BlockIo->ReadBlocks (\r
- BlockIo,\r
- MediaId,\r
- Lba,\r
- WorkingBufferSize,\r
- WorkingBuffer\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- WorkingBuffer += WorkingBufferSize;\r
-\r
- } else {\r
- //\r
- // Use the allocated buffer instead of the original buffer\r
- // to avoid alignment issue.\r
- // Here, the allocated buffer (8-byte align) can satisfy the alignment\r
- //\r
- LastRead = FALSE;\r
- do {\r
- if (WorkingBufferSize <= DataBufferSize) {\r
- //\r
- // It is the last calling to readblocks in this loop\r
- //\r
- DataBufferSize = WorkingBufferSize;\r
- LastRead = TRUE;\r
- }\r
-\r
- Status = BlockIo->ReadBlocks (\r
- BlockIo,\r
- MediaId,\r
- Lba,\r
- DataBufferSize,\r
- Data\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- CopyMem (WorkingBuffer, Data, DataBufferSize);\r
- WorkingBufferSize -= DataBufferSize;\r
- WorkingBuffer += DataBufferSize;\r
- Lba += DATA_BUFFER_BLOCK_NUM;\r
- } while (!LastRead);\r
- }\r
- }\r
-\r
- if (!TransactionComplete && OverRun != 0) {\r
- //\r
- // Last read is not a complete block.\r
- //\r
- Status = BlockIo->ReadBlocks (\r
- BlockIo,\r
- MediaId,\r
- OverRunLba,\r
- BlockSize,\r
- Data\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- CopyMem (WorkingBuffer, Data, OverRun);\r
- }\r
-\r
-Done:\r
- if (PreData != NULL) {\r
- FreePool (PreData);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Read BufferSize bytes from Offset into Buffer.\r
- Writes may require a read modify write to support writes that are not\r
- aligned on sector boundaries. There are three cases:\r
- UnderRun - The first byte is not on a sector boundary or the write request\r
- is less than a sector in length. Read modify write is required.\r
- Aligned - A write of N contiguous sectors.\r
- OverRun - The last byte is not on a sector boundary. Read modified write\r
- required.\r
-\r
- @param This Protocol instance pointer.\r
- @param MediaId Id of the media, changes every time the media is replaced.\r
- @param Offset The starting byte offset to read from\r
- @param BufferSize Size of Buffer\r
- @param Buffer Buffer containing read data\r
-\r
- @retval EFI_SUCCESS The data was written correctly to the device.\r
- @retval EFI_WRITE_PROTECTED The device can not be written to.\r
- @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
- @retval EFI_NO_MEDIA There is no media in the device.\r
- @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
- @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not\r
- valid for the device.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DiskIoWriteDisk (\r
- IN EFI_DISK_IO_PROTOCOL *This,\r
- IN UINT32 MediaId,\r
- IN UINT64 Offset,\r
- IN UINTN BufferSize,\r
- IN VOID *Buffer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- DISK_IO_PRIVATE_DATA *Private;\r
- EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
- EFI_BLOCK_IO_MEDIA *Media;\r
- UINT32 BlockSize;\r
- UINT64 Lba;\r
- UINT64 OverRunLba;\r
- UINT32 UnderRun;\r
- UINT32 OverRun;\r
- BOOLEAN TransactionComplete;\r
- UINTN WorkingBufferSize;\r
- UINT8 *WorkingBuffer;\r
- UINTN Length;\r
- UINT8 *Data;\r
- UINT8 *PreData;\r
- UINTN IsBufferAligned;\r
- UINTN DataBufferSize;\r
- BOOLEAN LastWrite;\r
-\r
- Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This);\r
-\r
- BlockIo = Private->BlockIo;\r
- Media = BlockIo->Media;\r
- BlockSize = Media->BlockSize;\r
-\r
- if (Media->ReadOnly) {\r
- return EFI_WRITE_PROTECTED;\r
- }\r
-\r
- if (Media->MediaId != MediaId) {\r
- return EFI_MEDIA_CHANGED;\r
- }\r
-\r
- DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;\r
-\r
- if (Media->IoAlign > 1) {\r
- PreData = AllocatePool (DataBufferSize + Media->IoAlign);\r
- Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;\r
- } else {\r
- PreData = AllocatePool (DataBufferSize);\r
- Data = PreData;\r
- }\r
-\r
- if (PreData == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- WorkingBuffer = Buffer;\r
- WorkingBufferSize = BufferSize;\r
-\r
- Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
-\r
- Length = BlockSize - UnderRun;\r
- TransactionComplete = FALSE;\r
-\r
- Status = EFI_SUCCESS;\r
- if (UnderRun != 0) {\r
- //\r
- // Offset starts in the middle of an Lba, so do read modify write.\r
- //\r
- Status = BlockIo->ReadBlocks (\r
- BlockIo,\r
- MediaId,\r
- Lba,\r
- BlockSize,\r
- Data\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- if (Length > BufferSize) {\r
- Length = BufferSize;\r
- TransactionComplete = TRUE;\r
- }\r
-\r
- CopyMem (Data + UnderRun, WorkingBuffer, Length);\r
-\r
- Status = BlockIo->WriteBlocks (\r
- BlockIo,\r
- MediaId,\r
- Lba,\r
- BlockSize,\r
- Data\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- WorkingBuffer += Length;\r
- WorkingBufferSize -= Length;\r
- if (WorkingBufferSize == 0) {\r
- goto Done;\r
- }\r
-\r
- Lba += 1;\r
- }\r
-\r
- OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);\r
-\r
- if (!TransactionComplete && WorkingBufferSize >= BlockSize) {\r
- //\r
- // If the DiskIo maps directly to a BlockIo device do the write.\r
- //\r
- if (OverRun != 0) {\r
- WorkingBufferSize -= OverRun;\r
- }\r
- //\r
- // Check buffer alignment\r
- //\r
- IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);\r
-\r
- if (Media->IoAlign <= 1 || IsBufferAligned == 0) {\r
- //\r
- // Alignment is satisfied, so write them together\r
- //\r
- Status = BlockIo->WriteBlocks (\r
- BlockIo,\r
- MediaId,\r
- Lba,\r
- WorkingBufferSize,\r
- WorkingBuffer\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- WorkingBuffer += WorkingBufferSize;\r
-\r
- } else {\r
- //\r
- // The buffer parameter is not aligned with the request\r
- // So use the allocated instead.\r
- // It can fit almost all the cases.\r
- //\r
- LastWrite = FALSE;\r
- do {\r
- if (WorkingBufferSize <= DataBufferSize) {\r
- //\r
- // It is the last calling to writeblocks in this loop\r
- //\r
- DataBufferSize = WorkingBufferSize;\r
- LastWrite = TRUE;\r
- }\r
-\r
- CopyMem (Data, WorkingBuffer, DataBufferSize);\r
- Status = BlockIo->WriteBlocks (\r
- BlockIo,\r
- MediaId,\r
- Lba,\r
- DataBufferSize,\r
- Data\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- WorkingBufferSize -= DataBufferSize;\r
- WorkingBuffer += DataBufferSize;\r
- Lba += DATA_BUFFER_BLOCK_NUM;\r
- } while (!LastWrite);\r
- }\r
- }\r
-\r
- if (!TransactionComplete && OverRun != 0) {\r
- //\r
- // Last bit is not a complete block, so do a read modify write.\r
- //\r
- Status = BlockIo->ReadBlocks (\r
- BlockIo,\r
- MediaId,\r
- OverRunLba,\r
- BlockSize,\r
- Data\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- CopyMem (Data, WorkingBuffer, OverRun);\r
-\r
- Status = BlockIo->WriteBlocks (\r
- BlockIo,\r
- MediaId,\r
- OverRunLba,\r
- BlockSize,\r
- Data\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- }\r
-\r
-Done:\r
- if (PreData != NULL) {\r
- FreePool (PreData);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- The user Entry Point for module DiskIo. The user code starts with this function.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
- @param[in] SystemTable A pointer to the EFI System Table.\r
- \r
- @retval EFI_SUCCESS The entry point is executed successfully.\r
- @retval other Some error occurs when executing this entry point.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InitializeDiskIo (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Install driver model protocol(s).\r
- //\r
- Status = EfiLibInstallAllDriverProtocols (\r
- ImageHandle,\r
- SystemTable,\r
- &gDiskIoDriverBinding,\r
- ImageHandle,\r
- &gDiskIoComponentName,\r
- NULL,\r
- NULL\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
-\r
- return Status;\r
-}\r
-\r