From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001
From: Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com>
Date: Tue, 10 Oct 2023 14:33:42 +0000
Subject: Add submodule dependency files

Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
---
 .../Universal/Disk/RamDiskDxe/RamDiskProtocol.c    | 857 +++++++++++++++++++++
 1 file changed, 857 insertions(+)
 create mode 100644 roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c

(limited to 'roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c')

diff --git a/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
new file mode 100644
index 000000000..4333e0005
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
@@ -0,0 +1,857 @@
+/** @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>
+  Copyright (c) Microsoft Corporation.<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);
+
+    BASE_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)) {
+    BASE_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;
+  }
+}
-- 
cgit