Exemplo n.º 1
0
EFI_STATUS
EFIAPI
AmdRasApeiDxeDriverEntryPoint (
  IN   EFI_HANDLE        ImageHandle,
  IN   EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS                      Status = EFI_SUCCESS;
  EFI_HANDLE                      Handle = NULL;
  EFI_HANDLE                      hEinj = NULL;
  AMD_RAS_APEI_PROTOCOL           *AmdRasApeiProtocol;
  BOOLEAN                         InSmm;
  EFI_SMM_BASE_PROTOCOL           *SmmBase = NULL;
  EFI_DEVICE_PATH_PROTOCOL        *ImageDevicePath = NULL;
  EFI_DEVICE_PATH_PROTOCOL        *NewFilePath = NULL;
  EFI_LOADED_IMAGE_PROTOCOL       *LoadedImage = NULL;
  EFI_SMM_SW_DISPATCH_PROTOCOL    *SwDispatch = NULL;
  EFI_SMM_SW_DISPATCH_CONTEXT     SwContext;
  EFI_ACPI_SUPPORT_PROTOCOL       *AcpiSupportProtocol = NULL;
  EFI_HANDLE                      SwHandle = NULL;
  EFI_HANDLE                      hNewHandle = NULL;
  UINTN                           BufferSize;
  UINTN                           HestTblHandle;
  UINT64                          Address64;
  UINT32                          Value32;
  //
  // Initialize Local Variables
  //
  InSmm = FALSE;
  BufferSize = 0;
  HestTblHandle = 0;

  //
  // Initialize Global Variables
  //
  EfiInitializeApei (ImageHandle, SystemTable);

  // Locate SMM Base Protocol
  Status  = gBS->LocateProtocol (
                                 &gEfiSmmBaseProtocolGuid,  // IN EFI_GUID Published unique identifier of requested protocol GUID to locate
                                 NULL,                      // IN VOID* Published unique identifier of requested protocol GUID
                                 &SmmBase                   // OUT VOID** Returns address of pointer for SMM Base protocol interface
                                 );

  if (EFI_ERROR (Status)) {
    ASSERT_EFI_ERROR (Status);
    return Status;     // Error detected while trying to locate SMM Base Protocol
  }

  // Save the SMM Base system table pointer
  SmmBase->GetSmstLocation (SmmBase, &gSmst);

  // Determine if we are in SMM or not
  SmmBase->InSmm (SmmBase, &InSmm);

  if (!InSmm) {
    // Query image handle to see if it supports a requested protocol and then get an address of the protocol image to be loaded
    Status = gBS->HandleProtocol (
                                  ImageHandle,                  // Handle of requested protocol
                                  &gEfiLoadedImageProtocolGuid, // Published unique identifier of requested protocol GUID
                                  (VOID*)&LoadedImage           // Returns address of pointer for requested protocol interface of the image
                                  );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return Status;            // Error detected while trying to query LoadImage protocol
    }

    // Query device handle of loaded image to see if it supports a requested protocol and then get an address of the prototocl device path
    Status = gBS->HandleProtocol (
                                  LoadedImage->DeviceHandle,   // Handle of requested protocol
                                  &gEfiDevicePathProtocolGuid, // Published unique identifier of requested protocol GUID
                                  (VOID*) &ImageDevicePath     // Returns address of pointer for requested protocol interface
                                  );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return Status;
    }

    // Add this image's device path to the loaded image device path image and return
    // a pointer to the new file path.
    NewFilePath = AddDevicePath (
                                 ImageDevicePath,         // IN EFI_DEVICE_PATH_PROTOCOL*
                                 LoadedImage->FilePath    // IN EFI_DEVICE_PATH_PROTOCOL* Device Path Image to add
                                 );

    //Load the image in System Management RAM; it will automatically generate an SMI.
    Status = SmmBase->Register (
                                SmmBase,      // IN *This Addreess of pointer for SMM Base protocol interface)
                                NewFilePath,  // IN EFI_DEVICE_PATH_PROTOCOL
                                NULL,         // IN SourceBuffer OPTIONAL
                                0,            // IN SourceSize OPTIONAL
                                &hEinj,       // OUT *ImageHandle
                                FALSE         // IN LegacyIA32Binary OPTIONAL
                                );

    // Free up residual heap memory if not equal to NULL
    if (NewFilePath) {
      gBS->FreePool (NewFilePath);
    }

    if (EFI_ERROR (Status)) {
      switch (EFIERR (Status))
      {
      case EFI_LOAD_ERROR:
        break;
      case EFI_INVALID_PARAMETER:
        break;
      case EFI_UNSUPPORTED:
        break;
      default:
        ;
      }
      return Status;
    }
  } else {
    // We are in SMM...
    // Allocate Memory for type Runtime Services Data - APEI Module Private Data
    Status = gBS->AllocatePool (EfiRuntimeServicesData, sizeof (APEI_DRIVER_PRIVATE_DATA), &mApeiPrivData);
    if (EFI_ERROR (Status)) {
      return Status;
    }

    // Allocate Memory for type Runtime Services Data - APEI Interface
    Status = gBS->AllocatePool (EfiRuntimeServicesData, sizeof (AMD_APEI_INTERFACE), &mApeiInterface);
    if (EFI_ERROR (Status)) {
      return Status;
    }

    // Locate SW SMM Dispatch Protocol
    Status  = gBS->LocateProtocol (
                                   &gEfiSmmSwDispatchProtocolGuid, // IN EFI_GUID Published unique identifier of requested protocol GUID to locate
                                   NULL,                           // IN VOID* Published unique identifier of requested protocol GUID
                                   &SwDispatch                     // OUT VOID** Returns address of pointer for SMM Base protocol interface
                                   );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return Status;
    }

    SwContext.SwSmiInputValue = EINJ_BEGIN_INJ_CMD;
    // Register EINJ SMM callback handler.
    Status = SwDispatch->Register (
                                   SwDispatch,           // IN *This
                                   ApeiEinjSwSmiHandler, // IN EFI SW SMM Dispatcher Callback Entry Point Address
                                   &SwContext,           // IN SwContext
                                   &SwHandle             // IN OUT SwHandle
                                   );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return Status;
    }

    SwContext.SwSmiInputValue = ERST_EXECUTE_OPERATION_CMD;
    // Register ERST SMM callback handler.
    Status = SwDispatch->Register (
                                   SwDispatch,
                                   ApeiErstSwSmiHandler,
                                   &SwContext,
                                   &SwHandle
                                   );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return Status;
    }

    // Allocate Memory for the the AMD_RAS_APEI_PROTOCOL protocol.
    Status = gBS->AllocatePool (
                                EfiBootServicesData,              // IN EFI_MEMORY_TYPE PoolType
                                sizeof (AMD_RAS_APEI_PROTOCOL),   // IN UINTN Size
                                &AmdRasApeiProtocol               // OUT VOID **Buffer
                                );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return EFI_OUT_OF_RESOURCES;    // Error detected while trying to locate SMM Base Protocol
    }

    EfiCommonLibZeroMem (AmdRasApeiProtocol, sizeof (AMD_RAS_APEI_PROTOCOL));

    // Initialize BERT
    ApeiBertInit ();
    // Initialize HEST
    ApeiHestInit ();
    // Determine if we have ECC error enable bits set
    Address64 = mCfgMmioBase | ((0x18 << 15) | (3 << 12) | 0x44); //F3:44 MC4_NB_CFG
    Value32 = RasSmmReadMem32 (Address64);
    if (Value32 & (1 << 22)) {
      //Initialize EINJ if ECC is Enabled
      ApeiEinjInit ();
    }
    // Initialize ERST
    ApeiErstInit ();

    AmdRasApeiProtocol->AmdApeiInterface = mApeiInterface;
    mApeiInterface->ApeiPrivData = mApeiPrivData;

    AmdRasApeiProtocol->AddBootErrorRecordEntry = 0;
    AmdRasApeiProtocol->AddHestErrorSourceEntry = 0;

    Status = gBS->InstallProtocolInterface (
                                            &Handle,                  // IN OUT EFI_HANDLE
                                            &gAmdRasApeiProtocolGuid, // IN EFI_GUID
                                            EFI_NATIVE_INTERFACE,     // IN EFI_INITERFACE_TYPE
                                            AmdRasApeiProtocol        // IN VOID* Interface
                                            );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return EFI_PROTOCOL_ERROR;    // Error detected while trying to locate SMM Base Protocol
    }
  } // End-- if(!InSmm)

  //
  // Do more non-SMM configuration
  //
  if (!InSmm) {
    Status = gBS->LocateProtocol (
                                  &gAmdRasApeiProtocolGuid,
                                  NULL,
                                  &AmdRasApeiProtocol
                                  );

    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return EFI_PROTOCOL_ERROR;   // Error detected while trying to locate SMM Base Protocol
    }

    mApeiInterface = AmdRasApeiProtocol->AmdApeiInterface;
    mApeiPrivData = mApeiInterface->ApeiPrivData;

    // Initialize function pointers to protocol interfaces
    AmdRasApeiProtocol->AddBootErrorRecordEntry = &AddBertErrorRecord;
    AmdRasApeiProtocol->AddHestErrorSourceEntry = &AddHestErrorRecord;

    //
    //  Find the protocol that was installed during SMM phase and reinstall it during
    //  Non-SMM phase as well.
    //

    // Get the buffer size for the EFI_HANDLE
    BufferSize = sizeof (EFI_HANDLE);

    // Returns an array of handles that support a specified protocol.
    Status = gBS->LocateHandle (
                                ByProtocol,               // IN EFI_LOCATE_SEARCH_TYPE SearchType
                                &gAmdRasApeiProtocolGuid, // IN EFI_GUID *Protocol OPTIONAL
                                NULL,                     // IN VOID *SearchKey OPTIONAL
                                &BufferSize,              // IN OUT UINTN BufferSize
                                &hNewHandle               // OUT EFI_HANDLE *Buffer
                                );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return EFI_PROTOCOL_ERROR;   // Error detected while trying to locate SMM Base Protocol
    }

    // Queries a handle to determine if it supports a specified protocol.
    Status = gBS->HandleProtocol (
                                  hNewHandle,                     // IN EFI_HANDLE Handle
                                  &gAmdRasApeiProtocolGuid,       // IN EFI_GUID *Protocol
                                  (VOID **) &AmdRasApeiProtocol   // OUT VOID *NewInterface
                                  );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return EFI_PROTOCOL_ERROR;    // Error detected while trying to locate SMM Base Protocol
    }

    // Local ACPI Protocol
    Status = gBS->LocateProtocol (
                                  &gAcpiSupportGuid,
                                  NULL,
                                  (VOID **) &AcpiSupportProtocol
                                  );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return EFI_PROTOCOL_ERROR;    // Error detected while trying to locate ACPI Support Protocol
    }

    //Add HEST table to the ACPI aware OS
    Status = AcpiSupportProtocol->SetAcpiTable (
                                                AcpiSupportProtocol,                        // IN EFI_ACPI_SUPPORT_PROTOCOL *This
                                                mApeiInterface->ApeiPrivData->ApeiHestTbl,  // IN VOID  *Table OPTIONAL
                                                TRUE,                                       // IN BOOLEAN Checksum
                                                EFI_ACPI_TABLE_VERSION_ALL,                 // IN EFI_ACPI_TABLE_VERSION Version
                                                &HestTblHandle                              // IN OUT UINTN *TableHandle
                                                );
    ASSERT_EFI_ERROR (Status);

    // Reinstalls a protocol interface on a device handle.
    Status = gBS->ReinstallProtocolInterface (
                                              hNewHandle,               // IN EFI_HANDLE Handle
                                              &gAmdRasApeiProtocolGuid, // IN EFI_GUID *Protocol
                                              AmdRasApeiProtocol,       // IN VOID *OldInterface
                                              AmdRasApeiProtocol        // IN VOID *NewInterface
                                              );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return EFI_PROTOCOL_ERROR;    // Error detected while trying to locate SMM Base Protocol
    }

    // Create a callback event to be executed at ReadyToBoot to publish APEI tables to OS.
    Status = gBS->CreateEventEx (
                                 EFI_EVENT_NOTIFY_SIGNAL,
                                 EFI_TPL_NOTIFY,
                                 AddApeiTables,
                                 NULL,
                                 &gEfiEventReadyToBootGuid,
                                 &mEvtApeiReadyToBoot
                                 );
    if (EFI_ERROR (Status)) {
      ASSERT_EFI_ERROR (Status);
      return EFI_OUT_OF_RESOURCES;    // Error detected while trying to locate SMM Base Protocol
    }
  }

  return Status;
}
Exemplo n.º 2
0
EFI_STATUS
EFIAPI
InitializePlatformSmm (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS                                Status;
  UINT8                                     Index;
  EFI_HANDLE                                Handle;
  EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT     PowerButtonContext;
  EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL    *PowerButtonDispatch;
  EFI_SMM_ICHN_DISPATCH_CONTEXT             IchnContext;
  EFI_SMM_ICHN_DISPATCH_PROTOCOL            *IchnDispatch;
  EFI_SMM_SX_DISPATCH_PROTOCOL              *SxDispatch;
  EFI_SMM_SX_DISPATCH_CONTEXT               EntryDispatchContext;
  EFI_SMM_SW_DISPATCH_PROTOCOL              *SwDispatch;
  EFI_SMM_SW_DISPATCH_CONTEXT               SwContext;
  UINTN                                     VarSize;
  EFI_BOOT_MODE                             BootMode;

  Handle = NULL;

  //
  //  Locate the Global NVS Protocol.
  //
  Status = gBS->LocateProtocol (
                  &gEfiGlobalNvsAreaProtocolGuid,
                  NULL,
                  (void **)&mGlobalNvsAreaPtr
                  );
  ASSERT_EFI_ERROR (Status);


  //
  // Get the ACPI Base Address
  //

  mAcpiBaseAddr = PchLpcPciCfg16( R_PCH_LPC_ACPI_BASE ) & B_PCH_LPC_ACPI_BASE_BAR;

  VarSize = sizeof(SYSTEM_CONFIGURATION);
  Status = SystemTable->RuntimeServices->GetVariable(
                          L"Setup",
                          &gEfiSetupVariableGuid,
                          NULL,
                          &VarSize,
                          &mSystemConfiguration
                          );
  if (EFI_ERROR (Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
    //The setup variable is corrupted
    VarSize = sizeof(SYSTEM_CONFIGURATION);
    Status = SystemTable->RuntimeServices->GetVariable(
              L"SetupRecovery",
              &gEfiSetupVariableGuid,
              NULL,
              &VarSize,
              &mSystemConfiguration
              );
    ASSERT_EFI_ERROR (Status);
  }  
  if (!EFI_ERROR(Status)) {
    mAcLossVariable = mSystemConfiguration.StateAfterG3;

    //
    // If LAN is disabled, WOL function should be disabled too.
    //
    if (mSystemConfiguration.Lan == 0x01){
      mWakeOnLanS5Variable = mSystemConfiguration.WakeOnLanS5;
    } else {
      mWakeOnLanS5Variable = FALSE;
    }

    mWakeOnRtcVariable = mSystemConfiguration.WakeOnRtcS5;
  }

  BootMode = GetBootModeHob ();

  //
  // Get the Power Button protocol
  //
  Status = gBS->LocateProtocol(
                  &gEfiSmmPowerButtonDispatchProtocolGuid,
                  NULL,
                  (void **)&PowerButtonDispatch
                  );
  ASSERT_EFI_ERROR(Status);

  if (BootMode != BOOT_ON_FLASH_UPDATE) {
    //
    // Register for the power button event
    //
    PowerButtonContext.Phase = PowerButtonEntry;
    Status = PowerButtonDispatch->Register(
                                    PowerButtonDispatch,
                                    PowerButtonCallback,
                                    &PowerButtonContext,
                                    &Handle
                                    );
    ASSERT_EFI_ERROR(Status);
  }
  //
  // Get the Sx dispatch protocol
  //
  Status = gBS->LocateProtocol (
                  &gEfiSmmSxDispatchProtocolGuid,
                  NULL,
                                  (void **)&SxDispatch
                  );
  ASSERT_EFI_ERROR(Status);

  //
  // Register entry phase call back function
  //
  EntryDispatchContext.Type  = SxS3;
  EntryDispatchContext.Phase = SxEntry;

  Status = SxDispatch->Register (
                         SxDispatch,
                           (EFI_SMM_SX_DISPATCH)SxSleepEntryCallBack,
                         &EntryDispatchContext,
                         &Handle
                         );


  EntryDispatchContext.Type  = SxS4;

  Status = SxDispatch->Register (
                         SxDispatch,
                         S4S5CallBack,
                         &EntryDispatchContext,
                         &Handle
                         );
  ASSERT_EFI_ERROR(Status);


  EntryDispatchContext.Type  = SxS5;

  Status = SxDispatch->Register (
                         SxDispatch,
                         S4S5CallBack,
                         &EntryDispatchContext,
                         &Handle
                         );
  ASSERT_EFI_ERROR(Status);

  Status = SxDispatch->Register (
                         SxDispatch,
                         S5SleepAcLossCallBack,
                         &EntryDispatchContext,
                         &Handle
                         );
  ASSERT_EFI_ERROR(Status);

  //
  //  Get the Sw dispatch protocol
  //
  Status = gBS->LocateProtocol (
                  &gEfiSmmSwDispatchProtocolGuid,
                  NULL,
                                  (void **)&SwDispatch
                  );
  ASSERT_EFI_ERROR(Status);

  //
  // Register ACPI enable handler
  //
  SwContext.SwSmiInputValue = ACPI_ENABLE;
  Status = SwDispatch->Register (
                         SwDispatch,
                         EnableAcpiCallback,
                         &SwContext,
                         &Handle
                         );
  ASSERT_EFI_ERROR(Status);

  //
  // Register ACPI disable handler
  //
  SwContext.SwSmiInputValue = ACPI_DISABLE;
  Status = SwDispatch->Register (
                         SwDispatch,
                         DisableAcpiCallback,
                         &SwContext,
                         &Handle
                         );
  ASSERT_EFI_ERROR(Status);


  //
  // Register for SmmReadyToBootCallback
  //
  SwContext.SwSmiInputValue = SMI_SET_SMMVARIABLE_PROTOCOL;
  Status = SwDispatch->Register(
                         SwDispatch,
                         SmmReadyToBootCallback,
                         &SwContext,
                         &Handle
                         );
  ASSERT_EFI_ERROR(Status);

  //
  // Get the ICHn protocol
  //
  Status = gBS->LocateProtocol(
                  &gEfiSmmIchnDispatchProtocolGuid,
                  NULL,
                  (void **)&IchnDispatch
                  );
  ASSERT_EFI_ERROR(Status);

  //
  // Register for the events that may happen that we do not care.
  // This is true for SMI related to TCO since TCO is enabled by BIOS WP
  //
  for (Index = 0; Index < sizeof(mTco1Sources)/sizeof(UINT8); Index++) {
    IchnContext.Type = mTco1Sources[Index];
    Status = IchnDispatch->Register(
                             IchnDispatch,
                             (EFI_SMM_ICHN_DISPATCH)DummyTco1Callback,
                             &IchnContext,
                             &Handle
                             );
    ASSERT_EFI_ERROR( Status );
  }

  //
  // Lock TCO_EN bit.
  //
  IoWrite16( mAcpiBaseAddr + R_PCH_TCO_CNT, IoRead16( mAcpiBaseAddr + R_PCH_TCO_CNT ) | B_PCH_TCO_CNT_LOCK );

  //
  // Set to power on from G3 dependent on WOL instead of AC Loss variable in order to support WOL from G3 feature.
  //
  //
  // Set wake from G3 dependent on AC Loss variable and Wake On LAN variable.
  // This is because no matter how, if WOL enabled or AC Loss variable not disabled, the board needs to wake from G3 to program the LAN WOL settings.
  // This needs to be done after LAN enable/disable so that the PWR_FLR state clear not impacted the WOL from G3 feature.
  //
  if (mAcLossVariable != 0x00) {
    SetAfterG3On (TRUE);
  } else {
    SetAfterG3On (FALSE);
  }




  return EFI_SUCCESS;
}