Home | History | Annotate | Download | only in RamDiskDxe
      1 /** @file
      2   The realization of EFI_RAM_DISK_PROTOCOL.
      3 
      4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5   (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "RamDiskImpl.h"
     17 
     18 RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = {
     19   RAM_DISK_PRIVATE_DATA_SIGNATURE,
     20   NULL
     21 };
     22 
     23 MEDIA_RAM_DISK_DEVICE_PATH  mRamDiskDeviceNodeTemplate = {
     24   {
     25     MEDIA_DEVICE_PATH,
     26     MEDIA_RAM_DISK_DP,
     27     {
     28       (UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)),
     29       (UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8)
     30     }
     31   }
     32 };
     33 
     34 BOOLEAN  mRamDiskSsdtTableKeyValid = FALSE;
     35 UINTN    mRamDiskSsdtTableKey;
     36 
     37 
     38 /**
     39   Initialize the RAM disk device node.
     40 
     41   @param[in]      PrivateData     Points to RAM disk private data.
     42   @param[in, out] RamDiskDevNode  Points to the RAM disk device node.
     43 
     44 **/
     45 VOID
     46 RamDiskInitDeviceNode (
     47   IN     RAM_DISK_PRIVATE_DATA         *PrivateData,
     48   IN OUT MEDIA_RAM_DISK_DEVICE_PATH    *RamDiskDevNode
     49   )
     50 {
     51   WriteUnaligned64 (
     52     (UINT64 *) &(RamDiskDevNode->StartingAddr[0]),
     53     (UINT64) PrivateData->StartingAddr
     54     );
     55   WriteUnaligned64 (
     56     (UINT64 *) &(RamDiskDevNode->EndingAddr[0]),
     57     (UINT64) PrivateData->StartingAddr + PrivateData->Size - 1
     58     );
     59   CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid);
     60   RamDiskDevNode->Instance = PrivateData->InstanceNumber;
     61 }
     62 
     63 
     64 /**
     65   Initialize and publish NVDIMM root device SSDT in ACPI table.
     66 
     67   @retval EFI_SUCCESS        The NVDIMM root device SSDT is published.
     68   @retval Others             The NVDIMM root device SSDT is not published.
     69 
     70 **/
     71 EFI_STATUS
     72 RamDiskPublishSsdt (
     73   VOID
     74   )
     75 {
     76   EFI_STATUS                     Status;
     77   EFI_ACPI_DESCRIPTION_HEADER    *Table;
     78   UINTN                          SectionInstance;
     79   UINTN                          TableSize;
     80 
     81   Status          = EFI_SUCCESS;
     82   SectionInstance = 0;
     83 
     84   //
     85   // Scan all the EFI raw section instances in FV to find the NVDIMM root
     86   // device SSDT.
     87   //
     88   while (TRUE) {
     89     Status = GetSectionFromFv (
     90                &gEfiCallerIdGuid,
     91                EFI_SECTION_RAW,
     92                SectionInstance,
     93                (VOID **) &Table,
     94                &TableSize
     95                );
     96     if (EFI_ERROR (Status)) {
     97       break;
     98     }
     99 
    100     if (Table->OemTableId == SIGNATURE_64 ('R', 'a', 'm', 'D', 'i', 's', 'k', ' ')) {
    101       Status = mAcpiTableProtocol->InstallAcpiTable (
    102                                      mAcpiTableProtocol,
    103                                      Table,
    104                                      TableSize,
    105                                      &mRamDiskSsdtTableKey
    106                                      );
    107       ASSERT_EFI_ERROR (Status);
    108 
    109       if (!EFI_ERROR (Status)) {
    110         mRamDiskSsdtTableKeyValid = TRUE;
    111       }
    112 
    113       FreePool (Table);
    114       return Status;
    115     } else {
    116       FreePool (Table);
    117       SectionInstance++;
    118     }
    119   }
    120 
    121   return Status;
    122 }
    123 
    124 
    125 /**
    126   Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI
    127   table.
    128 
    129   @param[in] PrivateData          Points to RAM disk private data.
    130 
    131   @retval EFI_SUCCESS             The RAM disk NFIT has been published.
    132   @retval others                  The RAM disk NFIT has not been published.
    133 
    134 **/
    135 EFI_STATUS
    136 RamDiskPublishNfit (
    137   IN RAM_DISK_PRIVATE_DATA        *PrivateData
    138   )
    139 {
    140   EFI_STATUS                                    Status;
    141   EFI_MEMORY_DESCRIPTOR                         *MemoryMap;
    142   EFI_MEMORY_DESCRIPTOR                         *MemoryMapEntry;
    143   EFI_MEMORY_DESCRIPTOR                         *MemoryMapEnd;
    144   UINTN                                         TableIndex;
    145   VOID                                          *TableHeader;
    146   EFI_ACPI_TABLE_VERSION                        TableVersion;
    147   UINTN                                         TableKey;
    148   EFI_ACPI_DESCRIPTION_HEADER                   *NfitHeader;
    149   EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE
    150                                                 *SpaRange;
    151   VOID                                          *Nfit;
    152   UINT32                                        NfitLen;
    153   UINTN                                         MemoryMapSize;
    154   UINTN                                         MapKey;
    155   UINTN                                         DescriptorSize;
    156   UINT32                                        DescriptorVersion;
    157   UINT64                                        CurrentData;
    158   UINT8                                         Checksum;
    159   BOOLEAN                                       MemoryFound;
    160 
    161   //
    162   // Get the EFI memory map.
    163   //
    164   MemoryMapSize = 0;
    165   MemoryMap     = NULL;
    166   MemoryFound   = FALSE;
    167 
    168   Status = gBS->GetMemoryMap (
    169                   &MemoryMapSize,
    170                   MemoryMap,
    171                   &MapKey,
    172                   &DescriptorSize,
    173                   &DescriptorVersion
    174                   );
    175   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
    176   do {
    177     MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
    178     ASSERT (MemoryMap != NULL);
    179     Status = gBS->GetMemoryMap (
    180                     &MemoryMapSize,
    181                     MemoryMap,
    182                     &MapKey,
    183                     &DescriptorSize,
    184                     &DescriptorVersion
    185                     );
    186     if (EFI_ERROR (Status)) {
    187       FreePool (MemoryMap);
    188     }
    189   } while (Status == EFI_BUFFER_TOO_SMALL);
    190   ASSERT_EFI_ERROR (Status);
    191 
    192   MemoryMapEntry = MemoryMap;
    193   MemoryMapEnd   = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
    194   while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {
    195     if ((MemoryMapEntry->Type == EfiReservedMemoryType) &&
    196         (MemoryMapEntry->PhysicalStart <= PrivateData->StartingAddr) &&
    197         (MemoryMapEntry->PhysicalStart +
    198          MultU64x32 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SIZE)
    199          >= PrivateData->StartingAddr + PrivateData->Size)) {
    200       MemoryFound = TRUE;
    201       DEBUG ((
    202         EFI_D_INFO,
    203         "RamDiskPublishNfit: RAM disk with reserved meomry type, will publish to NFIT.\n"
    204         ));
    205       break;
    206     }
    207     MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    208   }
    209   FreePool (MemoryMap);
    210 
    211   if (!MemoryFound) {
    212     return EFI_NOT_FOUND;
    213   }
    214 
    215   //
    216   // Determine whether there is a NFIT already in the ACPI table.
    217   //
    218   Status      = EFI_SUCCESS;
    219   TableIndex  = 0;
    220   TableKey    = 0;
    221   TableHeader = NULL;
    222 
    223   while (!EFI_ERROR (Status)) {
    224     Status = mAcpiSdtProtocol->GetAcpiTable (
    225                                  TableIndex,
    226                                  (EFI_ACPI_SDT_HEADER **)&TableHeader,
    227                                  &TableVersion,
    228                                  &TableKey
    229                                  );
    230     if (!EFI_ERROR (Status)) {
    231       TableIndex++;
    232 
    233       if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==
    234           EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {
    235         break;
    236       }
    237     }
    238   }
    239 
    240   if (!EFI_ERROR (Status)) {
    241     //
    242     // A NFIT is already in the ACPI table.
    243     //
    244     DEBUG ((
    245       EFI_D_INFO,
    246       "RamDiskPublishNfit: A NFIT is already exist in the ACPI Table.\n"
    247       ));
    248 
    249     NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)TableHeader;
    250     NfitLen    = NfitHeader->Length + sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
    251     Nfit       = AllocateZeroPool (NfitLen);
    252     if (Nfit == NULL) {
    253       return EFI_OUT_OF_RESOURCES;
    254     }
    255     CopyMem (Nfit, TableHeader, NfitHeader->Length);
    256 
    257     //
    258     // Update the NFIT head pointer.
    259     //
    260     NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;
    261 
    262     //
    263     // Uninstall the origin NFIT from the ACPI table.
    264     //
    265     Status = mAcpiTableProtocol->UninstallAcpiTable (
    266                                    mAcpiTableProtocol,
    267                                    TableKey
    268                                    );
    269     ASSERT_EFI_ERROR (Status);
    270 
    271     if (EFI_ERROR (Status)) {
    272       FreePool (Nfit);
    273       return Status;
    274     }
    275 
    276     //
    277     // Append the System Physical Address (SPA) Range Structure at the end
    278     // of the origin NFIT.
    279     //
    280     SpaRange   = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)
    281                  ((UINT8 *)Nfit + NfitHeader->Length);
    282 
    283     //
    284     // Update the length field of the NFIT
    285     //
    286     NfitHeader->Length   = NfitLen;
    287 
    288     //
    289     // The checksum will be updated after the new contents are appended.
    290     //
    291     NfitHeader->Checksum = 0;
    292   } else {
    293     //
    294     // Assumption is made that if no NFIT is in the ACPI table, there is no
    295     // NVDIMM root device in the \SB scope.
    296     // Therefore, a NVDIMM root device will be reported via Secondary System
    297     // Description Table (SSDT).
    298     //
    299     Status = RamDiskPublishSsdt ();
    300     if (EFI_ERROR (Status)) {
    301       return Status;
    302     }
    303 
    304     //
    305     // No NFIT is in the ACPI table, we will create one here.
    306     //
    307     DEBUG ((
    308       EFI_D_INFO,
    309       "RamDiskPublishNfit: No NFIT is in the ACPI Table, will create one.\n"
    310       ));
    311 
    312     NfitLen = sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE) +
    313               sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
    314     Nfit    = AllocateZeroPool (NfitLen);
    315     if (Nfit == NULL) {
    316       return EFI_OUT_OF_RESOURCES;
    317     }
    318 
    319     SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)
    320                ((UINT8 *)Nfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
    321 
    322     NfitHeader                  = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;
    323     NfitHeader->Signature       = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE;
    324     NfitHeader->Length          = NfitLen;
    325     NfitHeader->Revision        = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION;
    326     NfitHeader->Checksum        = 0;
    327     NfitHeader->OemRevision     = PcdGet32 (PcdAcpiDefaultOemRevision);
    328     NfitHeader->CreatorId       = PcdGet32 (PcdAcpiDefaultCreatorId);
    329     NfitHeader->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
    330     CurrentData                 = PcdGet64 (PcdAcpiDefaultOemTableId);
    331     CopyMem (NfitHeader->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (NfitHeader->OemId));
    332     CopyMem (&NfitHeader->OemTableId, &CurrentData, sizeof (UINT64));
    333   }
    334 
    335   //
    336   // Fill in the content of the SPA Range Structure.
    337   //
    338   SpaRange->Type   = EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE;
    339   SpaRange->Length = sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
    340   SpaRange->SystemPhysicalAddressRangeBase   = PrivateData->StartingAddr;
    341   SpaRange->SystemPhysicalAddressRangeLength = PrivateData->Size;
    342   CopyGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid);
    343 
    344   Checksum             = CalculateCheckSum8((UINT8 *)Nfit, NfitHeader->Length);
    345   NfitHeader->Checksum = Checksum;
    346 
    347   //
    348   // Publish the NFIT to the ACPI table.
    349   // Note, since the NFIT might be modified by other driver, therefore, we
    350   // do not track the returning TableKey from the InstallAcpiTable().
    351   //
    352   Status = mAcpiTableProtocol->InstallAcpiTable (
    353                                  mAcpiTableProtocol,
    354                                  Nfit,
    355                                  NfitHeader->Length,
    356                                  &TableKey
    357                                  );
    358   ASSERT_EFI_ERROR (Status);
    359 
    360   FreePool (Nfit);
    361 
    362   if (EFI_ERROR (Status)) {
    363     return Status;
    364   }
    365 
    366   PrivateData->InNfit = TRUE;
    367 
    368   return EFI_SUCCESS;
    369 }
    370 
    371 
    372 /**
    373   Unpublish the RAM disk NVDIMM Firmware Interface Table (NFIT) from the
    374   ACPI table.
    375 
    376   @param[in] PrivateData          Points to RAM disk private data.
    377 
    378   @retval EFI_SUCCESS             The RAM disk NFIT has been unpublished.
    379   @retval others                  The RAM disk NFIT has not been unpublished.
    380 
    381 **/
    382 EFI_STATUS
    383 RamDiskUnpublishNfit (
    384   IN RAM_DISK_PRIVATE_DATA        *PrivateData
    385   )
    386 {
    387   EFI_STATUS                                    Status;
    388   UINTN                                         TableIndex;
    389   VOID                                          *TableHeader;
    390   EFI_ACPI_TABLE_VERSION                        TableVersion;
    391   UINTN                                         TableKey;
    392   EFI_ACPI_DESCRIPTION_HEADER                   *NewNfitHeader;
    393   EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE
    394                                                 *SpaRange;
    395   VOID                                          *NewNfit;
    396   VOID                                          *NewNfitPtr;
    397   EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER            *NfitStructHeader;
    398   UINT32                                        NewNfitLen;
    399   UINT32                                        RemainLen;
    400   UINT8                                         Checksum;
    401 
    402   //
    403   // Find the NFIT in the ACPI table.
    404   //
    405   Status      = EFI_SUCCESS;
    406   TableIndex  = 0;
    407   TableKey    = 0;
    408   TableHeader = NULL;
    409 
    410   while (!EFI_ERROR (Status)) {
    411     Status = mAcpiSdtProtocol->GetAcpiTable (
    412                                  TableIndex,
    413                                  (EFI_ACPI_SDT_HEADER **)&TableHeader,
    414                                  &TableVersion,
    415                                  &TableKey
    416                                  );
    417     if (!EFI_ERROR (Status)) {
    418       TableIndex++;
    419 
    420       if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==
    421           EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {
    422         break;
    423       }
    424     }
    425   }
    426 
    427   if (EFI_ERROR (Status)) {
    428     //
    429     // No NFIT is found in the ACPI table.
    430     //
    431     return EFI_NOT_FOUND;
    432   }
    433 
    434   NewNfitLen    = ((EFI_ACPI_DESCRIPTION_HEADER *)TableHeader)->Length -
    435                   sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
    436 
    437   //
    438   // After removing this RAM disk from the NFIT, if no other structure is in
    439   // the NFIT, we just remove the NFIT and the SSDT which is used to report
    440   // the NVDIMM root device.
    441   //
    442   if (NewNfitLen == sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)) {
    443     //
    444     // Remove the NFIT.
    445     //
    446     Status = mAcpiTableProtocol->UninstallAcpiTable (
    447                                    mAcpiTableProtocol,
    448                                    TableKey
    449                                    );
    450     ASSERT_EFI_ERROR (Status);
    451     if (EFI_ERROR (Status)) {
    452       return Status;
    453     }
    454 
    455     //
    456     // Remove the SSDT which is used by RamDiskDxe driver to report the NVDIMM
    457     // root device.
    458     // We do not care the return status since this SSDT might already be
    459     // uninstalled by other drivers to update the information of the NVDIMM
    460     // root device.
    461     //
    462     if (mRamDiskSsdtTableKeyValid) {
    463       mRamDiskSsdtTableKeyValid = FALSE;
    464 
    465       mAcpiTableProtocol->UninstallAcpiTable (
    466                             mAcpiTableProtocol,
    467                             mRamDiskSsdtTableKey
    468                             );
    469     }
    470 
    471     return EFI_SUCCESS;
    472   }
    473 
    474   NewNfit = AllocateZeroPool (NewNfitLen);
    475   if (NewNfit == NULL) {
    476     return EFI_OUT_OF_RESOURCES;
    477   }
    478 
    479   //
    480   // Get a copy of the old NFIT header content.
    481   //
    482   CopyMem (NewNfit, TableHeader, sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
    483   NewNfitHeader           = (EFI_ACPI_DESCRIPTION_HEADER *)NewNfit;
    484   NewNfitHeader->Length   = NewNfitLen;
    485   NewNfitHeader->Checksum = 0;
    486 
    487   //
    488   // Copy the content of required NFIT structures.
    489   //
    490   NewNfitPtr       = (UINT8 *)NewNfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);
    491   RemainLen        = NewNfitLen - sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);
    492   NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
    493                      ((UINT8 *)TableHeader + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
    494   while (RemainLen > 0) {
    495     if ((NfitStructHeader->Type == EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE) &&
    496         (NfitStructHeader->Length == sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE))) {
    497       SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)NfitStructHeader;
    498 
    499       if ((SpaRange->SystemPhysicalAddressRangeBase == PrivateData->StartingAddr) &&
    500           (SpaRange->SystemPhysicalAddressRangeLength == PrivateData->Size) &&
    501           (CompareGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid))) {
    502         //
    503         // Skip the SPA Range Structure for the RAM disk to be unpublished
    504         // from NFIT.
    505         //
    506         NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
    507                            ((UINT8 *)NfitStructHeader + NfitStructHeader->Length);
    508         continue;
    509       }
    510     }
    511 
    512     //
    513     // Copy the content of origin NFIT.
    514     //
    515     CopyMem (NewNfitPtr, NfitStructHeader, NfitStructHeader->Length);
    516     NewNfitPtr = (UINT8 *)NewNfitPtr + NfitStructHeader->Length;
    517 
    518     //
    519     // Move to the header of next NFIT structure.
    520     //
    521     RemainLen       -= NfitStructHeader->Length;
    522     NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
    523                        ((UINT8 *)NfitStructHeader + NfitStructHeader->Length);
    524   }
    525 
    526   Checksum                = CalculateCheckSum8((UINT8 *)NewNfit, NewNfitHeader->Length);
    527   NewNfitHeader->Checksum = Checksum;
    528 
    529   Status = mAcpiTableProtocol->UninstallAcpiTable (
    530                                  mAcpiTableProtocol,
    531                                  TableKey
    532                                  );
    533   ASSERT_EFI_ERROR (Status);
    534 
    535   if (EFI_ERROR (Status)) {
    536     FreePool (NewNfit);
    537     return Status;
    538   }
    539 
    540   //
    541   // Publish the NFIT to the ACPI table.
    542   // Note, since the NFIT might be modified by other driver, therefore, we
    543   // do not track the returning TableKey from the InstallAcpiTable().
    544   //
    545   Status = mAcpiTableProtocol->InstallAcpiTable (
    546                                  mAcpiTableProtocol,
    547                                  NewNfit,
    548                                  NewNfitLen,
    549                                  &TableKey
    550                                  );
    551   ASSERT_EFI_ERROR (Status);
    552 
    553   FreePool (NewNfit);
    554   if (EFI_ERROR (Status)) {
    555     return Status;
    556   }
    557 
    558   return EFI_SUCCESS;
    559 }
    560 
    561 
    562 /**
    563   Register a RAM disk with specified address, size and type.
    564 
    565   @param[in]  RamDiskBase    The base address of registered RAM disk.
    566   @param[in]  RamDiskSize    The size of registered RAM disk.
    567   @param[in]  RamDiskType    The type of registered RAM disk. The GUID can be
    568                              any of the values defined in section 9.3.6.9, or a
    569                              vendor defined GUID.
    570   @param[in]  ParentDevicePath
    571                              Pointer to the parent device path. If there is no
    572                              parent device path then ParentDevicePath is NULL.
    573   @param[out] DevicePath     On return, points to a pointer to the device path
    574                              of the RAM disk device.
    575                              If ParentDevicePath is not NULL, the returned
    576                              DevicePath is created by appending a RAM disk node
    577                              to the parent device path. If ParentDevicePath is
    578                              NULL, the returned DevicePath is a RAM disk device
    579                              path without appending. This function is
    580                              responsible for allocating the buffer DevicePath
    581                              with the boot service AllocatePool().
    582 
    583   @retval EFI_SUCCESS             The RAM disk is registered successfully.
    584   @retval EFI_INVALID_PARAMETER   DevicePath or RamDiskType is NULL.
    585                                   RamDiskSize is 0.
    586   @retval EFI_ALREADY_STARTED     A Device Path Protocol instance to be created
    587                                   is already present in the handle database.
    588   @retval EFI_OUT_OF_RESOURCES    The RAM disk register operation fails due to
    589                                   resource limitation.
    590 
    591 **/
    592 EFI_STATUS
    593 EFIAPI
    594 RamDiskRegister (
    595   IN UINT64                       RamDiskBase,
    596   IN UINT64                       RamDiskSize,
    597   IN EFI_GUID                     *RamDiskType,
    598   IN EFI_DEVICE_PATH              *ParentDevicePath     OPTIONAL,
    599   OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath
    600   )
    601 {
    602   EFI_STATUS                      Status;
    603   RAM_DISK_PRIVATE_DATA           *PrivateData;
    604   RAM_DISK_PRIVATE_DATA           *RegisteredPrivateData;
    605   MEDIA_RAM_DISK_DEVICE_PATH      *RamDiskDevNode;
    606   UINTN                           DevicePathSize;
    607   LIST_ENTRY                      *Entry;
    608 
    609   if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) {
    610     return EFI_INVALID_PARAMETER;
    611   }
    612 
    613   //
    614   // Add check to prevent data read across the memory boundary
    615   //
    616   if (RamDiskBase + RamDiskSize > ((UINTN) -1) - RAM_DISK_BLOCK_SIZE + 1) {
    617     return EFI_INVALID_PARAMETER;
    618   }
    619 
    620   RamDiskDevNode = NULL;
    621 
    622   //
    623   // Create a new RAM disk instance and initialize its private data
    624   //
    625   PrivateData = AllocateCopyPool (
    626                   sizeof (RAM_DISK_PRIVATE_DATA),
    627                   &mRamDiskPrivateDataTemplate
    628                   );
    629   if (NULL == PrivateData) {
    630     return EFI_OUT_OF_RESOURCES;
    631   }
    632 
    633   PrivateData->StartingAddr = RamDiskBase;
    634   PrivateData->Size         = RamDiskSize;
    635   CopyGuid (&PrivateData->TypeGuid, RamDiskType);
    636   InitializeListHead (&PrivateData->ThisInstance);
    637 
    638   //
    639   // Generate device path information for the registered RAM disk
    640   //
    641   RamDiskDevNode = AllocateCopyPool (
    642                      sizeof (MEDIA_RAM_DISK_DEVICE_PATH),
    643                      &mRamDiskDeviceNodeTemplate
    644                      );
    645   if (NULL == RamDiskDevNode) {
    646     Status = EFI_OUT_OF_RESOURCES;
    647     goto ErrorExit;
    648   }
    649 
    650   RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);
    651 
    652   *DevicePath = AppendDevicePathNode (
    653                   ParentDevicePath,
    654                   (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode
    655                   );
    656   if (NULL == *DevicePath) {
    657     Status = EFI_OUT_OF_RESOURCES;
    658     goto ErrorExit;
    659   }
    660 
    661   PrivateData->DevicePath = *DevicePath;
    662 
    663   //
    664   // Check whether the created device path is already present in the handle
    665   // database
    666   //
    667   if (!IsListEmpty(&RegisteredRamDisks)) {
    668     DevicePathSize = GetDevicePathSize (PrivateData->DevicePath);
    669 
    670     EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
    671       RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
    672       if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) {
    673         //
    674         // Compare device path
    675         //
    676         if ((CompareMem (
    677                PrivateData->DevicePath,
    678                RegisteredPrivateData->DevicePath,
    679                DevicePathSize)) == 0) {
    680           *DevicePath = NULL;
    681           Status      = EFI_ALREADY_STARTED;
    682           goto ErrorExit;
    683         }
    684       }
    685     }
    686   }
    687 
    688   //
    689   // Fill Block IO protocol informations for the RAM disk
    690   //
    691   RamDiskInitBlockIo (PrivateData);
    692 
    693   //
    694   // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new
    695   // handle
    696   //
    697   Status = gBS->InstallMultipleProtocolInterfaces (
    698                   &PrivateData->Handle,
    699                   &gEfiBlockIoProtocolGuid,
    700                   &PrivateData->BlockIo,
    701                   &gEfiBlockIo2ProtocolGuid,
    702                   &PrivateData->BlockIo2,
    703                   &gEfiDevicePathProtocolGuid,
    704                   PrivateData->DevicePath,
    705                   NULL
    706                   );
    707   if (EFI_ERROR (Status)) {
    708     goto ErrorExit;
    709   }
    710 
    711   //
    712   // Insert the newly created one to the registered RAM disk list
    713   //
    714   InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance);
    715 
    716   gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE);
    717 
    718   FreePool (RamDiskDevNode);
    719 
    720   if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) {
    721     RamDiskPublishNfit (PrivateData);
    722   }
    723 
    724   return EFI_SUCCESS;
    725 
    726 ErrorExit:
    727   if (RamDiskDevNode != NULL) {
    728     FreePool (RamDiskDevNode);
    729   }
    730 
    731   if (PrivateData != NULL) {
    732     if (PrivateData->DevicePath) {
    733       FreePool (PrivateData->DevicePath);
    734     }
    735 
    736     FreePool (PrivateData);
    737   }
    738 
    739   return Status;
    740 }
    741 
    742 
    743 /**
    744   Unregister a RAM disk specified by DevicePath.
    745 
    746   @param[in] DevicePath      A pointer to the device path that describes a RAM
    747                              Disk device.
    748 
    749   @retval EFI_SUCCESS             The RAM disk is unregistered successfully.
    750   @retval EFI_INVALID_PARAMETER   DevicePath is NULL.
    751   @retval EFI_UNSUPPORTED         The device specified by DevicePath is not a
    752                                   valid ramdisk device path and not supported
    753                                   by the driver.
    754   @retval EFI_NOT_FOUND           The RAM disk pointed by DevicePath doesn't
    755                                   exist.
    756 
    757 **/
    758 EFI_STATUS
    759 EFIAPI
    760 RamDiskUnregister (
    761   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath
    762   )
    763 {
    764   LIST_ENTRY                      *Entry;
    765   LIST_ENTRY                      *NextEntry;
    766   BOOLEAN                         Found;
    767   UINT64                          StartingAddr;
    768   UINT64                          EndingAddr;
    769   EFI_DEVICE_PATH_PROTOCOL        *Header;
    770   MEDIA_RAM_DISK_DEVICE_PATH      *RamDiskDevNode;
    771   RAM_DISK_PRIVATE_DATA           *PrivateData;
    772 
    773   if (NULL == DevicePath) {
    774     return EFI_INVALID_PARAMETER;
    775   }
    776 
    777   //
    778   // Locate the RAM disk device node.
    779   //
    780   RamDiskDevNode = NULL;
    781   Header         = DevicePath;
    782   do {
    783     //
    784     // Test if the current device node is a RAM disk.
    785     //
    786     if ((MEDIA_DEVICE_PATH == Header->Type) &&
    787       (MEDIA_RAM_DISK_DP == Header->SubType)) {
    788       RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;
    789 
    790       break;
    791     }
    792 
    793     Header = NextDevicePathNode (Header);
    794   } while ((Header->Type != END_DEVICE_PATH_TYPE));
    795 
    796   if (NULL == RamDiskDevNode) {
    797     return EFI_UNSUPPORTED;
    798   }
    799 
    800   Found          = FALSE;
    801   StartingAddr   = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));
    802   EndingAddr     = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));
    803 
    804   if (!IsListEmpty(&RegisteredRamDisks)) {
    805     EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
    806       PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
    807 
    808       //
    809       // Unregister the RAM disk given by its starting address, ending address
    810       // and type guid.
    811       //
    812       if ((StartingAddr == PrivateData->StartingAddr) &&
    813           (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&
    814           (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {
    815         //
    816         // Remove the content for this RAM disk in NFIT.
    817         //
    818         if (PrivateData->InNfit) {
    819           RamDiskUnpublishNfit (PrivateData);
    820         }
    821 
    822         //
    823         // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL
    824         //
    825         gBS->UninstallMultipleProtocolInterfaces (
    826                PrivateData->Handle,
    827                &gEfiBlockIoProtocolGuid,
    828                &PrivateData->BlockIo,
    829                &gEfiBlockIo2ProtocolGuid,
    830                &PrivateData->BlockIo2,
    831                &gEfiDevicePathProtocolGuid,
    832                (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,
    833                NULL
    834                );
    835 
    836         RemoveEntryList (&PrivateData->ThisInstance);
    837 
    838         if (RamDiskCreateHii == PrivateData->CreateMethod) {
    839           //
    840           // If a RAM disk is created within HII, then the RamDiskDxe driver
    841           // driver is responsible for freeing the allocated memory for the
    842           // RAM disk.
    843           //
    844           FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);
    845         }
    846 
    847         FreePool (PrivateData->DevicePath);
    848         FreePool (PrivateData);
    849         Found = TRUE;
    850 
    851         break;
    852       }
    853     }
    854   }
    855 
    856   if (TRUE == Found) {
    857     return EFI_SUCCESS;
    858   } else {
    859     return EFI_NOT_FOUND;
    860   }
    861 }
    862