diff options
Diffstat (limited to 'Core/CORE_DXE/DiskIo.c')
-rw-r--r-- | Core/CORE_DXE/DiskIo.c | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/Core/CORE_DXE/DiskIo.c b/Core/CORE_DXE/DiskIo.c new file mode 100644 index 0000000..a9476cd --- /dev/null +++ b/Core/CORE_DXE/DiskIo.c @@ -0,0 +1,978 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//***************************************************************************** +// $Header: /Alaska/SOURCE/Core/EDK/DxeMain/DiskIo.c 27 8/12/11 12:23p Artems $ +// +// $Revision: 27 $ +// +// $Date: 8/12/11 12:23p $ +//***************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Core/EDK/DxeMain/DiskIo.c $ +// +// 27 8/12/11 12:23p Artems +// EIP 64107: Added changes for module to be compliant with UEFI +// specification v 2.3.1 +// +// 26 2/05/11 4:10p Artems +// Removed previous check-in changes +// +// 25 1/06/11 5:52p Oleksiyy +// [TAG] EIP28607 +// [Category] Improvement +// [Description] System was hanging for some time if Floppy Media +// removed while writing in meda in progress. +// EFI_TPL_CALLBACK priority level rised during media related calls. +// [Files] DiskIo.c, Info.c, MediaAccess.c, Open.c, Partition.c +// +// 24 8/27/09 5:21p Felixp +// +// 23 8/27/09 4:40p Felixp +// +// 20 8/21/09 4:29p Felixp +// Component Name protocol implementation is upadted to support both +// ComponentName and ComponentName2 protocols +// (based on value of the EFI_SPECIFICATION_VERSION SDL token). +// +// 19 7/08/09 5:54p Vyacheslava +// Updated according to the coding standards. +// +// 18 4/24/07 4:10p Robert +// Updated headers to be compliant with the CHM Help Builder +// +// 17 4/19/07 12:57p Felixp +// Minor bug fix in handling of media not present in ReadDiskIo (along +// with IdeBus.c changes resolves SCT failure) +// +// 15 4/16/07 6:29p Felixp +// Fix: proper handling of media not present in ReadDiskIo +// +// 14 8/24/06 10:11a Felixp +// x64 support: warning/error fixes +// +// 11 10/28/05 9:03p Felixp +// bug fix in CalcAlignmentValues +// +// 10 10/28/05 2:03p Felixp +// bug fix in WriteDiskIo for the case when AboveAlign is not zero. +// + +// 5 2/14/05 4:10p Felixp +// Small bug fix in ReadDiskIo (success returned in case of error) +// +// 4 2/11/05 6:09p Felixp +// - optimizations (both code size and speed) +// - SCT failure fixed +// +// 2 2/07/05 6:05p Felixp +// Small bug fix in ReadDiskIo and WriteDiskIo +// +//***************************************************************************** +//<AMI_FHDR_START> +// +// Name: Disko.c +// +// Description: EFI Disk Io Generic Driver. +// +//<AMI_FHDR_END> +//***************************************************************************** +#include <Protocol/DiskIo.h> +#include <Protocol/BlockIo.h> +#include <Protocol/DevicePath.h> +#include <Protocol/DriverBinding.h> +#include <Protocol/ComponentName2.h> +#include <AmiDxeLib.h> + +#ifndef EFI_COMPONENT_NAME2_PROTOCOL_GUID //old Core +#ifndef LANGUAGE_CODE_ENGLISH +#define LANGUAGE_CODE_ENGLISH "eng" +#endif +static BOOLEAN LanguageCodesEqual( + CONST CHAR8* LangCode1, CONST CHAR8* LangCode2 +){ + return LangCode1[0]==LangCode2[0] + && LangCode1[1]==LangCode2[1] + && LangCode1[2]==LangCode2[2]; +} +static EFI_GUID gEfiComponentName2ProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID; +#endif +//---------------------------------------------------------------------------- +// Function Prototypes +EFI_STATUS EFIAPI DiskIoSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +); + +EFI_STATUS EFIAPI DiskIoStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +); + +EFI_STATUS EFIAPI DiskIoStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer +); + +EFI_STATUS ReadDiskIo ( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + OUT VOID *Buffer +); + +EFI_STATUS WriteDiskIo ( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + IN VOID *Buffer +); + +//---------------------------------------------------------------------------- +// Data types +typedef struct _DISK_IO_DATA { + EFI_DISK_IO_PROTOCOL DiskIo; + EFI_BLOCK_IO_PROTOCOL *BlockIo; +} DISK_IO_DATA; + +//---------------------------------------------------------------------------- +// GUID Definitions +static EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID; +static EFI_GUID gEfiDiskIoProtocolGuid = EFI_DISK_IO_PROTOCOL_GUID; +static EFI_GUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID; + +//---------------------------------------------------------------------------- +// Module Scope Glo=bal Variables + +EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBindingProtocol = { + DiskIoSupported, + DiskIoStart, + DiskIoStop, + 0x10, + NULL, + NULL +}; + +DISK_IO_DATA gDiskIoData = { + { + EFI_DISK_IO_PROTOCOL_REVISION, + ReadDiskIo, + WriteDiskIo + }, + NULL +}; + +static EFI_BOOT_SERVICES *gBS = NULL; + +//---------------------------------------------------------------------------- +//Driver Name + +#ifdef EFI_DEBUG +static UINT16 *gDriverName = L"AMI Disk I/O Driver"; + +//---------------------------------------------------------------------------- +// Function Definitions + +//<AMI_PHDR_START> +//-------------------------------------------------------------------------- +// +// Procedure: ComponentNameGetControllerName +// +// DESCRIPTION: Retrieves a Unicode string that is the user readable name of +// the controller that is being managed by an EFI Driver. +// +// Input: +// This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL +// instance. +// ControllerHandle - The handle of a controller that the driver specified +// by This is managing. This handle specifies the controller whose +// name is to be returned. +// ChildHandle - The handle of the child controller to retrieve the name +// of. This is an optional parameter that may be NULL. It will be +// NULL for device drivers. It will also be NULL for a bus drivers +// that wish to retrieve the name of the bus controller. It will +// not be NULL for a bus driver that wishes to retrieve the name of +// a child controller. +// Language - A pointer to a three character ISO 639-2 language identifier. +// This is the language of the controller name that that the caller +// is requesting, and it must match one of the languages specified +// in Supported Languages. The number of languages supported by a +// driver is up to the driver writer. +// +// Output: +// ControllerName - A pointer to the Unicode string to return. This +// Unicode string is the name of the controller specified by +// ControllerHandle and ChildHandle in the language specified by +// Language from the point of view of thedriver specified by This. +// +// RETURNS: +// EFI_SUCCESS - The Unicode string for the user readable name in the +// language specified by Language for the driver specified by This +// was returned in DriverName. +// EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. +// EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid +// EFI_HANDLE. +// EFI_INVALID_PARAMETER - Language is NULL. +// EFI_INVALID_PARAMETER - ControllerName is NULL. +// EFI_UNSUPPORTED - The driver specified by This is not currently +// managing the controller specified by ControllerHandle and +// ChildHandle. +// EFI_UNSUPPORTED - The driver specified by This does not support the +// language specified by Language. +// +//-------------------------------------------------------------------------- +//<AMI_PHDR_END> + +static EFI_STATUS ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName ) +{ + return EFI_UNSUPPORTED; +} + +//<AMI_PHDR_START> +//-------------------------------------------------------------------------- +// Procedure: ComponentNameGetDriverName +// +// Description: Returns the Driver Name if the language is supported +// +// Input: +// This - Pointer to the instance of this driver +// Language - Current operating language +// DriverName - return parameter that will contain the Driver's Name +// +// Output: DriverName - return parameter that will contain the Driver's Name +// +// Returns: +// EFI_SUCCESS - Driver loaded +// EFI_INVALID_PARAMETER - If the Language or DriverName variable is +// not defined +// EFI_UNSUPPORTED - If the current laungage is not supported +//-------------------------------------------------------------------------- +//<AMI_PHDR_END> + +static EFI_STATUS ComponentNameGetDriverName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName ) +{ + //Supports only English + if (!Language || !DriverName) + return EFI_INVALID_PARAMETER; + + if ( !LanguageCodesEqual( Language, LANGUAGE_CODE_ENGLISH) ) + return EFI_UNSUPPORTED; + else + *DriverName = gDriverName; + + return EFI_SUCCESS; +} + +//Component Name Protocol +static EFI_COMPONENT_NAME2_PROTOCOL gComponentName = { + ComponentNameGetDriverName, + ComponentNameGetControllerName, + LANGUAGE_CODE_ENGLISH +}; + +#endif + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: DiskIoEntryPoint +// +// Description: Installs the Driver Binding Protocol for the Disk +// I/O Driver +// +// Input: +// ImageHandle - Identification Handle for the Disk I/O driver +// *SystemTable - Pointer to the EFI System Handle +// +// Output: +// EFI_SUCCESS - if the Binding Protocol is installed +// +// +// Modified: +// +// Referrals: InstallMultipleProtocolInterfaces +// +// Notes: +// Here is the control flow of this function: +// 1. Initialize Ami Lib. +// 2. Install Driver Binding Protocol +// 3. Return EFI_SUCCESS. +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS DiskIoEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + + // Initialize global variable for use in this driver + gBS = SystemTable->BootServices; + + // initiaize the ImageHandle and DriverBindingHandle + gDiskIoDriverBindingProtocol.DriverBindingHandle = NULL; + gDiskIoDriverBindingProtocol.ImageHandle = ImageHandle; + + Status = gBS->InstallMultipleProtocolInterfaces( + &gDiskIoDriverBindingProtocol.DriverBindingHandle, + &gEfiDriverBindingProtocolGuid, + &gDiskIoDriverBindingProtocol, +#ifdef EFI_DEBUG + &gEfiComponentName2ProtocolGuid, + &gComponentName, +#endif + NULL + ); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: DiskIoSupported +// +// Description: Checks whether Block I/O protocol is installed on the +// Controller +// +// Input: +// *This - pointer to the Briver Binding instance of the +// Disk I/O Protocol +// Controller - The Controller that is looking for drivers that +// operate on it +// *RemainingDevicePath - +// +// Output: +// EFI_SUCCESS - Driver supports the Controller that is passed in +// EFI_UNSUPPORTED - The Driver Does not support the Controller +// that is passed in +// +// Referrals: OpenProtocol CloseProtocol +// +// Notes: +// Here is the control flow of this function: +// 1. Check whether Block I/O driver is installed and not being used +// by another driver +// 2. Return EFI_SUCCESS or EFI_UNSUPPORTED +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI DiskIoSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + + // Check to see if the BlockIo Protocol in installed on the ControllerHandle + // if so, CloseProtocol and return success, otherwise exit with an error + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + (VOID**)&BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR(Status)) + return Status; + + return gBS->CloseProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: DiskIoStart +// +// Description: Installs DiskIo Protocol on the Controller +// +// Input: +// *This - Pointer to an instance of the Disk I/O protocol +// Controller - The controller being operated on +// *RemainingDevicePath - +// +// Output: +// EFI_SUCCESS - if Driver was installed properly +// Errors - Returns any error that would cause the protocol not +// to be installed +// +// Referrals: OpenProtocol CloseProtocol InstallProtocolInterface +// AllocatePool CopyMem FreePool +// +// Notes: +// Here is the control flow of this function: +// 1. Open the Block I/O protocol BY_DRIVER +// 2. Allocate memory for the new instance of the Disk I/O Data Structure +// 3. Copy the Default Data into the newly allocated memory +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI DiskIoStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +) +{ + EFI_STATUS Status; + DISK_IO_DATA *DiskIo; + + // make sure that the controller handle has the BlockIo Protocol installed on it + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + (VOID**)&gDiskIoData.BlockIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + // If not error out + if (EFI_ERROR (Status)) + return Status; + + // Allocate memory for the private data structure for the instance of the driver + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(DISK_IO_DATA), + &DiskIo + ); + + // if no memory is available, exit with error + if (EFI_ERROR(Status)) + return Status; + + // copy the corrct data into it + gBS->CopyMem( + DiskIo, + &gDiskIoData, + sizeof(DISK_IO_DATA) + ); + + // Install the Protocol on the handle if it has a BlockIo Protocol alread installed + Status = gBS->InstallProtocolInterface( + &ControllerHandle, + &gEfiDiskIoProtocolGuid, + EFI_NATIVE_INTERFACE, + &DiskIo->DiskIo + ); + + // If there is an error when installing the protocol, reverse everything that was done + if (EFI_ERROR(Status)) { + gBS->FreePool(DiskIo); + gBS->CloseProtocol( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: DiskIoStop +// +// Description: Uninstalls DiskIo Protocol on the Controller +// +// Input: +// *This - Pointer to an instance of the Disk I/O protocol +// Controller - The controller being operated on +// *RemainingDevicePath - +// +// Output: +// EFI_SUCCESS - if Driver was Uninstalled properly +// EFI_UNSUPPORTED - Disk I/O was not installed on the Controller +// Errors - Returns any error that would cause the protocol not +// to be installed +// +// Referrals: OpenProtocol CloseProtocol UnInstallProtocolInterface +// FreePool +// +// Notes: +// Here is the control flow of this function: +// 1. Open the Disk I/O protocol by GET_DERIVER +// 2. Uninstall the protocol +// 3. Free the allocated Memory +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI DiskIoStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer +) +{ + EFI_STATUS Status; + EFI_DISK_IO_PROTOCOL *DiskIoProtocol; + DISK_IO_DATA *DiskIo; + + // Unistall all protocols installed installed in DriverBindingStart + // open the disk Io protocol + Status = gBS->OpenProtocol( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + (VOID**)&DiskIoProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) + return EFI_UNSUPPORTED; + + // Find the pointer to the parent structure + // in this case, DiskIo is the first element in the data structure + DiskIo = (DISK_IO_DATA*)DiskIoProtocol; + + // Uninstall the protocol interface + Status = gBS->UninstallProtocolInterface( + ControllerHandle, + &gEfiDiskIoProtocolGuid, + &DiskIo->DiskIo + ); + + // if the interface is uninstalled then close the protocol + if (!EFI_ERROR (Status)) { + Status = gBS->CloseProtocol( + ControllerHandle, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + } + + // if the protocol is closed, then free the data structure + if (!EFI_ERROR (Status)) + Status = gBS->FreePool(DiskIo); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: CalcAlignmentValues +// +// Description: Calculates FirstBlock, Numblocks, and the amount +// of data above and below an alignment value +// +// Input: +// *Media - pointer to the media data structure that is being +// operated on +// Offset - byte value that is the offset into the media that +// indicates where the buffer starts +// BufferSize - Size of the entire buffer to read +// +// Output: +// *BelowAlign - Number of bytes below an aligned value where +// the Buffer starts +// *AboveAlign - Number of bytes above an aligned value where +// the Buffer ends +// *FirstBlock - First block that needs to be read to get the +// entire buffer +// *NumBlocks - number of blocks to be read +// +// Return: VOID +// +// Referrals: Div64 +// +// Notes: +// Here is the control flow of this function: +// 1. Calculate the first block of the media to read +// 2. calculate the number of blocks to read +// 3. Check for any data area that is ablove the final aligned block +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID CalcAlignmentValues( + IN EFI_BLOCK_IO_MEDIA *Media, + IN UINT64 Offset, + IN UINT64 BufferSize, + OUT UINTN *BelowAlign, + OUT UINTN *AboveAlign, + OUT UINT64 *FirstBlock, + OUT UINT64 *NumBlocks +) +{ + UINT64 Temp; + + // Find out if the Offset is aligned and the remainder if it is not + // use 64 bit division function + *FirstBlock = Div64( + Offset, + Media->BlockSize, + BelowAlign + ); + + // Find out if the ending point is aligned and the remainder if it is not + // use 64 bit division function + Temp = Div64( + Offset + BufferSize, + Media->BlockSize, + AboveAlign + ); + + // Calculate the total number of blocks to be read/written + *NumBlocks = Temp - *FirstBlock; + + if (*AboveAlign) + (*NumBlocks)++; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: ReadDiskIo +// +// Description: Reads the data from the media specified by the parameters +// that are passed in +// +// Input: +// *This - Pointer to the Disk I/O protocol instance +// MediaId - media ID of the device to read from +// Offset - byte offset where to start reading +// BufferSize - amount of data to read +// +// Output: +// *Buffer - location to store the data read from the media +// +// Return: +// EFI_SUCCESS - Function Read the Buffer properly or BufferSize = 0 +// EFI_MEDIA_CHANGED - Media changed since last operation +// EFI_INVALID_PARAMETER - Buffer does not fit within the Media +// +// Referrals: Mul64 AllocatePool CalcAlignmentValues CopyMem +// FreePool BlockIo->ReadBlock +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS ReadDiskIo ( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + OUT VOID *Buffer +) +{ + DISK_IO_DATA *Container; + UINT64 StartBlock = 0; + UINT64 NumBlocks = 0; + UINTN BelowAlign = 0; + UINTN AboveAlign = 0; + UINT32 IoAlign; + UINTN Temp; + UINT8 *DataBuffer, *AlignDataBuffer; + UINT32 BlockSize; + EFI_STATUS Status; + + // Get the pointer to the Container Structure + // DiskIo is the first element of the Data Structure + // also define some variables for easier access + Container = (DISK_IO_DATA*)This; + BlockSize = Container->BlockIo->Media->BlockSize; + IoAlign = Container->BlockIo->Media->IoAlign; + + // Error Check values here + if (Container->BlockIo->Media->MediaPresent) { + if (Container->BlockIo->Media->MediaId != MediaId) + return EFI_MEDIA_CHANGED; + + if ( Offset + BufferSize > Mul64(Container->BlockIo->Media->LastBlock + 1, BlockSize) ) + return EFI_INVALID_PARAMETER; + } + + if (!BufferSize) + return EFI_SUCCESS; + + if (!BlockSize) + return EFI_INVALID_PARAMETER; + + // find the needed data + CalcAlignmentValues( + Container->BlockIo->Media, + Offset, + BufferSize, + &BelowAlign, + &AboveAlign, + &StartBlock, + &NumBlocks + ); + + // Allocate a buffer for use in pulling data out of selected blocks + // Size is generated by total number of blocks to be read plus the IoAlignment + // value so that the buffer will have plenty of space in it if needed + Temp = BlockSize * (UINTN)NumBlocks; + + if ( Temp>BufferSize || IoAlign && ( (UINTN)Buffer & (IoAlign - 1) ) ) { + if (IoAlign > 1) + Temp += IoAlign; + + Status = gBS->AllocatePool( + EfiBootServicesData, + Temp, + &DataBuffer + ); + + // No buffer allocated: exit, no need to free the memory + if (Status != EFI_SUCCESS) + return EFI_OUT_OF_RESOURCES; + + AlignDataBuffer = (IoAlign <= 1) ? + DataBuffer : DataBuffer + IoAlign - ( (UINTN)DataBuffer & (IoAlign - 1) ); + + } else + AlignDataBuffer = Buffer; + + Status = Container->BlockIo->ReadBlocks( + Container->BlockIo, + MediaId, + StartBlock, + BlockSize * (UINTN)NumBlocks, + AlignDataBuffer + ); + + if (AlignDataBuffer != Buffer) { + gBS->CopyMem( + Buffer, + AlignDataBuffer + BelowAlign, + BufferSize + ); + gBS->FreePool(DataBuffer); + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// +// Procedure: WriteDiskIo +// +// Description: Writes the data to the media specified by the parameters +// that are passed in +// +// Input: +// *This - Pointer to the Disk I/O protocol instance +// MediaId - media ID of the device to write to +// Offset - byte offset where to start wrtiing +// BufferSize - amount of data to write +// +// Output: +// *Buffer - location of data that should be written to the media +// +// Return: +// EFI_SUCCESS - Function wrote the Buffer properly or BufferSize = 0 +// EFI_MEDIA_CHANGED - Media changed since last operation +// EFI_INVALID_PARAMETER - Buffer does not fit within the Media +// +// Referrals: Mul64 AllocatePool CalcAlignmentValues CopyMem +// FreePool BlockIo->ReadBlocks BlockIo->WriteBlocks +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS WriteDiskIo ( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + IN VOID *Buffer +) +{ + DISK_IO_DATA *Container; + UINT64 StartBlock = 0; + UINT64 NumBlocks = 0; + UINTN BelowAlign = 0; + UINTN AboveAlign = 0; + UINTN IoAlign; + UINT8 *DataBuffer, *AlignDataBuffer; + UINT32 BlockSize; + EFI_STATUS Status; + UINTN Temp; + + // Get the pointer to the Container Structure + // DiskIo is the first element of the Data Structure + // also define some variables for easier access + Container = (DISK_IO_DATA*)This; + BlockSize = Container->BlockIo->Media->BlockSize; + IoAlign = Container->BlockIo->Media->IoAlign; + + // Error Check values here + if (Container->BlockIo->Media->MediaId != MediaId) + return EFI_MEDIA_CHANGED; + + if ( Offset + BufferSize > Mul64(Container->BlockIo->Media->LastBlock + 1, BlockSize) ) + return EFI_INVALID_PARAMETER; + + if (!BufferSize) + return EFI_SUCCESS; + + // find the needed data + CalcAlignmentValues( + Container->BlockIo->Media, + Offset, + BufferSize, + &BelowAlign, + &AboveAlign, + &StartBlock, + &NumBlocks + ); + + // Allocate a buffer for use in pulling data out of selected blocks + // Size is generated by total number of blocks to be read plus the IoAlignment + // value so that the buffer will have plenty of space in it if needed + Temp = BlockSize * (UINTN)NumBlocks; + + if ( Temp>BufferSize || IoAlign && ( (UINTN)Buffer & (IoAlign - 1) ) ) { + if (IoAlign > 1) + Temp += IoAlign; + + Status = gBS->AllocatePool( + EfiBootServicesData, + Temp, + &DataBuffer + ); + + // No buffer allocated: exit, no need to free the memory + if (Status != EFI_SUCCESS) + return EFI_OUT_OF_RESOURCES; + + AlignDataBuffer = (IoAlign <= 1) ? + DataBuffer : DataBuffer + IoAlign - ( (UINTN)DataBuffer & (IoAlign - 1) ); + + } else { + + Status = Container->BlockIo->WriteBlocks( + Container->BlockIo, + MediaId, + StartBlock, + BufferSize, + Buffer + ); + return Status; + } + + if ( AboveAlign && (NumBlocks > 1 || !BelowAlign) ) { + // Read the block that contains the data at the beginning of the block + Status = Container->BlockIo->ReadBlocks( + Container->BlockIo, + MediaId, + StartBlock + NumBlocks - 1, + BlockSize, + AlignDataBuffer + ); + + // Check to see if the BlockIo protocol reported an error + if (Status != EFI_SUCCESS) { + gBS->FreePool(DataBuffer); + return Status; + } + + // just copy the data above the alignment address, not the complete block + gBS->CopyMem( + AlignDataBuffer + (UINTN)(NumBlocks - 1) * BlockSize + AboveAlign, + AlignDataBuffer + AboveAlign, + BlockSize - AboveAlign + ); + } + + // see if we need to only pull the data from the end of a block + if (BelowAlign) { + // read the block that contains the data at the end of the block + // Advance StartBlock to the next block after reading the current block + Status = Container->BlockIo->ReadBlocks( + Container->BlockIo, + MediaId, + StartBlock, + BlockSize, + AlignDataBuffer + ); + + + // Check to see if the BlockIo protocol reported an error + if (Status != EFI_SUCCESS) { + gBS->FreePool(DataBuffer); + return Status; + } + } + + // Copy that data to allocated memory + gBS->CopyMem( + AlignDataBuffer + BelowAlign, + Buffer, + BufferSize + ); + + // Write full blocks of data from the block I/O driver + Status = Container->BlockIo->WriteBlocks( + Container->BlockIo, + MediaId, + StartBlock, + (UINTN)NumBlocks * BlockSize, + AlignDataBuffer + ); + + // Free allocated memory + gBS->FreePool(DataBuffer); + return Status; +} + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* |