summaryrefslogtreecommitdiff
path: root/ReferenceCode/RapidStart/Smm/RapidStartSmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/RapidStart/Smm/RapidStartSmm.c')
-rw-r--r--ReferenceCode/RapidStart/Smm/RapidStartSmm.c836
1 files changed, 836 insertions, 0 deletions
diff --git a/ReferenceCode/RapidStart/Smm/RapidStartSmm.c b/ReferenceCode/RapidStart/Smm/RapidStartSmm.c
new file mode 100644
index 0000000..1e4316c
--- /dev/null
+++ b/ReferenceCode/RapidStart/Smm/RapidStartSmm.c
@@ -0,0 +1,836 @@
+/** @file
+ This SMM driver will install a S3 Entry callback SMI handler for RTC wakeup policy.
+
+@copyright
+ Copyright (c) 2011 - 2012 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Mobile Silicon Support Module" and is
+ licensed for Intel Mobile CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+
+///
+/// External include files do NOT need to be explicitly specified in real EDKII
+/// environment
+///
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGlueDxe.h"
+#include "RapidStartConfig.h"
+#include EFI_PROTOCOL_CONSUMER (RapidStartPlatformPolicy)
+#include EFI_PROTOCOL_DEPENDENCY (RapidStartGlobalNvsArea)
+
+#ifdef ISCT_FLAG
+#include EFI_PROTOCOL_PRODUCER (IsctNvsArea)
+#endif //ISCT_FLAG
+
+#include <SaAccess.h>
+#include <PchAccess.h>
+#include <PchPlatformLib.h>
+#include "RapidStartSmm.h"
+#include "RapidStartData.h"
+#include "RapidStartCommonLib.h"
+#include "RapidStartAhciReg.h"
+#endif
+
+#define DAY_IN_SEC (24 * 60 * 60)
+#define RAPID_START_DELTA_SEC 45
+
+EFI_GUID gRapidStartPersistantDataGuid = RAPID_START_PERSISTENT_DATA_GUID;
+CHAR16 gRapidStartPersistantDataName[] = RAPID_START_PERSISTENT_DATA_NAME;
+
+RAPID_START_PERSISTENT_DATA *mRapidStartData;
+RAPID_START_MEM_DATA *mRapidStartMemData;
+RAPID_START_GLOBAL_NVS_AREA *mRapidStartGlobalNvs;
+UINT32 *mRapidStartZeroPageBitMap;
+UINT32 *mCrc32Record;
+
+#ifdef ISCT_FLAG
+ISCT_NVS_AREA *mIsctNvs;
+#endif //ISCT_FLAG
+/**
+ Convert RTC_TIME structure data to seconds
+
+ @param[in] tm A time data structure including second, minute and hour fields.
+
+ @retval A number of seconds converted from given RTC_TIME structure data.
+**/
+STATIC
+UINT32
+TimeToSeconds (
+ IN RTC_TIME *tm
+ )
+{
+ ASSERT (tm->Hour < 24);
+ ASSERT (tm->Minute < 60);
+ ASSERT (tm->Second < 60);
+ return ((tm->Hour * 60) + tm->Minute) * 60 + tm->Second;
+}
+
+/**
+ Check if it is leap year
+
+ @param[in] Year year to be check
+
+ @retval True year is leap year
+ @retval FALSE year is not a leap year
+**/
+BOOLEAN
+IsLeapYear (
+ IN UINT16 Year
+ )
+{
+ return (Year % 4 == 0) && ((Year % 100 != 0) || (Year % 400 == 0));
+}
+
+STATIC UINT8 mDaysOfMonthInfo[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+/**
+ Check if it is leap year
+
+ @param[in] Year Year number
+ @param[in] Month Month number, January is 1, Feburary is 2, ... December is 12.
+
+ @retval Days Number of day of the Month of the Year
+**/
+UINT8
+DaysOfMonth (
+ IN UINT16 Year,
+ IN UINT8 Month
+ )
+{
+ UINT8 Days;
+ if (Month < 1 || Month > 12) {
+ return 0;
+ }
+
+ Days = mDaysOfMonthInfo[Month - 1];
+ if (Month == 2) {
+ Days += IsLeapYear (Year);
+ }
+
+ return Days;
+}
+
+/**
+ Convert seconds to RTC_TIME structure data
+
+ @param[out] tm A time data structure which will be updated with converted value.
+ @param[in] Seconds Total seconds that will be converted into RTC_TIME
+**/
+STATIC
+VOID
+SecondsToTime (
+ OUT RTC_TIME *tm,
+ IN UINT32 Seconds
+ )
+{
+ tm->Second = Seconds % 60;
+ Seconds /= 60;
+ tm->Minute = Seconds % 60;
+ Seconds /= 60;
+ tm->Hour = Seconds % 24;
+ tm->Date = 0;
+}
+
+/**
+ Check if tm2 is after 2 days of tm1
+
+ @param tm1 First time to compare
+ @param tm2 Second time to compare
+
+ @retval TRUE tm2 is 2 days after tm1
+ @retval FALSE tm2 is not 2 days after tm1
+**/
+BOOLEAN
+IsOver2Days (
+ IN RTC_TIME *tm1,
+ IN RTC_TIME *tm2
+)
+{
+ BOOLEAN RetVal;
+ RetVal = TRUE;
+ if (tm2->Date > tm1->Date) {
+ if (tm2->Date - tm1->Date == 1) {
+ RetVal = FALSE;;
+ }
+ } else if ((DaysOfMonth (tm1->Year, tm1->Month) == tm1->Date) && (tm2->Date == 1)) {
+ RetVal = FALSE;;
+ }
+ return RetVal;
+}
+
+/**
+ Adjusts RTC Alarm setting according to RapidStart platform policy.
+
+ @param[in] WakeAfter Time offset in seconds to wake from S3
+
+ @retval EFI_SUCCESS Timer started successfully
+ @retval EFI_ALREADY_STARTED Timer already set sooner than desired
+**/
+STATIC
+EFI_STATUS
+RapidStartAdjustRtcAlarm (
+ IN UINT32 WakeAfter
+ )
+{
+ UINT32 CurrentTime;
+ UINT32 AlarmTime;
+ UINT32 WakeTime;
+ RTC_TIME tm;
+ RTC_TIME wake_tm;
+ EFI_STATUS Status, RtcStatus;
+ UINT16 PmBase;
+#ifdef ISCT_FLAG
+ UINT32 IsctWakeAfter;
+ RTC_TIME Isct_wake_tm;
+#endif // ISCT_FLAG
+
+ Status = EFI_SUCCESS;
+
+ ///
+ /// For an instant wake 2 seconds is a safe value
+ ///
+ if (WakeAfter < 2) {
+ WakeAfter = 2;
+ }
+ ///
+ /// Make sure RTC is in BCD and 24h format
+ ///
+ RtcInit ();
+
+ RtcStatus = RtcGetTime (&tm);
+ ASSERT_EFI_ERROR (RtcStatus);
+
+ CurrentTime = TimeToSeconds (&tm);
+
+#ifdef ISCT_FLAG
+ IsctWakeAfter = 0;
+ Isct_wake_tm.Second = 0;
+ Isct_wake_tm.Minute = 0;
+ Isct_wake_tm.Hour = 0;
+ Isct_wake_tm.Date = 0;
+ Isct_wake_tm.Month = 0;
+ Isct_wake_tm.Year = 0;
+
+ //
+ // Get Isct wake up time
+ //
+ if (mIsctNvs != NULL) {
+ mIsctNvs->IsctOverWrite = 0;
+
+ IsctWakeAfter = mIsctNvs->RtcDurationTime;
+ if ((IsctWakeAfter != 0) && (IsctWakeAfter < 2)) {
+ IsctWakeAfter = 2;
+ }
+ }
+
+ SecondsToTime (&Isct_wake_tm, IsctWakeAfter + CurrentTime);
+#endif //ISCT_FLAG
+ RtcStatus = RtcGetAlarm (&wake_tm);
+ if (RtcStatus == EFI_SUCCESS && (!(mRapidStartMemData->EntryCanceled))) {
+ AlarmTime = TimeToSeconds (&wake_tm);
+ ///
+ /// When OS set alarm date to zero,
+ /// that would mean the alarm date is today or next day depending alarm time,
+ /// and the alarm will happen in 24 hour.
+ ///
+ if (wake_tm.Date != 0 && wake_tm.Date != tm.Date) {
+ ///
+ /// OS Wake-up time is over 1 day
+ ///
+ AlarmTime += DAY_IN_SEC;
+ if (IsOver2Days (&tm, &wake_tm)) {
+ ///
+ /// OS Wake-up time is over 2 day
+ ///
+ AlarmTime += DAY_IN_SEC;
+ }
+ } else if (AlarmTime < CurrentTime && wake_tm.Date == 0) {
+ ///
+ /// When alarm time behind current time and alarm date is zero,
+ /// OS set the alarm for next day
+ //
+ AlarmTime += DAY_IN_SEC;
+ }
+ ///
+ /// OS RTC alarm set sooner than RapidStart entry after
+ /// Add some seconds so RapidStart wake time won't overcome the OS timer
+ ///
+ if ((WakeAfter + RAPID_START_DELTA_SEC >= AlarmTime - CurrentTime)
+#ifdef ISCT_FLAG
+ ///
+ /// OS RTC alarm set sooner than Isct alarm
+ ///
+ && ((IsctWakeAfter >= AlarmTime - CurrentTime) || (IsctWakeAfter == 0))
+#endif // ISCT_FLAG
+ ) {
+ return EFI_ALREADY_STARTED;
+ }
+ ///
+ /// Store OS wake-up time, so it can be restored upon entering RapidStart
+ ///
+ mRapidStartMemData->OsWakeTime = wake_tm;
+ mRapidStartMemData->OsWakeTimeEnabled = 1;
+#ifdef ISCT_FLAG
+ ///
+ /// ISCT time is smaller than OS's, so store ISCT wake-up time, so it can be restored upon entering RapidStart
+ ///
+ if ((IsctWakeAfter <= AlarmTime - CurrentTime) && (IsctWakeAfter != 0)) {
+ mRapidStartMemData->OsWakeTime = Isct_wake_tm;
+ mIsctNvs->IsctOverWrite = 1;
+ }
+#endif // ISCT_FLAG
+ }
+
+ WakeTime = CurrentTime + WakeAfter;
+#ifdef ISCT_FLAG
+ ///
+ /// ISCT alarm set sooner than RapidStart entry after
+ /// Add some seconds so RapidStart wake time won't overcome the ISCT timer
+ ///
+ if ((IsctWakeAfter <= WakeAfter + RAPID_START_DELTA_SEC) && (IsctWakeAfter != 0)) {
+ WakeTime = CurrentTime + IsctWakeAfter;
+ mIsctNvs->IsctOverWrite = 1;
+ Status = EFI_NOT_STARTED;
+ }
+
+ ///
+ /// OS hasn't set up the wake-up time, so store ISCT wake-up time then it can be restored upon entering RapidStart
+ ///
+ if (mRapidStartMemData->OsWakeTimeEnabled == 0 && IsctWakeAfter != 0) {
+ mRapidStartMemData->OsWakeTime = Isct_wake_tm;
+ mRapidStartMemData->OsWakeTimeEnabled = 1;
+ mIsctNvs->IsctOverWrite = 1;
+ }
+#endif // ISCT_FLAG
+
+ SecondsToTime (&tm, WakeTime);
+
+ RtcStatus = RtcSetAlarm (&tm);
+ ASSERT_EFI_ERROR (RtcStatus);
+
+ PmBase = (UINT16) (PciRead32 (
+ PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_ACPI_BASE)
+ ) & B_PCH_LPC_ACPI_BASE_BAR);
+
+ ///
+ /// Clear RTC PM1 status
+ ///
+ IoWrite16 (PmBase + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);
+
+ ///
+ /// set RTC_EN bit in PM1_EN to wake up from the alarm
+ ///
+ IoWrite16 (
+ PmBase + R_PCH_ACPI_PM1_EN,
+ (IoRead16 (PmBase + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC)
+ );
+ return Status;
+}
+
+#ifdef ISCT_FLAG
+/**
+ Adjusts RTC Alarm setting according to Isct.
+
+ @retval EFI_SUCCESS Timer started successfully
+ @retval EFI_ALREADY_STARTED Timer already set sooner than desired
+**/
+STATIC
+EFI_STATUS
+IsctAdjustRtcAlarm (
+ )
+{
+ UINT32 CurrentTime;
+ UINT32 AlarmTime;
+ UINT32 WakeTime;
+ RTC_TIME tm;
+ RTC_TIME wake_tm;
+ EFI_STATUS Status, RtcStatus;
+ UINT16 PmBase;
+ UINT32 IsctWakeAfter;
+ RTC_TIME Isct_wake_tm;
+
+ Status = EFI_SUCCESS;
+
+ DEBUG((EFI_D_INFO, "IsctAdjustRtcAlarm() Begin.\n"));
+
+ ///
+ /// Make sure RTC is in BCD and 24h format
+ ///
+ RtcInit ();
+
+ RtcStatus = RtcGetTime (&tm);
+ ASSERT_EFI_ERROR (RtcStatus);
+
+ CurrentTime = TimeToSeconds (&tm);
+
+ IsctWakeAfter = 0;
+ Isct_wake_tm.Second = 0;
+ Isct_wake_tm.Minute = 0;
+ Isct_wake_tm.Hour = 0;
+ Isct_wake_tm.Date = 0;
+ Isct_wake_tm.Month = 0;
+ Isct_wake_tm.Year = 0;
+
+ if (mIsctNvs == NULL) {
+ return EFI_ABORTED;
+ }
+
+ mIsctNvs->IsctOverWrite = 0;
+
+ //
+ // Get Isct wake up time
+ //
+ IsctWakeAfter = mIsctNvs->RtcDurationTime;
+ if ((IsctWakeAfter != 0) && (IsctWakeAfter < 2)) {
+ IsctWakeAfter = 2;
+ }
+
+ SecondsToTime (&Isct_wake_tm, IsctWakeAfter + CurrentTime);
+
+ RtcStatus = RtcGetAlarm (&wake_tm);
+ if (RtcStatus == EFI_SUCCESS) {
+ AlarmTime = TimeToSeconds (&wake_tm);
+ ///
+ /// When OS set alarm date to zero,
+ /// that would mean the alarm date is today or next day depending alarm time,
+ /// and the alarm will happen in 24 hour.
+ ///
+ if (wake_tm.Date != 0 && wake_tm.Date != tm.Date) {
+ ///
+ /// OS Wake-up time is over 1 day
+ ///
+ AlarmTime += DAY_IN_SEC;
+ if (IsOver2Days (&tm, &wake_tm)) {
+ ///
+ /// OS Wake-up time is over 2 day
+ ///
+ AlarmTime += DAY_IN_SEC;
+ }
+ } else if (AlarmTime < CurrentTime && wake_tm.Date == 0) {
+ ///
+ /// When alarm time behind current time and alarm date is zero,
+ /// OS set the alarm for next day
+ //
+ AlarmTime += DAY_IN_SEC;
+ }
+ ///
+ /// OS RTC alarm set sooner than Isct alarm
+ ///
+ if ((IsctWakeAfter >= AlarmTime - CurrentTime) || (IsctWakeAfter == 0)) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ mIsctNvs->IsctOverWrite = 1;
+
+ WakeTime = CurrentTime + IsctWakeAfter;
+ Status = EFI_NOT_STARTED;
+
+ SecondsToTime (&tm, WakeTime);
+
+ RtcStatus = RtcSetAlarm (&tm);
+ ASSERT_EFI_ERROR (RtcStatus);
+
+ PmBase = (UINT16) (PciRead32 (
+ PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_ACPI_BASE)
+ ) & B_PCH_LPC_ACPI_BASE_BAR);
+
+ ///
+ /// Clear RTC PM1 status
+ ///
+ IoWrite16 (PmBase + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);
+
+ ///
+ /// set RTC_EN bit in PM1_EN to wake up from the alarm
+ ///
+ IoWrite16 (
+ PmBase + R_PCH_ACPI_PM1_EN,
+ (IoRead16 (PmBase + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC)
+ );
+
+ DEBUG((EFI_D_INFO, "IsctAdjustRtcAlarm() End.\n"));
+
+ return Status;
+}
+#endif // ISCT_FLAG
+
+/**
+ Scan Zero page within specific memory range.
+
+ @param[in] BaseAddress Start address of memory
+ @param[in] EndAddress End address of memory
+
+ @retval SaveSize Save Size requirement
+**/
+STATIC
+UINTN
+ScanZeroPageByRange (
+ IN UINT64 BaseAddress,
+ IN UINT64 EndAddress
+ )
+{
+ UINT64 NonZeroPointer;
+ UINT32 TempBitMap;
+ UINTN count;
+ UINT32 *ZeroPagePointer;
+ UINTN SaveSize;
+
+ count = 0;
+ TempBitMap = 0;
+ ZeroPagePointer = mRapidStartZeroPageBitMap + 2 + (UINT32) NUMBER_OF_PAGES_IN_DWORD (BaseAddress);
+ SaveSize = 0;
+ while (BaseAddress < EndAddress) {
+ NonZeroPointer = (UINT64)ScanValueMem64 ((VOID*)BaseAddress, EFI_PAGE_SIZE/ sizeof (UINT64), 0);
+ BaseAddress += EFI_PAGE_SIZE;
+ NonZeroPointer++;
+ if (NonZeroPointer == 0) {
+ //
+ // This is Zero Page so we set the corresponding bit in BitMap.
+ //
+ TempBitMap |= 1;
+ } else {
+ SaveSize += EFI_PAGE_SIZE;
+ }
+
+ TempBitMap = RRotU32 (TempBitMap, 1);
+ count++;
+ if (count == (sizeof (*mRapidStartZeroPageBitMap) * 8)) {
+ *ZeroPagePointer = TempBitMap;
+ count = 0;
+ TempBitMap = 0;
+ ZeroPagePointer += 1;
+ if ((UINTN) ((UINTN) ZeroPagePointer - (UINTN) (mRapidStartZeroPageBitMap + 2)) >= mRapidStartData->ZeroBitmapSize) {
+ //
+ // Zero page filter table is full, skip other checking.
+ //
+ SaveSize += (UINTN)(EndAddress - BaseAddress);
+ break;
+ }
+ }
+
+ }
+ return SaveSize;
+}
+
+/**
+ Create a bitmap for zero page filter.
+
+ @retval Save Size requirement
+**/
+STATIC
+UINTN
+BuildZeroPageBitMap (
+ VOID
+ )
+{
+ UINT32 GfxGTTBase;
+ UINTN SaveSize;
+
+ SaveSize = 0;
+ GfxGTTBase = (PciRead32 (
+ PCI_LIB_ADDRESS (SA_MC_BUS,
+ SA_MC_DEV,
+ SA_MC_FUN,
+ R_SA_BGSM)
+ ) & B_SA_BGSM_BGSM_MASK);
+
+ ///
+ /// Ensure all ZeroPageBitMap were zero-ed
+ ///
+ ZeroMem (mRapidStartZeroPageBitMap, mRapidStartData->ZeroBitmapSize);
+
+#ifdef RAPID_START_SCAN_ZERO_PAGE
+ ///
+ /// Handle Below 4GB memory
+ /// Skip GTT region
+ ///
+ SaveSize = ScanZeroPageByRange (0x0, GfxGTTBase);
+
+#if defined(EFIX64)
+ ///
+ /// Handle Above 4GB memory
+ ///
+ if (mRapidStartData->Tohm > MEM_EQU_4GB) {
+ SaveSize += ScanZeroPageByRange (MEM_EQU_4GB, mRapidStartData->Tohm);
+ }
+#endif
+#endif
+ return SaveSize;
+}
+
+#ifdef RAPID_START_WHOLE_MEMORY_CHECK
+/**
+ Log or compare CRC32 value for above 4GB memory.
+
+ @param[in] IsComparingCrc32 - FALSE to save CRC32 value into buffer. TRUE to compare CRC32 value with pre-saved value in buffer.
+**/
+VOID
+SaveOrCompareCrc32ForAbove4GB (
+ IN BOOLEAN IsComparingCrc32
+ )
+{
+#if defined(EFIX64)
+ if (mRapidStartData->Tohm > MEM_EQU_4GB) {
+ SaveOrCompareCrc32 (IsComparingCrc32, MEM_EQU_4GB, mRapidStartData->Tohm, mRapidStartData);
+ }
+#endif
+}
+
+/**
+ A SW SMI callback to check whole memory CRC32
+
+ @param[in] DispatchHandle - The handle of this callback, obtained when registering
+ @param[in] DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
+**/
+VOID
+RapidStartSwSmiCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
+ )
+{
+ if (mRapidStartGlobalNvs->EventsEnabled) {
+ SaveOrCompareCrc32ForAbove4GB (TRUE);
+ }
+}
+#endif
+
+/**
+ RapidStart S3 entry callback SMI handler
+
+ @param[in] DispatchHandle - The handle of this callback, obtained when registering
+ @param[in] DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
+**/
+VOID
+EFIAPI
+RapidStartS3EntryCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
+ )
+{
+ UINT16 PmBase;
+ EFI_STATUS Status;
+ UINTN SaveSize;
+ UINT32 CheckingSizeInSector;
+ UINT8 EventsEnabledFlag;
+ PCH_SERIES PchSeries;
+
+ mRapidStartMemData->OsWakeTimeEnabled = 0;
+ EventsEnabledFlag = 0;
+ PchSeries = GetPchSeries();
+
+ Status = EFI_SUCCESS;
+ if (mRapidStartMemData->EntryCanceled) {
+ ///
+ /// Immediate wake system up regardless of original setting.
+ ///
+ RapidStartAdjustRtcAlarm (0);
+ Status = EFI_NOT_STARTED;
+ mRapidStartMemData->EntryCanceled = 0;
+ } else {
+ /* mRapidStartMemData->EntryCanceled */
+ if (mRapidStartGlobalNvs->EventsEnabled) {
+ SaveSize = BuildZeroPageBitMap ();
+ if (mRapidStartData->ActivePageThresholdSizeInSector == 0) {
+ ///
+ /// In AUTO mode, RapidStart will check the partition size automatically with active memory size
+ ///
+ CheckingSizeInSector = mRapidStartData->StoreSectors;
+ } else {
+ ///
+ /// If Active Page Threshold Size is set manually, RapidStart compare this with active memory size
+ ///
+ CheckingSizeInSector = mRapidStartData->ActivePageThresholdSizeInSector;
+ }
+ if (MEM_TO_SECT (SaveSize + mRapidStartData->ZeroBitmapSize + mRapidStartData->Crc32RecordSize) > CheckingSizeInSector) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+#ifdef RAPID_START_WHOLE_MEMORY_CHECK
+ if (!EFI_ERROR (Status)) {
+ SaveOrCompareCrc32ForAbove4GB (FALSE);
+ }
+#endif
+ }
+ //
+ // Enable and override KSC critical battery wake up event threshold
+ // to ensure enough battery capacity for RapidStart Entry transition
+ //
+ if (!EFI_ERROR (Status)) {
+ if (mRapidStartGlobalNvs->EventsEnabled & RAPID_START_ACPI_BATT_WAKE) {
+ RapidStartInitializeCriticalBatteryWakeupEvent (TRUE);
+ EventsEnabledFlag |= RAPID_START_ACPI_BATT_WAKE;
+ }
+
+ if (mRapidStartGlobalNvs->EventsEnabled & RAPID_START_ACPI_RTC_WAKE) {
+ Status = RapidStartAdjustRtcAlarm (mRapidStartGlobalNvs->WakeTimerMin * 60);
+ if (!EFI_ERROR (Status)) {
+ EventsEnabledFlag |= RAPID_START_ACPI_RTC_WAKE;
+ }
+ }
+#ifdef ISCT_FLAG
+ else {
+ IsctAdjustRtcAlarm();
+ }
+#endif
+ }
+#ifdef ISCT_FLAG
+ else {
+ IsctAdjustRtcAlarm();
+ }
+#endif
+ } /* end else: mRapidStartMemData->EntryCanceled */
+
+ RapidStartSetConfig (EventsEnabledFlag);
+
+ if (!EFI_ERROR (Status)) {
+ PmBase = (UINT16) (PciRead32 (
+ PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_ACPI_BASE)
+ ) & B_PCH_LPC_ACPI_BASE_BAR);
+
+ ///
+ /// Save wake events
+ ///
+ if (PchSeries == PchLp) {
+ mRapidStartMemData->GPE0 = IoRead32 (PmBase + R_PCH_ACPI_GPE0_EN_127_96);
+ } else if (PchSeries == PchH) {
+ mRapidStartMemData->GPE0a = IoRead32 (PmBase + R_PCH_ACPI_GPE0a_EN);
+ mRapidStartMemData->GPE0b = IoRead32 (PmBase + R_PCH_ACPI_GPE0b_EN);
+ }
+ }
+
+ AfterInitializingEntryEvent (Status);
+ return;
+}
+
+/**
+ Initializes the SMM S3 Handler.
+
+ @param[in] ImageHandle - The image handle of Wake On Lan driver
+ @param[in] SystemTable - The standard EFI system table
+
+ @retval EFI_SUCCESS - RapidStart S3 entry callback SMI handle has been registered when RapidStart wake up policy enabled
+**/
+EFI_STATUS
+RapidStartSmmEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ RAPID_START_GLOBAL_NVS_AREA_PROTOCOL *RapidStartGlobalNvsAreaProtocol;
+ EFI_SMM_SX_DISPATCH_PROTOCOL *SxDispatchProtocol;
+ EFI_SMM_SX_DISPATCH_CONTEXT EntryDispatchContext;
+#ifdef RAPID_START_WHOLE_MEMORY_CHECK
+ EFI_SMM_SW_DISPATCH_PROTOCOL *SwDispatch;
+ EFI_SMM_SW_DISPATCH_CONTEXT SwContext;
+#endif
+ EFI_HANDLE DispatchHandle;
+ EFI_STATUS Status;
+#ifdef ISCT_FLAG
+ ISCT_NVS_AREA_PROTOCOL *IsctNvsAreaProtocol;
+#endif //ISCT_FLAG
+
+ DEBUG ((EFI_D_INFO, "RapidStartSmmEntryPoint()\n"));
+
+ Status = gBS->LocateProtocol (
+ &gRapidStartGlobalNvsAreaProtocolGuid,
+ NULL,
+ (VOID **) &RapidStartGlobalNvsAreaProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "No RapidStart info protocol available\n"));
+ ASSERT (0);
+ return Status;
+ }
+
+#ifdef ISCT_FLAG
+ mIsctNvs = NULL;
+ ///
+ /// Locate ISCT Global NVS protocol.
+ ///
+ Status = gBS->LocateProtocol (
+ &gIsctNvsAreaProtocolGuid,
+ NULL,
+ &IsctNvsAreaProtocol
+ );
+ if (!EFI_ERROR (Status)) {
+ mIsctNvs = IsctNvsAreaProtocol->Area;
+ mIsctNvs->IsctOverWrite = 0;
+ }
+#endif //ISCT_FLAG
+ mRapidStartData = RapidStartGlobalNvsAreaProtocol->RapidStartData;
+ mRapidStartGlobalNvs = RapidStartGlobalNvsAreaProtocol->Area;
+ mRapidStartMemData = RAPID_START_MEM_DATA_PTR (mRapidStartData);
+ mRapidStartZeroPageBitMap = RAPID_START_ZERO_PAGE_BITMAP_PTR (mRapidStartData);
+ mCrc32Record = RAPID_START_CRC32_RECORD_PTR (mRapidStartData);
+
+ DEBUG ((EFI_D_INFO, "RapidStartGlobalNvs: %x\n", mRapidStartGlobalNvs));
+ DEBUG ((EFI_D_INFO, "RapidStartMemData: %x\n", mRapidStartMemData));
+ DEBUG ((EFI_D_INFO, "RapidStartZeroPageBitMap: %x\n", mRapidStartZeroPageBitMap));
+ DEBUG ((EFI_D_INFO, "CRC32 record: %x\n", mCrc32Record));
+
+ mRapidStartMemData->OsWakeTimeEnabled = 0;
+
+ Status = gBS->LocateProtocol (
+ &gEfiSmmSxDispatchProtocolGuid,
+ NULL,
+ (VOID **) &SxDispatchProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Register S3 entry phase call back function
+ ///
+ EntryDispatchContext.Type = SxS3;
+ EntryDispatchContext.Phase = SxEntry;
+ Status = SxDispatchProtocol->Register (
+ SxDispatchProtocol,
+ RapidStartS3EntryCallback,
+ &EntryDispatchContext,
+ &DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+#ifdef RAPID_START_WHOLE_MEMORY_CHECK
+ ///
+ /// Locate the SMM SW dispatch protocol
+ ///
+ Status = gBS->LocateProtocol (&gEfiSmmSwDispatchProtocolGuid, NULL, &SwDispatch);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Register SWSMI handler
+ ///
+ DEBUG ((EFI_D_INFO, "Register RapidStart SwSmi: %x\n", SW_SMI_WHOLE_MEMORY_CHECK));
+ SwContext.SwSmiInputValue = SW_SMI_WHOLE_MEMORY_CHECK;
+ Status = SwDispatch->Register (
+ SwDispatch,
+ RapidStartSwSmiCallback,
+ &SwContext,
+ &DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+#endif
+
+ return EFI_SUCCESS;
+}