mirror of https://github.com/acidanthera/audk.git
857 lines
28 KiB
C
857 lines
28 KiB
C
/** @file
|
|
The realization of EFI_RAM_DISK_PROTOCOL.
|
|
|
|
Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
|
|
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "RamDiskImpl.h"
|
|
|
|
RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = {
|
|
RAM_DISK_PRIVATE_DATA_SIGNATURE,
|
|
NULL
|
|
};
|
|
|
|
MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = {
|
|
{
|
|
MEDIA_DEVICE_PATH,
|
|
MEDIA_RAM_DISK_DP,
|
|
{
|
|
(UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)),
|
|
(UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8)
|
|
}
|
|
}
|
|
};
|
|
|
|
BOOLEAN mRamDiskSsdtTableKeyValid = FALSE;
|
|
UINTN mRamDiskSsdtTableKey;
|
|
|
|
|
|
/**
|
|
Initialize the RAM disk device node.
|
|
|
|
@param[in] PrivateData Points to RAM disk private data.
|
|
@param[in, out] RamDiskDevNode Points to the RAM disk device node.
|
|
|
|
**/
|
|
VOID
|
|
RamDiskInitDeviceNode (
|
|
IN RAM_DISK_PRIVATE_DATA *PrivateData,
|
|
IN OUT MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode
|
|
)
|
|
{
|
|
WriteUnaligned64 (
|
|
(UINT64 *) &(RamDiskDevNode->StartingAddr[0]),
|
|
(UINT64) PrivateData->StartingAddr
|
|
);
|
|
WriteUnaligned64 (
|
|
(UINT64 *) &(RamDiskDevNode->EndingAddr[0]),
|
|
(UINT64) PrivateData->StartingAddr + PrivateData->Size - 1
|
|
);
|
|
CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid);
|
|
RamDiskDevNode->Instance = PrivateData->InstanceNumber;
|
|
}
|
|
|
|
|
|
/**
|
|
Initialize and publish NVDIMM root device SSDT in ACPI table.
|
|
|
|
@retval EFI_SUCCESS The NVDIMM root device SSDT is published.
|
|
@retval Others The NVDIMM root device SSDT is not published.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RamDiskPublishSsdt (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_ACPI_DESCRIPTION_HEADER *Table;
|
|
UINTN SectionInstance;
|
|
UINTN TableSize;
|
|
|
|
Status = EFI_SUCCESS;
|
|
SectionInstance = 0;
|
|
|
|
//
|
|
// Scan all the EFI raw section instances in FV to find the NVDIMM root
|
|
// device SSDT.
|
|
//
|
|
while (TRUE) {
|
|
Status = GetSectionFromFv (
|
|
&gEfiCallerIdGuid,
|
|
EFI_SECTION_RAW,
|
|
SectionInstance,
|
|
(VOID **) &Table,
|
|
&TableSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
if (Table->OemTableId == SIGNATURE_64 ('R', 'a', 'm', 'D', 'i', 's', 'k', ' ')) {
|
|
Status = mAcpiTableProtocol->InstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
Table,
|
|
TableSize,
|
|
&mRamDiskSsdtTableKey
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
mRamDiskSsdtTableKeyValid = TRUE;
|
|
}
|
|
|
|
FreePool (Table);
|
|
return Status;
|
|
} else {
|
|
FreePool (Table);
|
|
SectionInstance++;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI
|
|
table.
|
|
|
|
@param[in] PrivateData Points to RAM disk private data.
|
|
|
|
@retval EFI_SUCCESS The RAM disk NFIT has been published.
|
|
@retval others The RAM disk NFIT has not been published.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RamDiskPublishNfit (
|
|
IN RAM_DISK_PRIVATE_DATA *PrivateData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
|
|
UINTN TableIndex;
|
|
VOID *TableHeader;
|
|
EFI_ACPI_TABLE_VERSION TableVersion;
|
|
UINTN TableKey;
|
|
EFI_ACPI_DESCRIPTION_HEADER *NfitHeader;
|
|
EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE
|
|
*SpaRange;
|
|
VOID *Nfit;
|
|
UINT32 NfitLen;
|
|
UINTN MemoryMapSize;
|
|
UINTN MapKey;
|
|
UINTN DescriptorSize;
|
|
UINT32 DescriptorVersion;
|
|
UINT64 CurrentData;
|
|
UINT8 Checksum;
|
|
BOOLEAN MemoryFound;
|
|
|
|
//
|
|
// Get the EFI memory map.
|
|
//
|
|
MemoryMapSize = 0;
|
|
MemoryMap = NULL;
|
|
MemoryFound = FALSE;
|
|
|
|
Status = gBS->GetMemoryMap (
|
|
&MemoryMapSize,
|
|
MemoryMap,
|
|
&MapKey,
|
|
&DescriptorSize,
|
|
&DescriptorVersion
|
|
);
|
|
ASSERT (Status == EFI_BUFFER_TOO_SMALL);
|
|
do {
|
|
MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
|
|
ASSERT (MemoryMap != NULL);
|
|
Status = gBS->GetMemoryMap (
|
|
&MemoryMapSize,
|
|
MemoryMap,
|
|
&MapKey,
|
|
&DescriptorSize,
|
|
&DescriptorVersion
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (MemoryMap);
|
|
}
|
|
} while (Status == EFI_BUFFER_TOO_SMALL);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
MemoryMapEntry = MemoryMap;
|
|
MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
|
|
while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {
|
|
if ((MemoryMapEntry->Type == EfiReservedMemoryType) &&
|
|
(MemoryMapEntry->PhysicalStart <= PrivateData->StartingAddr) &&
|
|
(MemoryMapEntry->PhysicalStart +
|
|
MultU64x32 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SIZE)
|
|
>= PrivateData->StartingAddr + PrivateData->Size)) {
|
|
MemoryFound = TRUE;
|
|
DEBUG ((
|
|
EFI_D_INFO,
|
|
"RamDiskPublishNfit: RAM disk with reserved meomry type, will publish to NFIT.\n"
|
|
));
|
|
break;
|
|
}
|
|
MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
|
|
}
|
|
FreePool (MemoryMap);
|
|
|
|
if (!MemoryFound) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Determine whether there is a NFIT already in the ACPI table.
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
TableIndex = 0;
|
|
TableKey = 0;
|
|
TableHeader = NULL;
|
|
|
|
while (!EFI_ERROR (Status)) {
|
|
Status = mAcpiSdtProtocol->GetAcpiTable (
|
|
TableIndex,
|
|
(EFI_ACPI_SDT_HEADER **)&TableHeader,
|
|
&TableVersion,
|
|
&TableKey
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
TableIndex++;
|
|
|
|
if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==
|
|
EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// A NFIT is already in the ACPI table.
|
|
//
|
|
DEBUG ((
|
|
EFI_D_INFO,
|
|
"RamDiskPublishNfit: A NFIT is already exist in the ACPI Table.\n"
|
|
));
|
|
|
|
NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)TableHeader;
|
|
NfitLen = NfitHeader->Length + sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
|
|
Nfit = AllocateZeroPool (NfitLen);
|
|
if (Nfit == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (Nfit, TableHeader, NfitHeader->Length);
|
|
|
|
//
|
|
// Update the NFIT head pointer.
|
|
//
|
|
NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;
|
|
|
|
//
|
|
// Uninstall the origin NFIT from the ACPI table.
|
|
//
|
|
Status = mAcpiTableProtocol->UninstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
TableKey
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (Nfit);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Append the System Physical Address (SPA) Range Structure at the end
|
|
// of the origin NFIT.
|
|
//
|
|
SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)
|
|
((UINT8 *)Nfit + NfitHeader->Length);
|
|
|
|
//
|
|
// Update the length field of the NFIT
|
|
//
|
|
NfitHeader->Length = NfitLen;
|
|
|
|
//
|
|
// The checksum will be updated after the new contents are appended.
|
|
//
|
|
NfitHeader->Checksum = 0;
|
|
} else {
|
|
//
|
|
// Assumption is made that if no NFIT is in the ACPI table, there is no
|
|
// NVDIMM root device in the \SB scope.
|
|
// Therefore, a NVDIMM root device will be reported via Secondary System
|
|
// Description Table (SSDT).
|
|
//
|
|
Status = RamDiskPublishSsdt ();
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// No NFIT is in the ACPI table, we will create one here.
|
|
//
|
|
DEBUG ((
|
|
EFI_D_INFO,
|
|
"RamDiskPublishNfit: No NFIT is in the ACPI Table, will create one.\n"
|
|
));
|
|
|
|
NfitLen = sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE) +
|
|
sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
|
|
Nfit = AllocateZeroPool (NfitLen);
|
|
if (Nfit == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)
|
|
((UINT8 *)Nfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
|
|
|
|
NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;
|
|
NfitHeader->Signature = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE;
|
|
NfitHeader->Length = NfitLen;
|
|
NfitHeader->Revision = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION;
|
|
NfitHeader->Checksum = 0;
|
|
NfitHeader->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
|
|
NfitHeader->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
|
|
NfitHeader->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
|
|
CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
|
|
CopyMem (NfitHeader->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (NfitHeader->OemId));
|
|
CopyMem (&NfitHeader->OemTableId, &CurrentData, sizeof (UINT64));
|
|
}
|
|
|
|
//
|
|
// Fill in the content of the SPA Range Structure.
|
|
//
|
|
SpaRange->Type = EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE;
|
|
SpaRange->Length = sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
|
|
SpaRange->SystemPhysicalAddressRangeBase = PrivateData->StartingAddr;
|
|
SpaRange->SystemPhysicalAddressRangeLength = PrivateData->Size;
|
|
CopyGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid);
|
|
|
|
Checksum = CalculateCheckSum8((UINT8 *)Nfit, NfitHeader->Length);
|
|
NfitHeader->Checksum = Checksum;
|
|
|
|
//
|
|
// Publish the NFIT to the ACPI table.
|
|
// Note, since the NFIT might be modified by other driver, therefore, we
|
|
// do not track the returning TableKey from the InstallAcpiTable().
|
|
//
|
|
Status = mAcpiTableProtocol->InstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
Nfit,
|
|
NfitHeader->Length,
|
|
&TableKey
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
FreePool (Nfit);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
PrivateData->InNfit = TRUE;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Unpublish the RAM disk NVDIMM Firmware Interface Table (NFIT) from the
|
|
ACPI table.
|
|
|
|
@param[in] PrivateData Points to RAM disk private data.
|
|
|
|
@retval EFI_SUCCESS The RAM disk NFIT has been unpublished.
|
|
@retval others The RAM disk NFIT has not been unpublished.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
RamDiskUnpublishNfit (
|
|
IN RAM_DISK_PRIVATE_DATA *PrivateData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN TableIndex;
|
|
VOID *TableHeader;
|
|
EFI_ACPI_TABLE_VERSION TableVersion;
|
|
UINTN TableKey;
|
|
EFI_ACPI_DESCRIPTION_HEADER *NewNfitHeader;
|
|
EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE
|
|
*SpaRange;
|
|
VOID *NewNfit;
|
|
VOID *NewNfitPtr;
|
|
EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *NfitStructHeader;
|
|
UINT32 NewNfitLen;
|
|
UINT32 RemainLen;
|
|
UINT8 Checksum;
|
|
|
|
//
|
|
// Find the NFIT in the ACPI table.
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
TableIndex = 0;
|
|
TableKey = 0;
|
|
TableHeader = NULL;
|
|
|
|
while (!EFI_ERROR (Status)) {
|
|
Status = mAcpiSdtProtocol->GetAcpiTable (
|
|
TableIndex,
|
|
(EFI_ACPI_SDT_HEADER **)&TableHeader,
|
|
&TableVersion,
|
|
&TableKey
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
TableIndex++;
|
|
|
|
if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==
|
|
EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// No NFIT is found in the ACPI table.
|
|
//
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
NewNfitLen = ((EFI_ACPI_DESCRIPTION_HEADER *)TableHeader)->Length -
|
|
sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
|
|
|
|
//
|
|
// After removing this RAM disk from the NFIT, if no other structure is in
|
|
// the NFIT, we just remove the NFIT and the SSDT which is used to report
|
|
// the NVDIMM root device.
|
|
//
|
|
if (NewNfitLen == sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)) {
|
|
//
|
|
// Remove the NFIT.
|
|
//
|
|
Status = mAcpiTableProtocol->UninstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
TableKey
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Remove the SSDT which is used by RamDiskDxe driver to report the NVDIMM
|
|
// root device.
|
|
// We do not care the return status since this SSDT might already be
|
|
// uninstalled by other drivers to update the information of the NVDIMM
|
|
// root device.
|
|
//
|
|
if (mRamDiskSsdtTableKeyValid) {
|
|
mRamDiskSsdtTableKeyValid = FALSE;
|
|
|
|
mAcpiTableProtocol->UninstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
mRamDiskSsdtTableKey
|
|
);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
NewNfit = AllocateZeroPool (NewNfitLen);
|
|
if (NewNfit == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Get a copy of the old NFIT header content.
|
|
//
|
|
CopyMem (NewNfit, TableHeader, sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
|
|
NewNfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)NewNfit;
|
|
NewNfitHeader->Length = NewNfitLen;
|
|
NewNfitHeader->Checksum = 0;
|
|
|
|
//
|
|
// Copy the content of required NFIT structures.
|
|
//
|
|
NewNfitPtr = (UINT8 *)NewNfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);
|
|
RemainLen = NewNfitLen - sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);
|
|
NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
|
|
((UINT8 *)TableHeader + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
|
|
while (RemainLen > 0) {
|
|
if ((NfitStructHeader->Type == EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE) &&
|
|
(NfitStructHeader->Length == sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE))) {
|
|
SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)NfitStructHeader;
|
|
|
|
if ((SpaRange->SystemPhysicalAddressRangeBase == PrivateData->StartingAddr) &&
|
|
(SpaRange->SystemPhysicalAddressRangeLength == PrivateData->Size) &&
|
|
(CompareGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid))) {
|
|
//
|
|
// Skip the SPA Range Structure for the RAM disk to be unpublished
|
|
// from NFIT.
|
|
//
|
|
NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
|
|
((UINT8 *)NfitStructHeader + NfitStructHeader->Length);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy the content of origin NFIT.
|
|
//
|
|
CopyMem (NewNfitPtr, NfitStructHeader, NfitStructHeader->Length);
|
|
NewNfitPtr = (UINT8 *)NewNfitPtr + NfitStructHeader->Length;
|
|
|
|
//
|
|
// Move to the header of next NFIT structure.
|
|
//
|
|
RemainLen -= NfitStructHeader->Length;
|
|
NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
|
|
((UINT8 *)NfitStructHeader + NfitStructHeader->Length);
|
|
}
|
|
|
|
Checksum = CalculateCheckSum8((UINT8 *)NewNfit, NewNfitHeader->Length);
|
|
NewNfitHeader->Checksum = Checksum;
|
|
|
|
Status = mAcpiTableProtocol->UninstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
TableKey
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (NewNfit);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Publish the NFIT to the ACPI table.
|
|
// Note, since the NFIT might be modified by other driver, therefore, we
|
|
// do not track the returning TableKey from the InstallAcpiTable().
|
|
//
|
|
Status = mAcpiTableProtocol->InstallAcpiTable (
|
|
mAcpiTableProtocol,
|
|
NewNfit,
|
|
NewNfitLen,
|
|
&TableKey
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
FreePool (NewNfit);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Register a RAM disk with specified address, size and type.
|
|
|
|
@param[in] RamDiskBase The base address of registered RAM disk.
|
|
@param[in] RamDiskSize The size of registered RAM disk.
|
|
@param[in] RamDiskType The type of registered RAM disk. The GUID can be
|
|
any of the values defined in section 9.3.6.9, or a
|
|
vendor defined GUID.
|
|
@param[in] ParentDevicePath
|
|
Pointer to the parent device path. If there is no
|
|
parent device path then ParentDevicePath is NULL.
|
|
@param[out] DevicePath On return, points to a pointer to the device path
|
|
of the RAM disk device.
|
|
If ParentDevicePath is not NULL, the returned
|
|
DevicePath is created by appending a RAM disk node
|
|
to the parent device path. If ParentDevicePath is
|
|
NULL, the returned DevicePath is a RAM disk device
|
|
path without appending. This function is
|
|
responsible for allocating the buffer DevicePath
|
|
with the boot service AllocatePool().
|
|
|
|
@retval EFI_SUCCESS The RAM disk is registered successfully.
|
|
@retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.
|
|
RamDiskSize is 0.
|
|
@retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created
|
|
is already present in the handle database.
|
|
@retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to
|
|
resource limitation.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RamDiskRegister (
|
|
IN UINT64 RamDiskBase,
|
|
IN UINT64 RamDiskSize,
|
|
IN EFI_GUID *RamDiskType,
|
|
IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL,
|
|
OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
RAM_DISK_PRIVATE_DATA *PrivateData;
|
|
RAM_DISK_PRIVATE_DATA *RegisteredPrivateData;
|
|
MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
|
|
UINTN DevicePathSize;
|
|
LIST_ENTRY *Entry;
|
|
|
|
if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Add check to prevent data read across the memory boundary
|
|
//
|
|
if ((RamDiskSize > MAX_UINTN) ||
|
|
(RamDiskBase > MAX_UINTN - RamDiskSize + 1)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
RamDiskDevNode = NULL;
|
|
|
|
//
|
|
// Create a new RAM disk instance and initialize its private data
|
|
//
|
|
PrivateData = AllocateCopyPool (
|
|
sizeof (RAM_DISK_PRIVATE_DATA),
|
|
&mRamDiskPrivateDataTemplate
|
|
);
|
|
if (NULL == PrivateData) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
PrivateData->StartingAddr = RamDiskBase;
|
|
PrivateData->Size = RamDiskSize;
|
|
CopyGuid (&PrivateData->TypeGuid, RamDiskType);
|
|
InitializeListHead (&PrivateData->ThisInstance);
|
|
|
|
//
|
|
// Generate device path information for the registered RAM disk
|
|
//
|
|
RamDiskDevNode = AllocateCopyPool (
|
|
sizeof (MEDIA_RAM_DISK_DEVICE_PATH),
|
|
&mRamDiskDeviceNodeTemplate
|
|
);
|
|
if (NULL == RamDiskDevNode) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);
|
|
|
|
*DevicePath = AppendDevicePathNode (
|
|
ParentDevicePath,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode
|
|
);
|
|
if (NULL == *DevicePath) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
PrivateData->DevicePath = *DevicePath;
|
|
|
|
//
|
|
// Check whether the created device path is already present in the handle
|
|
// database
|
|
//
|
|
if (!IsListEmpty(&RegisteredRamDisks)) {
|
|
DevicePathSize = GetDevicePathSize (PrivateData->DevicePath);
|
|
|
|
EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
|
|
RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
|
|
if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) {
|
|
//
|
|
// Compare device path
|
|
//
|
|
if ((CompareMem (
|
|
PrivateData->DevicePath,
|
|
RegisteredPrivateData->DevicePath,
|
|
DevicePathSize)) == 0) {
|
|
*DevicePath = NULL;
|
|
Status = EFI_ALREADY_STARTED;
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill Block IO protocol informations for the RAM disk
|
|
//
|
|
RamDiskInitBlockIo (PrivateData);
|
|
|
|
//
|
|
// Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new
|
|
// handle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&PrivateData->Handle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&PrivateData->BlockIo,
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
&PrivateData->BlockIo2,
|
|
&gEfiDevicePathProtocolGuid,
|
|
PrivateData->DevicePath,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// Insert the newly created one to the registered RAM disk list
|
|
//
|
|
InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance);
|
|
|
|
gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE);
|
|
|
|
FreePool (RamDiskDevNode);
|
|
|
|
if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) {
|
|
RamDiskPublishNfit (PrivateData);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
ErrorExit:
|
|
if (RamDiskDevNode != NULL) {
|
|
FreePool (RamDiskDevNode);
|
|
}
|
|
|
|
if (PrivateData != NULL) {
|
|
if (PrivateData->DevicePath) {
|
|
FreePool (PrivateData->DevicePath);
|
|
}
|
|
|
|
FreePool (PrivateData);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Unregister a RAM disk specified by DevicePath.
|
|
|
|
@param[in] DevicePath A pointer to the device path that describes a RAM
|
|
Disk device.
|
|
|
|
@retval EFI_SUCCESS The RAM disk is unregistered successfully.
|
|
@retval EFI_INVALID_PARAMETER DevicePath is NULL.
|
|
@retval EFI_UNSUPPORTED The device specified by DevicePath is not a
|
|
valid ramdisk device path and not supported
|
|
by the driver.
|
|
@retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
|
|
exist.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RamDiskUnregister (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
LIST_ENTRY *NextEntry;
|
|
BOOLEAN Found;
|
|
UINT64 StartingAddr;
|
|
UINT64 EndingAddr;
|
|
EFI_DEVICE_PATH_PROTOCOL *Header;
|
|
MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
|
|
RAM_DISK_PRIVATE_DATA *PrivateData;
|
|
|
|
if (NULL == DevicePath) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Locate the RAM disk device node.
|
|
//
|
|
RamDiskDevNode = NULL;
|
|
Header = DevicePath;
|
|
do {
|
|
//
|
|
// Test if the current device node is a RAM disk.
|
|
//
|
|
if ((MEDIA_DEVICE_PATH == Header->Type) &&
|
|
(MEDIA_RAM_DISK_DP == Header->SubType)) {
|
|
RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;
|
|
|
|
break;
|
|
}
|
|
|
|
Header = NextDevicePathNode (Header);
|
|
} while ((Header->Type != END_DEVICE_PATH_TYPE));
|
|
|
|
if (NULL == RamDiskDevNode) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Found = FALSE;
|
|
StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));
|
|
EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));
|
|
|
|
if (!IsListEmpty(&RegisteredRamDisks)) {
|
|
EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
|
|
PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
|
|
|
|
//
|
|
// Unregister the RAM disk given by its starting address, ending address
|
|
// and type guid.
|
|
//
|
|
if ((StartingAddr == PrivateData->StartingAddr) &&
|
|
(EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&
|
|
(CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {
|
|
//
|
|
// Remove the content for this RAM disk in NFIT.
|
|
//
|
|
if (PrivateData->InNfit) {
|
|
RamDiskUnpublishNfit (PrivateData);
|
|
}
|
|
|
|
//
|
|
// Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL
|
|
//
|
|
gBS->UninstallMultipleProtocolInterfaces (
|
|
PrivateData->Handle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
&PrivateData->BlockIo,
|
|
&gEfiBlockIo2ProtocolGuid,
|
|
&PrivateData->BlockIo2,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,
|
|
NULL
|
|
);
|
|
|
|
RemoveEntryList (&PrivateData->ThisInstance);
|
|
|
|
if (RamDiskCreateHii == PrivateData->CreateMethod) {
|
|
//
|
|
// If a RAM disk is created within HII, then the RamDiskDxe driver
|
|
// driver is responsible for freeing the allocated memory for the
|
|
// RAM disk.
|
|
//
|
|
FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);
|
|
}
|
|
|
|
FreePool (PrivateData->DevicePath);
|
|
FreePool (PrivateData);
|
|
Found = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TRUE == Found) {
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|