mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-27 01:03:45 +01:00 
			
		
		
		
	This commit will scan all the EFI raw section instances within the module's FV to make sure the NVDIMM root device SSDT can be properly located. Cc: Feng Tian <feng.tian@intel.com> Cc: Zhang Chao B <chao.b.zhang@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Chao Zhang <chao.b.zhang@intel.com>
		
			
				
	
	
		
			862 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			862 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   The realization of EFI_RAM_DISK_PROTOCOL.
 | |
| 
 | |
|   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
 | |
|   (C) Copyright 2016 Hewlett Packard Enterprise Development LP<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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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 (RamDiskBase + RamDiskSize > ((UINTN) -1) - RAM_DISK_BLOCK_SIZE + 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;
 | |
|   }
 | |
| }
 |