text: /** @file
    The driver entry point for RamDiskDxe driver.
  
    Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
    SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  
  #include "RamDiskImpl.h"
  
  //
  // Handle for the EFI_RAM_DISK_PROTOCOL instance
  //
  EFI_HANDLE  mRamDiskHandle = NULL;
  
  //
  // The EFI_RAM_DISK_PROTOCOL instances that is installed onto the driver
  // handle
  //
  EFI_RAM_DISK_PROTOCOL  mRamDiskProtocol = {
    RamDiskRegister,
    RamDiskUnregister
  };
  
  //
  // RamDiskDxe driver maintains a list of registered RAM disks.
  //
  LIST_ENTRY  RegisteredRamDisks;
  
  //
  // Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL.
  //
  EFI_ACPI_TABLE_PROTOCOL  *mAcpiTableProtocol = NULL;
  EFI_ACPI_SDT_PROTOCOL    *mAcpiSdtProtocol   = NULL;
  
  
  /**
    Check whether EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL are produced.
    If both protocols are produced, publish all the reserved memory type RAM
    disks to the NVDIMM Firmware Interface Table (NFIT).
  
    @param[in] Event      Event whose notification function is being invoked.
    @param[in] Context    The pointer to the notification function's context,
                          which is implementation-dependent.
  
  **/
  VOID
  EFIAPI
  RamDiskAcpiCheck (
    IN EFI_EVENT    Event,
    IN VOID         *Context
    )
  {
    EFI_STATUS                 Status;
    LIST_ENTRY                 *Entry;
    RAM_DISK_PRIVATE_DATA      *PrivateData;
  
    gBS->CloseEvent (Event);
  
    //
    // Locate the EFI_ACPI_TABLE_PROTOCOL.
    //
    Status = gBS->LocateProtocol (
                    &gEfiAcpiTableProtocolGuid,
                    NULL,
                    (VOID **)&mAcpiTableProtocol
                    );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        EFI_D_INFO,
        "RamDiskAcpiCheck: Cannot locate the EFI ACPI Table Protocol, "
        "unable to publish RAM disks to NFIT.\n"
        ));
      return;
    }
  
    //
    // Locate the EFI_ACPI_SDT_PROTOCOL.
    //
    Status = gBS->LocateProtocol (
                    &gEfiAcpiSdtProtocolGuid,
                    NULL,
                    (VOID **)&mAcpiSdtProtocol
                    );
    if (EFI_ERROR (Status)) {
      DEBUG ((
        EFI_D_INFO,
        "RamDiskAcpiCheck: Cannot locate the EFI ACPI Sdt Protocol, "
        "unable to publish RAM disks to NFIT.\n"
        ));
      mAcpiTableProtocol = NULL;
      return;
    }
  
    EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
      PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
      RamDiskPublishNfit (PrivateData);
    }
  }
  
  
  /**
    The entry point for RamDiskDxe driver.
  
    @param[in] ImageHandle     The image handle of the driver.
    @param[in] SystemTable     The system table.
  
    @retval EFI_ALREADY_STARTED     The driver already exists in system.
    @retval EFI_OUT_OF_RESOURCES    Fail to execute entry point due to lack of
                                    resources.
    @retval EFI_SUCCES              All the related protocols are installed on
                                    the driver.
  
  **/
  EFI_STATUS
  EFIAPI
  RamDiskDxeEntryPoint (
    IN EFI_HANDLE                   ImageHandle,
    IN EFI_SYSTEM_TABLE             *SystemTable
    )
  {
    EFI_STATUS                      Status;
    RAM_DISK_CONFIG_PRIVATE_DATA    *ConfigPrivate;
    VOID                            *DummyInterface;
    EFI_EVENT                       Event;
  
    //
    // If already started, return.
    //
    Status = gBS->LocateProtocol (
                    &gEfiRamDiskProtocolGuid,
                    NULL,
                    &DummyInterface
                    );
    if (!EFI_ERROR (Status)) {
      DEBUG ((EFI_D_INFO, "Driver already started!\n"));
      return EFI_ALREADY_STARTED;
    }
  
    //
    // Create a private data structure.
    //
    ConfigPrivate = AllocateCopyPool (sizeof (RAM_DISK_CONFIG_PRIVATE_DATA), &mRamDiskConfigPrivateDataTemplate);
    if (ConfigPrivate == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
  
    //
    // Install RAM disk configuration form
    //
    Status = InstallRamDiskConfigForm (ConfigPrivate);
    if (EFI_ERROR (Status)) {
      goto ErrorExit;
    }
  
    //
    // Install the EFI_RAM_DISK_PROTOCOL and RAM disk private data onto a
    // new handle
    //
    Status = gBS->InstallMultipleProtocolInterfaces (
                    &mRamDiskHandle,
                    &gEfiRamDiskProtocolGuid,
                    &mRamDiskProtocol,
                    &gEfiCallerIdGuid,
                    ConfigPrivate,
                    NULL
                    );
    if (EFI_ERROR (Status)) {
      goto ErrorExit;
    }
  
    //
    // Initialize the list of registered RAM disks maintained by the driver
    //
    InitializeListHead (&RegisteredRamDisks);
  
    Status = EfiCreateEventReadyToBootEx (
               TPL_CALLBACK,
               RamDiskAcpiCheck,
               NULL,
               &Event
               );
    ASSERT_EFI_ERROR (Status);
  
    return EFI_SUCCESS;
  
  ErrorExit:
    if (ConfigPrivate != NULL) {
      UninstallRamDiskConfigForm (ConfigPrivate);
    }
  
    return Status;
  }
  
  
  /**
    Unload the RamDiskDxe driver and its configuration form.
  
    @param[in] ImageHandle     The driver's image handle.
  
    @retval EFI_SUCCESS             The RamDiskDxe driver and its configuration
                                    form is unloaded.
    @retval Others                  Failed to unload the form.
  
  **/
  EFI_STATUS
  EFIAPI
  RamDiskDxeUnload (
    IN EFI_HANDLE                   ImageHandle
    )
  {
    EFI_STATUS                      Status;
    RAM_DISK_CONFIG_PRIVATE_DATA    *ConfigPrivate;
  
    Status = gBS->HandleProtocol (
                    mRamDiskHandle,
                    &gEfiCallerIdGuid,
                    (VOID **) &ConfigPrivate
                    );
    if (EFI_ERROR (Status)) {
      return Status;
    }
  
    ASSERT (ConfigPrivate->Signature == RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE);
  
    //
    // Unregister all registered RAM disks
    //
    UnregisterAllRamDisks ();
  
    gBS->UninstallMultipleProtocolInterfaces (
           mRamDiskHandle,
           &gEfiRamDiskProtocolGuid,
           &mRamDiskProtocol,
           &gEfiCallerIdGuid,
           ConfigPrivate,
           NULL
           );
  
    UninstallRamDiskConfigForm (ConfigPrivate);
  
    return EFI_SUCCESS;
  }
  