diff options
Diffstat (limited to 'MdeModulePkg')
5 files changed, 658 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl new file mode 100644 index 0000000000..115dca09c0 --- /dev/null +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl @@ -0,0 +1,44 @@ +/** @file
+ The definition block in ACPI table for NVDIMM root device.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+DefinitionBlock (
+ "RamDisk.aml",
+ "SSDT",
+ 2,
+ "INTEL ",
+ "RamDisk ",
+ 0x1000
+ )
+{
+ Scope (\_SB)
+ {
+ Device (NVDR)
+ {
+ //
+ // Define _HID, "ACPI0012" NVDIMM Root Device
+ //
+ Name (_HID, "ACPI0012")
+
+ //
+ // Readable name of this device
+ //
+ Name (_STR, Unicode ("NVDIMM Root Device"))
+
+ Method (_STA, 0)
+ {
+ Return (0x0f)
+ }
+ }
+ }
+}
diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c index 7d068b25c9..e65aee8021 100644 --- a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c @@ -34,6 +34,77 @@ EFI_RAM_DISK_PROTOCOL mRamDiskProtocol = { LIST_ENTRY RegisteredRamDisks;
UINTN ListEntryNum;
+//
+// Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL.
+//
+EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol = NULL;
+EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol = NULL;
+
+
+/**
+ Check whether EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL are produced.
+ If both protocols are produced, publish all the reserved memory type RAM
+ disks to the NVDIMM Firmware Interface Table (NFIT).
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+RamDiskAcpiCheck (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Entry;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ gBS->CloseEvent (Event);
+
+ //
+ // Locate the EFI_ACPI_TABLE_PROTOCOL.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiTableProtocolGuid,
+ NULL,
+ (VOID **)&mAcpiTableProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskAcpiCheck: Cannot locate the EFI ACPI Table Protocol,",
+ "unable to publish RAM disks to NFIT.\n"
+ ));
+ return;
+ }
+
+ //
+ // Locate the EFI_ACPI_SDT_PROTOCOL.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID **)&mAcpiSdtProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskAcpiCheck: Cannot locate the EFI ACPI Sdt Protocol,",
+ "unable to publish RAM disks to NFIT.\n"
+ ));
+ mAcpiTableProtocol = NULL;
+ return;
+ }
+
+ EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ RamDiskPublishNfit (PrivateData);
+ }
+}
+
/**
The entry point for RamDiskDxe driver.
@@ -58,6 +129,7 @@ RamDiskDxeEntryPoint ( EFI_STATUS Status;
RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate;
VOID *DummyInterface;
+ EFI_EVENT Event;
//
// If already started, return.
@@ -109,6 +181,14 @@ RamDiskDxeEntryPoint ( //
InitializeListHead (&RegisteredRamDisks);
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ RamDiskAcpiCheck,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
return EFI_SUCCESS;
ErrorExit:
diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf index 9fe35996ee..d1eb42947f 100644 --- a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf @@ -39,6 +39,7 @@ RamDiskHii.vfr
RamDiskHiiStrings.uni
RamDiskNVData.h
+ RamDisk.asl
[Packages]
MdePkg/MdePkg.dec
@@ -57,6 +58,8 @@ FileExplorerLib
DevicePathLib
PrintLib
+ PcdLib
+ DxeServicesLib
[Guids]
gEfiIfrTianoGuid ## PRODUCES ## GUID # HII opcode
@@ -73,6 +76,15 @@ gEfiBlockIoProtocolGuid ## PRODUCES
gEfiBlockIo2ProtocolGuid ## PRODUCES
gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiAcpiTableProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiAcpiSdtProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES
[Depex]
gEfiHiiConfigRoutingProtocolGuid AND
diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h index 0b9a4f9ec8..2fcc89f046 100644 --- a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h @@ -28,14 +28,19 @@ #include <Library/FileExplorerLib.h>
#include <Library/DevicePathLib.h>
#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DxeServicesLib.h>
#include <Protocol/RamDisk.h>
#include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Protocol/HiiConfigAccess.h>
#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
#include <Guid/MdeModuleHii.h>
#include <Guid/RamDiskHii.h>
#include <Guid/FileInfo.h>
+#include <IndustryStandard/Acpi61.h>
#include "RamDiskNVData.h"
@@ -69,6 +74,12 @@ extern LIST_ENTRY RegisteredRamDisks; extern UINTN ListEntryNum;
//
+// Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL.
+//
+extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol;
+extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol;
+
+//
// RAM Disk create method.
//
typedef enum _RAM_DISK_CREATE_METHOD {
@@ -96,6 +107,7 @@ typedef struct { EFI_GUID TypeGuid;
UINT16 InstanceNumber;
RAM_DISK_CREATE_METHOD CreateMethod;
+ BOOLEAN InNfit;
LIST_ENTRY ThisInstance;
} RAM_DISK_PRIVATE_DATA;
@@ -630,4 +642,20 @@ OpenFileByDevicePath( IN UINT64 Attributes
);
+
+/**
+ 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
+ );
+
#endif
diff --git a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c index de11721232..93b1b83877 100644 --- a/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c +++ b/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c @@ -31,6 +31,9 @@ MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = { }
};
+BOOLEAN mRamDiskSsdtTableKeyValid = FALSE;
+UINTN mRamDiskSsdtTableKey;
+
/**
Initialize the RAM disk device node.
@@ -59,6 +62,486 @@ RamDiskInitDeviceNode ( /**
+ 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 TableSize;
+
+ Status = GetSectionFromFv (
+ &gEfiCallerIdGuid,
+ EFI_SECTION_RAW,
+ 1,
+ (VOID **) &Table,
+ &TableSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ASSERT (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;
+ } else {
+ mRamDiskSsdtTableKeyValid = FALSE;
+ }
+
+ FreePool (Table);
+
+ 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;
+
+ 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;
+
+ 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.
@@ -217,6 +700,10 @@ RamDiskRegister ( FreePool (RamDiskDevNode);
+ if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) {
+ RamDiskPublishNfit (PrivateData);
+ }
+
return EFI_SUCCESS;
ErrorExit:
@@ -309,6 +796,13 @@ RamDiskUnregister ( (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 (
|