summaryrefslogtreecommitdiff
path: root/ReferenceCode/RapidStart/Pei
diff options
context:
space:
mode:
authorraywu <raywu0301@gmail.com>2018-06-15 00:00:50 +0800
committerraywu <raywu0301@gmail.com>2018-06-15 00:00:50 +0800
commitb7c51c9cf4864df6aabb99a1ae843becd577237c (patch)
treeeebe9b0d0ca03062955223097e57da84dd618b9a /ReferenceCode/RapidStart/Pei
downloadzprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz
init. 1AQQW051HEADmaster
Diffstat (limited to 'ReferenceCode/RapidStart/Pei')
-rw-r--r--ReferenceCode/RapidStart/Pei/RapidStartAhci.c1211
-rw-r--r--ReferenceCode/RapidStart/Pei/RapidStartAhci.h344
-rw-r--r--ReferenceCode/RapidStart/Pei/RapidStartPei.c2379
-rw-r--r--ReferenceCode/RapidStart/Pei/RapidStartPei.cif14
-rw-r--r--ReferenceCode/RapidStart/Pei/RapidStartPei.dxs41
-rw-r--r--ReferenceCode/RapidStart/Pei/RapidStartPei.inf119
-rw-r--r--ReferenceCode/RapidStart/Pei/RapidStartPei.mak151
-rw-r--r--ReferenceCode/RapidStart/Pei/RapidStartPei.sdl68
8 files changed, 4327 insertions, 0 deletions
diff --git a/ReferenceCode/RapidStart/Pei/RapidStartAhci.c b/ReferenceCode/RapidStart/Pei/RapidStartAhci.c
new file mode 100644
index 0000000..7a37eb6
--- /dev/null
+++ b/ReferenceCode/RapidStart/Pei/RapidStartAhci.c
@@ -0,0 +1,1211 @@
+/** @file
+ Provide functions to initialize SATA controller and perform ACHI commands
+
+@copyright
+ Copyright (c) 1999 - 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 Reference Module" and is
+ licensed for Intel 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
+
+**/
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGluePeim.h"
+#include "RapidStartConfig.h"
+#include <SaAccess.h>
+#include <PchAccess.h>
+#include <PchPlatformLib.h>
+#include "RapidStartPeiLib.h"
+#include "RapidStartData.h"
+#include "RapidStartAhci.h"
+#endif
+
+typedef struct {
+ UINT64 DataByteAddr;
+ UINT32 Reserved;
+ UINT32 ByteCountI;
+} AHCI_PRDT;
+
+#ifndef EFI_DEBUG
+#define DumpPortStatus(a)
+#else
+/**
+ Send serial out debug message for AHCI port status
+
+ @param[in] Ahci - AHCI controller information structure
+**/
+STATIC
+VOID
+DumpPortStatus (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ UINTN PxBase;
+ ASSERT (Ahci->Port <= 31);
+ PxBase = AHCI_PORT_BASE (Ahci);
+
+ DEBUG (
+ (EFI_D_ERROR,
+ " CLB:%08x FB:%08x\n CMD:%08x TFD:%08x IS:%08x\nSSTS:%08x SERR:%08x\n CI:%08x SACT:%08x SIG:%08x\n",
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCLB),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXFB),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCMD),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXTFD),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXIS),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXSSTS),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXSERR),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCI),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXSACT),
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXSIG))
+ );
+}
+#endif
+
+/**
+ Returns SATA Port Control and Status register value.
+
+ @retval PCS value
+**/
+STATIC
+UINT16
+AhciGetPortControlStatus (
+ VOID
+ )
+{
+ UINTN PciD31F2RegBase;
+ PciD31F2RegBase = MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SATA,
+ PCI_FUNCTION_NUMBER_PCH_SATA,
+ 0
+ );
+ return MmioRead16 (PciD31F2RegBase + R_PCH_SATA_PCS);
+}
+
+/**
+ Returns SATA enabled port bitmap basing on PCS value.
+
+ @retval Enabled ports map.
+**/
+UINT32
+AhciGetEnabledPorts (
+ VOID
+ )
+{
+ return AhciGetPortControlStatus () & 0x7F;
+}
+
+/**
+ Returns SATA present port bitmap basing on PCS value.
+
+ @retval Present ports map.
+**/
+UINT32
+AhciGetPresentPorts (
+ VOID
+ )
+{
+ return (AhciGetPortControlStatus () >> 8) & 0x7F;
+}
+
+/**
+ This is a work-around to make sure Port Implemented bits (RWO) are set.
+ PI is set according to PCS value restored from previous boot
+
+ @param[in] Ahci - SATA controller information structure
+**/
+STATIC
+VOID
+AhciConfigurePortsImplemented (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ ASSERT (Ahci->Port <= 31);
+ if ((MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_PI) & (1 << Ahci->Port)) == 0) {
+ MmioWrite32 (Ahci->Abar + R_PCH_SATA_AHCI_PI, AhciGetEnabledPorts ());
+ //
+ // Two reads required (C-spec ch. 25 - 1.9.14.1)
+ //
+ MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_PI);
+ MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_PI);
+ ASSERT (MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_PI) & (1 << Ahci->Port));
+ }
+}
+
+/**
+ Initialize SATA controller and enable decode
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_SUCCESS - SATA controller has been initialized successfully
+**/
+EFI_STATUS
+AhciInit (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ UINTN PciD31F2RegBase;
+
+ DEBUG ((EFI_D_INFO, "AhciInit()\n"));
+
+ Ahci->State = AHCI_STATE_INIT;
+ Ahci->Identify = NULL;
+
+ ASSERT ((Ahci->Abar &~(~0 << N_PCH_SATA_AHCI_BAR_ALIGNMENT)) == 0);
+
+ PciD31F2RegBase = MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SATA,
+ PCI_FUNCTION_NUMBER_PCH_SATA,
+ 0
+ );
+
+ MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_AHCI_BAR, Ahci->Abar);
+ ///
+ /// Enable decode
+ ///
+ MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_COMMAND, 0x6);
+
+ DEBUG ((EFI_D_INFO, "FFS SATA BAR: %x\n", MmioRead32 (PciD31F2RegBase + R_PCH_SATA_AHCI_BAR)));
+ DEBUG ((EFI_D_INFO, "FFS SATA ID: %x\n", MmioRead32 (PciD31F2RegBase + 0)));
+ DEBUG ((EFI_D_INFO, "FFS SATA CMD: %x\n", MmioRead16 (PciD31F2RegBase + R_PCH_SATA_COMMAND)));
+ DEBUG ((EFI_D_INFO, "FFS SATA STS: %x\n", MmioRead16 (PciD31F2RegBase + R_PCH_SATA_PCISTS)));
+ DEBUG ((EFI_D_INFO, "FFS SATA PI: %x\n", MmioRead8 (PciD31F2RegBase + R_PCH_SATA_PI_REGISTER)));
+ DEBUG ((EFI_D_INFO, "FFS SATA CC: %x\n", MmioRead8 (PciD31F2RegBase + R_PCH_SATA_SUB_CLASS_CODE)));
+
+ ///
+ /// Enable SATA ports if not enabled already.
+ ///
+ AhciConfigurePortsImplemented (Ahci);
+
+ ///
+ /// Enable AHCI by setting AE bit
+ ///
+ MmioWrite32 (Ahci->Abar + R_PCH_SATA_AHCI_GHC, B_PCH_SATA_AHCI_GHC_AE);
+
+ DEBUG ((EFI_D_INFO, "FFS AHCI VS: %x\n", MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_VS)));
+ DEBUG ((EFI_D_INFO, "FFS AHCI GHC: %x\n", MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_GHC)));
+ DEBUG ((EFI_D_INFO, "FFS AHCI CAP: %x\n", MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_CAP)));
+ DEBUG ((EFI_D_INFO, "FFS AHCI PI: %x\n", MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_PI)));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disable SATA controller after all AHCI commands have completed
+
+ @param[in] Ahci - SATA controller information structure
+**/
+VOID
+AhciDone (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ UINTN PciD31F2RegBase;
+
+ DEBUG ((EFI_D_INFO, "AhciDone()\n"));
+ ASSERT (Ahci->State == AHCI_STATE_INIT);
+ Ahci->State = AHCI_STATE_UNKNOWN;
+
+ PciD31F2RegBase = MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SATA,
+ PCI_FUNCTION_NUMBER_PCH_SATA,
+ 0
+ );
+
+ ///
+ /// Disable AHCI
+ ///
+ MmioWrite32 (Ahci->Abar + R_PCH_SATA_AHCI_GHC, 0);
+
+ ///
+ /// Unconfigure SATA
+ ///
+ MmioWrite32 (PciD31F2RegBase + R_PCH_SATA_AHCI_BAR, 0);
+ MmioWrite8 (PciD31F2RegBase + R_PCH_SATA_COMMAND, 0);
+}
+
+/**
+ Spin up Ahci port
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Port - SATA port number
+
+ @retval EFI_SUCCESS - AHCI Port has been spun up successfully
+**/
+EFI_STATUS
+AhciSpinUpPort (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINTN Port
+ )
+{
+ UINTN PxBase;
+
+ DEBUG ((EFI_D_INFO, "AhciPortSpinUpPort(%d)\n", Port));
+ ASSERT (Ahci->State == AHCI_STATE_INIT);
+ ASSERT (Port <= 31);
+ ASSERT (MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_GHC) & B_PCH_SATA_AHCI_GHC_AE);
+
+ PxBase = AHCI_PORT_BASE_X (Ahci, Port);
+
+ ASSERT ((MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCMD) & B_PCH_SATA_AHCI_PxCMD_ST) == 0);
+
+ ///
+ /// Clear errors
+ ///
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXSERR, (UINT32)~0u);
+
+ ///
+ /// Spin Up
+ ///
+ MmioOr32 (PxBase + R_PCH_SATA_AHCI_PXCMD, B_PCH_SATA_AHCI_PxCMD_SUD);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize AHCI port for reading/writing RapidStart Store
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_DEVICE_ERROR - AHCI port initialization failed
+ @retval EFI_SUCCESS - AHCI port initialized successfully and RapidStart Store is ready for reading/writing
+ @retval EFI_SECURITY_VIOLATION - Drive is already in SECURITY FREEZE state and will not accept UNLOCK command
+ @retval EFI_ACCESS_DENIED - Drive is in LOCKED state and need to execute UNLOCK command before accessing
+**/
+EFI_STATUS
+AhciPortInit (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ UINTN PxBase;
+ UINT32 Timer;
+ UINT32 Count;
+
+ DEBUG ((EFI_D_INFO, "AhciPortInit()\n"));
+ ASSERT (Ahci->State == AHCI_STATE_INIT);
+ ASSERT (Ahci->Port <= 31);
+ ASSERT (MmioRead32 (Ahci->Abar + R_PCH_SATA_AHCI_GHC) & B_PCH_SATA_AHCI_GHC_AE);
+ DEBUG ((EFI_D_INFO, "Mem used: %d\n", AHCI_MEM_MAX (Ahci) - Ahci->PortBase));
+ DEBUG ((EFI_D_INFO, "AHCI_MEM_MAX_SIZE: %d\n", AHCI_MEM_MAX_SIZE));
+
+ ASSERT (AHCI_MEM_MAX (Ahci) <= (Ahci->PortBase + Ahci->PortSize));
+ ASSERT ((AHCI_MEM_MAX (Ahci) - Ahci->PortBase) == AHCI_MEM_MAX_SIZE);
+
+ PxBase = AHCI_PORT_BASE (Ahci);
+
+ ASSERT ((MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCMD) & B_PCH_SATA_AHCI_PxCMD_ST) == 0);
+
+ ZeroMem ((VOID *) Ahci->PortBase, Ahci->PortSize);
+
+ DEBUG ((EFI_D_INFO, "AHCI_CMD_LIST_BASE: %08lx\n", (UINT64) AHCI_CMD_LIST_BASE (Ahci)));
+ DEBUG ((EFI_D_INFO, "AHCI_RXFIS_BASE: %08lx\n", (UINT64) AHCI_RXFIS_BASE (Ahci)));
+ DEBUG ((EFI_D_INFO, "AHCI_CMD_TABLE_BASE: %08lx\n", (UINT64) AHCI_CMD_TABLE_BASE (Ahci)));
+ DEBUG ((EFI_D_INFO, "AHCI_MEM_MAX: %08lx\n", (UINT64) AHCI_MEM_MAX (Ahci)));
+
+ ASSERT ((AHCI_CMD_LIST_BASE (Ahci) & 0x3FF) == 0);
+ ASSERT ((AHCI_RXFIS_BASE (Ahci) & 0xFF) == 0);
+
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXCLB, (UINT32) AHCI_CMD_LIST_BASE (Ahci));
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXCLBU, (UINT32) RShiftU64 (AHCI_CMD_LIST_BASE (Ahci), 32));
+
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXFB, (UINT32) AHCI_RXFIS_BASE (Ahci));
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXFBU, (UINT32) RShiftU64 (AHCI_RXFIS_BASE (Ahci), 32));
+
+ MmioOr32 (PxBase + R_PCH_SATA_AHCI_PXCMD, B_PCH_SATA_AHCI_PxCMD_FRE);
+
+ ASSERT (MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCMD) & B_PCH_SATA_AHCI_PxCMD_SUD);
+
+ ///
+ /// Clear errors
+ ///
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXSERR, (UINT32)~0u);
+
+ for (Count = 0; Count < AHCI_INIT_RETRY_COUNT; ++Count) {
+ ///
+ /// Reset port if in error state
+ ///
+ if (Count > 0 || MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXSERR) != 0) {
+ DEBUG ((EFI_D_INFO, "Resetting AHCI port.\n"));
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXSCTL, V_PCH_SATA_AHCI_PXSCTL_DET_1);
+ PchPmTimerStall (1000);
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXSCTL, 0);
+ }
+
+ Timer = 0;
+
+ ///
+ /// Wait till device detected
+ ///
+ while
+ (
+ Timer < AHCI_INIT_TIMEOUT &&
+ ((MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXSSTS) & B_PCH_SATA_AHCI_PXSSTS_DET) != B_PCH_SATA_AHCI_PXSSTS_DET_3)
+ ) {
+ PchPmTimerStall (AHCI_INIT_WAIT);
+ Timer += AHCI_INIT_WAIT;
+ }
+ ///
+ /// Clear errors
+ ///
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXSERR, (UINT32)~0u);
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXIS, (UINT32)~0u);
+
+ ///
+ /// Wait for device ready
+ ///
+ while (Timer < AHCI_INIT_TIMEOUT) {
+ if ((
+ MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXTFD) & (B_PCH_SATA_AHCI_PXTFD_STS_DRQ | B_PCH_SATA_AHCI_PXTFD_STS_BSY)
+ ) == 0
+ ) {
+ goto complete;
+ }
+
+ PchPmTimerStall (AHCI_INIT_WAIT);
+ Timer += AHCI_INIT_WAIT;
+ }
+ }
+
+complete:
+
+ if (Count == AHCI_INIT_RETRY_COUNT) {
+
+ DEBUG ((EFI_D_ERROR, "AHCI port initialization timeout.\n"));
+ DumpPortStatus (Ahci);
+
+ ///
+ /// Clear FRE
+ ///
+ MmioAnd32 (PxBase + R_PCH_SATA_AHCI_PXCMD, (UINT32)~B_PCH_SATA_AHCI_PxCMD_FRE);
+
+ ///
+ /// Wait for FR to be cleared
+ ///
+ while (MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCMD) & B_PCH_SATA_AHCI_PxCMD_FR) {
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ ASSERT ((MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCMD) & (B_PCH_SATA_AHCI_PxCMD_CLO | B_PCH_SATA_AHCI_PxCMD_CR)) == 0);
+
+ ///
+ /// Set Start bit
+ ///
+ MmioOr32 (PxBase + R_PCH_SATA_AHCI_PXCMD, B_PCH_SATA_AHCI_PxCMD_ST);
+
+ Ahci->State = AHCI_STATE_INUSE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether device is password locked.
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_SUCCESS - Device not locked
+ @retval EFI_ACCESS_DENIED - Drive is in LOCKED state and need to execute UNLOCK command before accessing
+ @retval EFI_SECURITY_VIOLATION - Drive is already in SECURITY FREEZE state and will not accept UNLOCK command
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+**/
+EFI_STATUS
+AhciGetLockStatus (
+ IN AHCI_CONTEXT *Ahci
+)
+{
+ UINT16 SecurityStatus;
+ EFI_STATUS Status;
+ VOID *Buffer;
+
+ DEBUG ((EFI_D_INFO, "AhciGetLockStatus()\n"));
+ ASSERT (Ahci->State == AHCI_STATE_INUSE);
+
+ if (Ahci->Identify == 0) {
+ Buffer = (VOID*) AHCI_ID_BLOCK (Ahci);
+ Status = AhciIdentifyDevice (Ahci, Buffer);
+ if (Status == EFI_SUCCESS) {
+ Ahci->Identify = (UINT16 *) Buffer;
+ } else {
+ DEBUG ((EFI_D_ERROR, "Error: Identifying device failed!\n"));
+ return Status;
+ }
+ }
+ SecurityStatus = Ahci->Identify[ATA_ID_DEV_SECURITY_STATUS];
+ if ((SecurityStatus & (B_ATA_ID_DEV_SEC_SUPPORTED | B_ATA_ID_DEV_SEC_ENABLED | B_ATA_ID_DEV_SEC_LOCKED)
+ ) == (B_ATA_ID_DEV_SEC_SUPPORTED | B_ATA_ID_DEV_SEC_ENABLED | B_ATA_ID_DEV_SEC_LOCKED)
+ ) {
+ if (SecurityStatus & (B_ATA_ID_DEV_SEC_FROZEN | B_ATA_ID_DEV_SEC_COUNT_EXP)) {
+ DEBUG ((EFI_D_ERROR, "AHCI device lock freeze!\n"));
+ return EFI_SECURITY_VIOLATION;
+ }
+ DEBUG ((EFI_D_WARN, "AHCI device locked!\n"));
+ return EFI_ACCESS_DENIED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Stops AHCI port.
+
+ @param[in] Ahci - SATA controller information structure
+**/
+VOID
+AhciPortDone (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ UINTN PxBase;
+
+ DEBUG ((EFI_D_INFO, "AhciPortDone()\n"));
+ Ahci->State = AHCI_STATE_INIT;
+
+ PxBase = AHCI_PORT_BASE (Ahci);
+ ASSERT (MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCI) == 0);
+
+ MmioAnd32 (PxBase + R_PCH_SATA_AHCI_PXCMD, (UINT32)~B_PCH_SATA_AHCI_PxCMD_ST);
+
+ ///
+ /// Wait for CR to be cleared
+ ///
+ while (MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCMD) & B_PCH_SATA_AHCI_PxCMD_CR) {
+ }
+
+ MmioAnd32 (PxBase + R_PCH_SATA_AHCI_PXCMD, (UINT32)~B_PCH_SATA_AHCI_PxCMD_FRE);
+
+ ///
+ /// Wait for FR to be cleared
+ ///
+ while (MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCMD) & B_PCH_SATA_AHCI_PxCMD_FR) {
+ }
+}
+
+/**
+ Check whether there are available command slots.
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval TRUE if there is an available slot, FALSE otherwise.
+**/
+BOOLEAN
+AhciHasFreeCmdSlot (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ UINTN PxBase;
+ UINT32 ci;
+
+ ASSERT (AHCI_MAX_CMD <= 32);
+
+ PxBase = AHCI_PORT_BASE (Ahci);
+ ci = MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCI);
+
+ return ci != ((UINT32)~0u >> (32 - AHCI_MAX_CMD));
+}
+
+/**
+ Finds or waits for available command slot
+
+ @param[in] Ahci - SATA controller information structure
+ @param[out] CmdIndex - Available command slot index
+
+ @retval EFI_SUCCESS - Available command slot index found
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+ @retval EFI_NOT_STARTED - The RapidStart Entry flow should be canceled and do S3 resume back to OS
+**/
+STATIC
+EFI_STATUS
+AhciFindCmdSlot (
+ IN AHCI_CONTEXT *Ahci,
+ OUT UINTN *CmdIndex
+ )
+{
+ UINTN PxBase;
+ UINT32 ci;
+ UINT32 Timer;
+ UINT32 Index;
+
+ PxBase = AHCI_PORT_BASE (Ahci);
+
+ Timer = 0;
+ while (Timer < AHCI_CMD_TIMEOUT) {
+ ci = MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCI);
+
+ for (Index = 0; Index < AHCI_MAX_CMD; ++Index) {
+ if ((ci & (1u << Index)) == 0) {
+ *CmdIndex = Index;
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (Ahci->PollCancellation && RapidStartShouldCancelEntry ()) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (AHCI_ERROR (PxBase)) {
+ DEBUG ((EFI_D_ERROR, "AHCI error!\n"));
+ DumpPortStatus (Ahci);
+ return EFI_DEVICE_ERROR;
+ }
+
+ PchPmTimerStall (AHCI_CMD_WAIT);
+ Timer += AHCI_CMD_WAIT;
+ }
+
+ DEBUG ((EFI_D_ERROR, "AHCI command timeout!\n"));
+ DumpPortStatus (Ahci);
+ return EFI_TIMEOUT;
+}
+
+/**
+ Waits until given command(s) complete.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] CmdMask - Command(s) mask
+
+ @retval EFI_SUCCESS - Command complete
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+ @retval EFI_NOT_STARTED - The RapidStart Entry flow should be canceled and do S3 resume back to OS
+**/
+EFI_STATUS
+AhciWaitComplete (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINT32 CmdMask
+ )
+{
+ UINTN PxBase;
+ UINT32 ci;
+ UINT32 Timer;
+
+ DEBUG ((EFI_D_INFO, "AhciWaitComplete(%d)\n", CmdMask));
+ ASSERT (Ahci->State == AHCI_STATE_INUSE);
+
+ PxBase = AHCI_PORT_BASE (Ahci);
+
+ Timer = 0;
+ while (Timer < AHCI_CMD_TIMEOUT) {
+ ci = MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCI);
+
+ if ((ci & CmdMask) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (Ahci->PollCancellation && RapidStartShouldCancelEntry ()) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (AHCI_ERROR (PxBase)) {
+ DEBUG ((EFI_D_ERROR, "AHCI error!\n"));
+ DumpPortStatus (Ahci);
+ return EFI_DEVICE_ERROR;
+ }
+
+ PchPmTimerStall (AHCI_CMD_WAIT);
+ Timer += AHCI_CMD_WAIT;
+ }
+
+ DEBUG ((EFI_D_ERROR, "AHCI command timeout!\n"));
+ DumpPortStatus (Ahci);
+ return EFI_TIMEOUT;
+}
+
+/**
+ Waits until all AHCI commands completed.
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_SUCCESS - All AHCI commands have completed
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+ @retval EFI_NOT_STARTED - The RapidStart Entry flow should be canceled and do S3 resume back to OS
+**/
+EFI_STATUS
+AhciWaitAllComplete (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ UINTN PxBase;
+ UINT32 Ci;
+ UINT32 PrevCi;
+ EFI_STATUS Status;
+ UINT32 Timer;
+
+ DEBUG ((EFI_D_INFO, "AhciWaitAllComplete() "));
+ ASSERT (Ahci->State == AHCI_STATE_INUSE);
+
+ PxBase = AHCI_PORT_BASE (Ahci);
+ Timer = 0;
+ Status = EFI_TIMEOUT;
+
+ Ci = MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCI);
+ PrevCi = Ci;
+
+ while (Timer < AHCI_CMD_TIMEOUT) {
+ if (Ci == 0) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ if (Ahci->PollCancellation && RapidStartShouldCancelEntry ()) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (AHCI_ERROR (PxBase)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ if (Ci != PrevCi) {
+ DEBUG ((EFI_D_INFO, "."));
+ Timer = 0;
+ }
+
+ PchPmTimerStall (AHCI_CMD_WAIT);
+ Timer += AHCI_CMD_WAIT;
+ PrevCi = Ci;
+ Ci = MmioRead32 (PxBase + R_PCH_SATA_AHCI_PXCI);
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ if (Status == EFI_TIMEOUT) {
+ DEBUG ((EFI_D_ERROR, "AHCI command timeout!\n"));
+ } else if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "AHCI error!\n"));
+ DumpPortStatus (Ahci);
+ }
+
+ return Status;
+}
+
+/**
+ Enqueues ahci command for read/write and optionally with Zero filter
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in,out] AtaCmd - ATA command structure
+ @param[out] CmdMask - If given a bit corresponding to allocated command slot is set
+ @param[in] ZeroPageBitMap - A pointer for ZeroPageTable
+ @param[out] SmRamBufferLba - If given the drive LBA storing original SMRAM buffer content will be passed by it.
+
+ @retval EFI_SUCCESS - AHCI command successfully posted
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciPostCommandWithZeroFilter (
+ IN AHCI_CONTEXT *Ahci,
+ IN OUT ATA_COMMAND *AtaCmd,
+ OUT OPTIONAL UINT32 *CmdMask,
+ IN OPTIONAL UINT32 *ZeroPageBitMap,
+ OUT OPTIONAL UINT64 *SmRamBufferLba
+ )
+{
+ UINTN PxBase;
+ UINTN CmdIndex;
+ UINTN CmdTableAddr;
+ UINT32 *CmdHeader;
+ UINT32 *CmdFis;
+ AHCI_PRDT *Prdt;
+ UINT16 PrdCount;
+ UINT16 Index;
+ UINT32 MemLeft;
+ UINT32 MemChunk;
+ UINT64 MemAddr;
+ EFI_STATUS Status;
+ UINT32 TempBitMap;
+ UINT32 *ZeroPagePointer;
+ UINT8 count;
+ UINT32 AhciMaxRegion;
+ UINT32 NumberOfPages;
+ UINT32 SectorCount;
+
+ count = 0;
+ ZeroPagePointer = 0;
+ TempBitMap = 0;
+ CmdIndex = 0;
+
+ DEBUG (
+ (EFI_D_INFO,
+ "AhciPostCommand port=%d cmd=%02x lba=%08x mem=%08lx ",
+ Ahci->Port,
+ AtaCmd->Command,
+ (UINT32) AtaCmd->Lba,
+ (UINT64) AtaCmd->MemAddr)
+ );
+ ASSERT (Ahci->State == AHCI_STATE_INUSE);
+
+ MemAddr = AtaCmd->MemAddr;
+ MemLeft = AtaCmd->SectorCount << SECTOR_SHIFT;
+ PxBase = AHCI_PORT_BASE (Ahci);
+
+ ASSERT ((MemAddr & (ZeroPageBitMap ? 0xFFF : 1)) == 0);
+ ASSERT (AtaCmd->SectorCount <= AHCI_MAX_SECTORS);
+
+ Status = AhciFindCmdSlot (Ahci, &CmdIndex);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (CmdIndex < AHCI_MAX_CMD);
+
+ CmdHeader = (UINT32 *) AHCI_CMD_HEADER (Ahci, CmdIndex);
+ CmdTableAddr = AHCI_CMD_TABLE (Ahci, CmdIndex);
+ CmdFis = (UINT32 *) (UINTN) CmdTableAddr;
+ Prdt = (AHCI_PRDT *) (UINTN) (CmdTableAddr + AHCI_CMD_TABLE_HEADER_SIZE);
+
+ ASSERT ((UINT32) CmdHeader >= AHCI_CMD_LIST_BASE (Ahci));
+ ASSERT ((UINT32) CmdHeader + AHCI_CMD_HEADER_SIZE <= AHCI_CMD_LIST_BASE (Ahci) + AHCI_CMD_LIST_SIZE);
+ ASSERT (CmdTableAddr >= Ahci->PortBase);
+ ASSERT (CmdTableAddr + AHCI_CMD_TABLE_SIZE <= Ahci->PortBase + Ahci->PortSize);
+ ASSERT (RShiftU64 (AtaCmd->Lba, 48) == 0);
+
+ ///
+ /// Create PRD table
+ ///
+ PrdCount = 0;
+ AhciMaxRegion = AHCI_REGION_MAX;
+ SectorCount = 0;
+ ///
+ /// Initialize ZeroPage Filter Parameters
+ ///
+ if (ZeroPageBitMap != NULL) {
+ NumberOfPages = (UINT32) NUMBER_OF_PAGES_IN_DWORD (MemAddr);
+ ZeroPagePointer = ZeroPageBitMap + NumberOfPages;
+ count = (UINT8) (NUMBER_OF_PAGES (MemAddr) - (NumberOfPages * ZERO_BITMAP_UNIT));
+ TempBitMap = (UINT32) *ZeroPagePointer;
+ AhciMaxRegion = EFI_PAGE_SIZE;
+ }
+
+ while (MemLeft > 0) {
+ ASSERT (PrdCount < AHCI_MAX_PRDT);
+ ASSERT ((MemAddr & 1) == 0);
+
+ if (MemLeft >= AhciMaxRegion) {
+ MemChunk = AhciMaxRegion;
+ } else {
+ MemChunk = MemLeft;
+ }
+
+ ASSERT (((MemChunk - 1) &~(AhciMaxRegion - 1)) == 0);
+ ASSERT ((MemChunk & 0x1FF) == 0);
+
+ if (ZeroPageBitMap != NULL) {
+ ///
+ /// Get LBA which storing SMRAM buffer and later restore this buffer after SMRAM handled.
+ ///
+ if (SmRamBufferLba != NULL) {
+ if (MemAddr == LEGACY_SMRAM_BUFFER) {
+ *SmRamBufferLba = AtaCmd->Lba + SectorCount;
+ }
+ }
+
+ if (((UINT32) (TempBitMap >> count) & 1) == 0) {
+ Prdt[PrdCount].DataByteAddr = MemAddr;
+ Prdt[PrdCount].Reserved = 0;
+ Prdt[PrdCount].ByteCountI = MemChunk - 1;
+ PrdCount++;
+ SectorCount += 8;
+ }
+ ///
+ /// Shift ZeroPage filter bitmap to next bit, if it is end of current DWORD, will shift to next DWORD
+ ///
+ if (count < (ZERO_BITMAP_UNIT - 1)) {
+ count++;
+ } else {
+ count = 0;
+ ZeroPagePointer++;
+ TempBitMap = (UINT32) *ZeroPagePointer;
+ }
+ } else {
+ Prdt[PrdCount].DataByteAddr = MemAddr;
+ Prdt[PrdCount].Reserved = 0;
+ Prdt[PrdCount].ByteCountI = MemChunk - 1;
+ PrdCount++;
+ SectorCount += MemChunk >> SECTOR_SHIFT;
+ }
+
+ MemAddr += MemChunk;
+ MemLeft -= MemChunk;
+ }
+
+ AtaCmd->MemAddr += AtaCmd->SectorCount << SECTOR_SHIFT;
+ AtaCmd->SectorCount = SectorCount;
+
+ if (ZeroPageBitMap != NULL && PrdCount == 0) {
+ DEBUG ((EFI_D_INFO, "skipped\n"));
+ return EFI_SUCCESS;
+ }
+ ///
+ /// Fill command header
+ ///
+ ASSERT ((CmdTableAddr & 0x7F) == 0);
+ CmdHeader[0] = AHCI_CMD_PRDTL (PrdCount) | AHCI_CMD_CFL (5);
+ if (AtaCmd->Direction == AHCI_DIR_HOST2DEV) {
+ CmdHeader[0] |= AHCI_CMD_WRITE | AHCI_CMD_PREFETCHABLE;
+ }
+
+ CmdHeader[1] = 0;
+ CmdHeader[2] = (UINT32) CmdTableAddr;
+ CmdHeader[3] = (UINT32) RShiftU64 (CmdTableAddr, 32);
+ for (Index = 4; Index < 8; ++Index) {
+ CmdHeader[Index] = 0;
+ }
+ ///
+ /// Create FIS
+ ///
+ CmdFis[0] = SATA_FIS_FEAT (AtaCmd->Feature) | SATA_FIS_CMD (AtaCmd->Command) | SATA_FIS_C | SATA_FIS_HOST2DEVICE;
+ CmdFis[1] = SATA_FIS_DEV_LBA | SATA_FIS_LBA (AtaCmd->Lba);
+ CmdFis[2] = SATA_FIS_FEAT_EXP (AtaCmd->Feature) | SATA_FIS_LBA_EXP (AtaCmd->Lba);
+ CmdFis[3] = SATA_FIS_SECT_COUNT (SectorCount);
+ CmdFis[4] = AtaCmd->Auxiliary.Data;
+ DEBUG ((EFI_D_INFO, "FIS[4] = %x\n", AtaCmd->Auxiliary.Data));
+
+ DEBUG ((EFI_D_INFO, "actualcount=%d ", SectorCount));
+
+ ///
+ /// Issue the command to the controller
+ ///
+ MmioWrite32 (PxBase + R_PCH_SATA_AHCI_PXCI, (1u << CmdIndex));
+
+ if (CmdMask != NULL) {
+ *CmdMask |= (1u << CmdIndex);
+ }
+
+ AtaCmd->Lba += SectorCount;
+ DEBUG ((EFI_D_INFO, "idx=%d\n", CmdIndex));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Executes AHCI command and waits until command completes.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in,out] AtaCmd - ATA command structure
+
+ @retval EFI_SUCCESS - AHCI command successfully posted
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciExecCommand (
+ IN AHCI_CONTEXT *Ahci,
+ IN OUT ATA_COMMAND *AtaCmd
+ )
+{
+ EFI_STATUS Status;
+ UINTN CmdMask;
+
+ CmdMask = 0;
+ Status = AhciPostCommand (Ahci, AtaCmd, &CmdMask);
+ if (Status == EFI_SUCCESS) {
+ Status = AhciWaitComplete (Ahci, CmdMask);
+ }
+
+ return Status;
+}
+
+/**
+ Issues ATA command with no data transfer.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Command - Command to be issued
+
+ @retval EFI_SUCCESS - fucntion executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciSimpleCommand (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINT8 Command
+ )
+{
+ ATA_COMMAND AtaCmd;
+
+ ZeroMem (&AtaCmd, sizeof (AtaCmd));
+ AtaCmd.Command = Command;
+
+ return AhciExecCommand (Ahci, &AtaCmd);
+}
+
+/**
+ Sends Identify Device ATA command to port
+
+ @param[in] Ahci - SATA controller information structure
+ @param[out] Buffer - Buffer to store device information
+
+ @retval EFI_SUCCESS - function executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciIdentifyDevice (
+ IN AHCI_CONTEXT *Ahci,
+ OUT VOID *Buffer
+ )
+{
+ ATA_COMMAND AtaCmd;
+
+ DEBUG ((EFI_D_INFO, "AhciIdentifyDevice()\n"));
+ ASSERT (Buffer != NULL);
+
+ AtaCmd.Command = ATA_CMD_IDENTIFY_DEVICE;
+ AtaCmd.Direction = AHCI_DIR_DEV2HOST;
+ AtaCmd.Lba = 0;
+ AtaCmd.SectorCount = 1;
+ AtaCmd.MemAddr = (UINTN) Buffer;
+ AtaCmd.Feature = 0;
+
+ return AhciExecCommand (Ahci, &AtaCmd);
+}
+
+/**
+ Performs TRIM command on given LBA range.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Lba - First block to be trimmed
+ @param[in] Count - Number of blocks to trim
+
+ @retval EFI_SUCCESS - fucntion executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @exception EFI_UNSUPPORTED - TRIM is not supported by the device
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciTrimRange (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINT64 Lba,
+ IN UINT32 Count
+ )
+{
+ UINT64 *RangeEntries;
+ UINTN Index;
+ UINT16 Blocks;
+ ATA_COMMAND AtaCmd;
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "AhciTrimRange(lba=%lx count=%x)\n", Lba, Count));
+ ASSERT (Ahci->Identify != NULL);
+
+ if (!((Ahci->Identify[ATA_ID_DEV_DATA_SET_MGMNT_SUPPORT] & B_ATA_ID_DEV_DATA_SET_TRIM) &&
+ (Ahci->Identify[ATA_ID_DEV_DATA_SET_MGMNT_BLOCKS] > 0))
+ ) {
+ DEBUG ((EFI_D_WARN, "TRIM is not supported!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ RangeEntries = (UINT64 *) AHCI_TMP_BLOCK (Ahci);
+
+ AtaCmd.Command = ATA_CMD_DATA_SET_MANAGEMENT;
+ AtaCmd.Direction = AHCI_DIR_HOST2DEV;
+ AtaCmd.Feature = V_ATA_TRIM_FEATURE;
+ AtaCmd.SectorCount = 1;
+
+ while (Count > 0) {
+ for (Index = 0; Index < (AHCI_TMP_BLOCK_SIZE / sizeof (UINT64)); ++Index) {
+ if (Count <= 0xFFFF) {
+ Blocks = (UINT16) Count;
+ } else {
+ Blocks = 0xFFFF;
+ }
+
+ if (Blocks != 0) {
+ RangeEntries[Index] = LShiftU64 (Blocks, 48) | Lba;
+ } else {
+ RangeEntries[Index] = 0;
+ }
+
+ Count -= Blocks;
+ Lba += Blocks;
+ }
+
+ AtaCmd.Lba = 0;
+ AtaCmd.MemAddr = (UINTN) RangeEntries;
+
+ Status = AhciExecCommand (Ahci, &AtaCmd);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Unlocks ATA device.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Password - security credential
+
+ @retval EFI_SUCCESS - Command executed successfully
+ @retval EFI_SECURITY_VIOLATION - Device security lock freeze
+ @exception EFI_UNSUPPORTED - Security is not supported by the device
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciSecurityUnlock (
+ IN AHCI_CONTEXT *Ahci,
+ IN CHAR8 *Password
+ )
+{
+ UINT16 *Block;
+ ATA_COMMAND AtaCmd;
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "AhciSecurityUnlock()\n"));
+ ASSERT (Ahci->Identify != NULL);
+
+ if ((Ahci->Identify[ATA_ID_DEV_SECURITY_STATUS] & B_ATA_ID_DEV_SEC_SUPPORTED) == 0) {
+ DEBUG ((EFI_D_ERROR, "AHCI security not supported!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((Ahci->Identify[ATA_ID_DEV_SECURITY_STATUS] & (B_ATA_ID_DEV_SEC_ENABLED | B_ATA_ID_DEV_SEC_LOCKED)) !=
+ (B_ATA_ID_DEV_SEC_ENABLED | B_ATA_ID_DEV_SEC_LOCKED)
+ ) {
+ DEBUG ((EFI_D_WARN, "AHCI device already unlocked!\n"));
+ return EFI_SUCCESS;
+ }
+
+ if (Ahci->Identify[ATA_ID_DEV_SECURITY_STATUS] & (B_ATA_ID_DEV_SEC_FROZEN | B_ATA_ID_DEV_SEC_COUNT_EXP)) {
+ DEBUG ((EFI_D_ERROR, "AHCI device lock freeze!\n"));
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ Block = (UINT16 *) AHCI_TMP_BLOCK (Ahci);
+ Block[0] = 0;
+ CopyMem (&Block[1], Password, ATA_PASSWORD_LEN);
+
+ AtaCmd.Command = ATA_CMD_SECURITY_UNLOCK;
+ AtaCmd.Direction = AHCI_DIR_HOST2DEV;
+ AtaCmd.Feature = 0;
+ AtaCmd.Lba = 0;
+ AtaCmd.MemAddr = (UINTN) Block;
+ AtaCmd.SectorCount = 1;
+
+ Status = AhciExecCommand (Ahci, &AtaCmd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "AHCI unlock failed!\n"));
+ }
+
+ return Status;
+}
+
+/**
+ Hybrid Hard Disk Support.
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_SUCCESS - fucntion executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @exception EFI_UNSUPPORTED - HHD is not supported by the device
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciHybridHardDiskSupport (
+ IN AHCI_CONTEXT *Ahci
+ )
+{
+ EFI_STATUS Status;
+ ATA_COMMAND AtaCmd;
+ UINT8 *HybridLogRangeEntries;
+ UINT8 *HybridInfoHeader;
+ UINT8 *HybridInfoDescriptor;
+ UINT16 Index, HybridInfoDescriptorNumber;
+ UINT64 X, Y;
+ UINT64 NvmSize;
+
+ DEBUG ((EFI_D_INFO, "Ahci Hybrid Hard Device Support Start\n"));
+ ASSERT (Ahci->Identify != NULL);
+
+ if (!((Ahci->Identify[ATA_ID_DEV_HYBRID_FEATURE_SUPPORT] & B_ATA_ID_DEV_HYBRID_FEATURE_SUPPORT) &
+ (Ahci->Identify[ATA_ID_DEV_HYBRID_FEATURE_ENABLE] & B_ATA_ID_DEV_HYBRID_FEATURE_ENABLE))
+ ) {
+ DEBUG ((EFI_D_ERROR, "Hybrid is not supported!\n"));
+ DEBUG ((EFI_D_ERROR, "Hybrid Feature support = %x\n", Ahci->Identify[ATA_ID_DEV_HYBRID_FEATURE_SUPPORT]));
+ DEBUG ((EFI_D_ERROR, "Hybrid Feature Enable = %x\n", Ahci->Identify[ATA_ID_DEV_HYBRID_FEATURE_ENABLE]));
+
+ return EFI_UNSUPPORTED;
+ }
+
+ HybridLogRangeEntries = (UINT8 *) AHCI_TMP_BLOCK (Ahci);
+
+ AtaCmd.Command = ATA_CMD_READ_LOG_EXT;
+ AtaCmd.Direction = AHCI_DIR_DEV2HOST;
+ AtaCmd.Lba = 0x14;
+ AtaCmd.SectorCount = 1;
+ AtaCmd.MemAddr = (UINTN) HybridLogRangeEntries;
+ AtaCmd.Feature = 0;
+
+ Status = AhciExecCommand (Ahci, &AtaCmd);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Hybrid can't be supported, READ_LOG_EXT fail and Status is %r\n", Status));
+ return Status;
+ }
+
+ HybridInfoHeader = HybridLogRangeEntries;
+
+ if (HybridInfoHeader[2] != 0xFF) {
+ DEBUG ((EFI_D_ERROR, "Hybrid Information is Disabled\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((EFI_D_INFO, "Maximum Hybrid Priority is %x\n", HybridInfoHeader[7]));
+ if (HybridInfoHeader[7] == 0 || HybridInfoHeader[7] > 16) {
+ DEBUG ((EFI_D_ERROR, "Maximum Hybrid Priority Level is invalid !!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Ahci->HybridInfo.HybridInfoValid = HybridInfoHeader[2];
+ Ahci->HybridInfo.HybridPriority = HybridInfoHeader[7] - 1;
+ DEBUG ((EFI_D_INFO, "RapidStart Hybrid Priority is %x\n", Ahci->HybridInfo.HybridPriority));
+
+ X = 0;
+ Y = 0;
+ HybridInfoDescriptorNumber = *(UINT16 *)HybridInfoHeader;
+ DEBUG ((EFI_D_INFO, "HybridInfoDescriptorNumber is %x\n", HybridInfoDescriptorNumber));
+ for (Index = 0; Index < HybridInfoDescriptorNumber; Index++) {
+ HybridInfoDescriptor = HybridLogRangeEntries + 64;
+ HybridInfoDescriptor += (16 * Index);
+ DEBUG ((EFI_D_INFO, "%x - Hybrid Priority is %x\n", Index, HybridInfoDescriptor[0]));
+ DEBUG ((EFI_D_INFO, " - Consumed NVM Size Fraction is %x\n", HybridInfoDescriptor[1]));
+ DEBUG ((EFI_D_INFO, " - Consumed Mapping Resources Fraction is %x\n", HybridInfoDescriptor[2]));
+ DEBUG ((EFI_D_INFO, " - Consumed NVM Size for Dirty Data Fraction is %x\n", HybridInfoDescriptor[3]));
+ DEBUG ((EFI_D_INFO, " - Consumed Mapping Resources for Dirty Data Fraction is %x\n", HybridInfoDescriptor[4]));
+
+ X+= HybridInfoDescriptor[3];
+ Y+= HybridInfoDescriptor[4];
+ }
+
+ DEBUG ((EFI_D_INFO, "Total Consumed Capacity For Dirty Data Fraction is %x\n", X));
+
+ NvmSize = *(UINT64 *)(HybridInfoHeader + 16);
+ DEBUG ((EFI_D_INFO, "NVM Size is %lx\n", NvmSize));
+ X = MultU64x64 (X, NvmSize);
+ X = DivU64x32 (X, 0xFF);
+
+ Ahci->TotalRemainingCacheCapacityInSector = (UINT32)(NvmSize - X);
+ DEBUG ((EFI_D_INFO, "TotalRemainingCacheCapacityInSector = %x\n", Ahci->TotalRemainingCacheCapacityInSector));
+
+ DEBUG ((EFI_D_INFO, "Ahci Hybrid Hard Device Support Successfully\n"));
+
+ return EFI_SUCCESS;
+}
diff --git a/ReferenceCode/RapidStart/Pei/RapidStartAhci.h b/ReferenceCode/RapidStart/Pei/RapidStartAhci.h
new file mode 100644
index 0000000..652cf96
--- /dev/null
+++ b/ReferenceCode/RapidStart/Pei/RapidStartAhci.h
@@ -0,0 +1,344 @@
+/** @file
+ Header file for function definitions
+
+@copyright
+ Copyright (c) 1999 - 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 Reference Module" and is
+ licensed for Intel 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
+
+**/
+#ifndef RAPID_START_AHCI_H_
+#define RAPID_START_AHCI_H_
+
+#include <RapidStartAhciReg.h>
+
+#pragma pack(1)
+
+typedef struct {
+ UINT32 Abar;
+ UINT32 PortBase;
+ UINT32 PortSize;
+ UINTN Port;
+ BOOLEAN PollCancellation;
+
+ // Internal fields
+ UINT16 *Identify;
+ enum {
+ AHCI_STATE_UNKNOWN,
+ AHCI_STATE_INIT,
+ AHCI_STATE_INUSE,
+ AHCI_STATE_MAX,
+ } State;
+ struct {
+ UINT8 HybridPriority : 4;
+ UINT8 Reserved : 3;
+ UINT8 HybridInfoValid : 1;
+ } HybridInfo;
+ UINT32 TotalRemainingCacheCapacityInSector;
+} AHCI_CONTEXT;
+
+typedef union {
+ UINT32 Data;
+ struct {
+ UINT32 ByteReserved1 : 8;
+ UINT32 ByteReserved2 : 8;
+ UINT32 HybridPriority : 4;
+ UINT32 Reserved : 1;
+ UINT32 HybridInfoValid : 1;
+ UINT32 Reserved1 : 2;
+ UINT32 ByteReserved4 : 8;
+ } r;
+} ATA_AUX;
+
+typedef struct {
+ UINT64 MemAddr;
+ UINT64 Lba;
+ UINT32 SectorCount;
+ UINT16 Feature;
+ UINT8 Command;
+ UINT8 Direction;
+ ATA_AUX Auxiliary;
+} ATA_COMMAND;
+
+#pragma pack()
+
+#define AhciSpinUp(Ahci) \
+ AhciSpinUpPort (Ahci, Ahci->Port)
+
+#define AhciPostCommand(Ahci, AtaCmd, CmdIdx) \
+ AhciPostCommandWithZeroFilter (Ahci, AtaCmd, CmdIdx, NULL, NULL)
+
+/**
+ Initialize SATA controller and enable decode
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_SUCCESS - SATA controller has been initialized successfully
+**/
+EFI_STATUS
+AhciInit (
+ IN AHCI_CONTEXT *Ahci
+ );
+
+/**
+ Returns SATA enabled port bitmap basing on PCS value.
+
+ @retval Enabled ports map.
+**/
+UINT32
+AhciGetEnabledPorts (
+ VOID
+ );
+
+/**
+ Returns SATA present port bitmap basing on PCS value.
+
+ @retval Present ports map.
+**/
+UINT32
+AhciGetPresentPorts (
+ VOID
+ );
+
+/**
+ Check whether device is password locked.
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_SUCCESS - Device not locked
+ @retval EFI_ACCESS_DENIED - Drive is in LOCKED state and need to execute UNLOCK command before accessing
+ @retval EFI_SECURITY_VIOLATION - Drive is already in SECURITY FREEZE state and will not accept UNLOCK command
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+**/
+EFI_STATUS
+AhciGetLockStatus (
+ IN AHCI_CONTEXT *Ahci
+ );
+
+/**
+ Disable SATA controller after all AHCI commands have completed
+
+ @param[in] Ahci - SATA controller information structure
+**/
+VOID
+AhciDone (
+ IN AHCI_CONTEXT *Ahci
+ );
+
+/**
+ Spin up Ahci port
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Port - SATA port number
+
+ @retval EFI_SUCCESS - AHCI Port has been spun up successfully
+**/
+EFI_STATUS
+AhciSpinUpPort (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINTN Port
+ );
+
+/**
+ Initialize AHCI port for reading/writing RapidStart Store
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_DEVICE_ERROR - AHCI port initialization failed
+ @retval EFI_SUCCESS - AHCI port initialized successfully and RapidStart Store is ready for reading/writing
+**/
+EFI_STATUS
+AhciPortInit (
+ IN AHCI_CONTEXT *Ahci
+ );
+
+/**
+ Stops AHCI port.
+
+ @param[in] Ahci - SATA controller information structure
+**/
+VOID
+AhciPortDone (
+ IN AHCI_CONTEXT *Ahci
+ );
+
+/**
+ Executes AHCI command.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in,out] AtaCmd - ATA command structure
+
+ @retval EFI_SUCCESS - Command successfull
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciExecCommand (
+ IN AHCI_CONTEXT *Ahci,
+ IN OUT ATA_COMMAND *AtaCmd
+ );
+
+/**
+ Enqueues ahci command and for read/write it is optionally with Zero filter.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in,out] AtaCmd - ATA command structure
+ @param[out] CmdMask - If given a bit corresponding to allocated command slot is set
+ @param[in] ZeroPageBitMap - A pointer for ZeroPageTable
+ @param[out] SmRamBufferLba - If given the drive LBA storing original SMRAM buffer content will be passed by it.
+
+ @retval EFI_SUCCESS - AHCI command successfully posted
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciPostCommandWithZeroFilter (
+ IN AHCI_CONTEXT *Ahci,
+ IN OUT ATA_COMMAND *AtaCmd,
+ OUT OPTIONAL UINT32 *CmdMask,
+ IN OPTIONAL UINT32 *ZeroPageBitMap,
+ OUT OPTIONAL UINT64 *SmRamBufferLba
+ );
+
+/**
+ Issues ATA command with no data transfer.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Command - Command to be issued
+
+ @retval EFI_SUCCESS - fucntion executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciSimpleCommand (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINT8 Command
+ );
+
+/**
+ Check whether there are available command slots.
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval TRUE if there is an available slot, FALSE otherwise.
+**/
+BOOLEAN
+AhciHasFreeCmdSlot (
+ IN AHCI_CONTEXT *Ahci
+ );
+
+/**
+ Waits untill given command(s) complete.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] CmdMask - Command(s) mask
+
+ @retval EFI_SUCCESS - Command complete
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+ @retval EFI_NOT_STARTED - The RapidStart Entry flow should be canceled and do S3 resume back to OS
+**/
+EFI_STATUS
+AhciWaitComplete (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINT32 CmdMask
+ );
+
+/**
+ Waits for all AHCI commands completed.
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_SUCCESS - All AHCI commands have completed
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+ @retval EFI_NOT_STARTED - The RapidStart Entry flow should be canceled and do S3 resume back to OS
+**/
+EFI_STATUS
+AhciWaitAllComplete (
+ IN AHCI_CONTEXT *Ahci
+ );
+
+/**
+ Sends Identify Device ATA command to port
+
+ @param[in] Ahci - SATA controller information structure
+ @param[out] Buffer - Buffer to store device information
+
+ @retval EFI_SUCCESS - function executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciIdentifyDevice (
+ IN AHCI_CONTEXT *Ahci,
+ OUT VOID *Buffer
+ );
+
+/**
+ Performs TRIM command on given LBA range
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Lba - First block to be trimmed
+ @param[in] Count - Number of blocks to trim
+
+ @retval EFI_SUCCESS - fucntion executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @exception EFI_UNSUPPORTED - TRIM is not supported by the device
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciTrimRange (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINT64 Lba,
+ IN UINT32 Count
+ );
+
+/**
+ Unlocks ATA device.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Password - security credential
+
+ @retval EFI_SUCCESS - Command executed successfully
+ @retval EFI_SECURITY_VIOLATION - Device security lock freeze
+ @exception EFI_UNSUPPORTED - Security is not supported by the device
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciSecurityUnlock (
+ IN AHCI_CONTEXT *Ahci,
+ IN CHAR8 *Password
+ );
+
+/**
+ Hybrid Hard Disk Support.
+
+ @param[in] Ahci - SATA controller information structure
+
+ @retval EFI_SUCCESS - fucntion executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @exception EFI_UNSUPPORTED - TRIM is not supported by the device
+ @retval EFI_DEVICE_ERROR - Command failed
+**/
+EFI_STATUS
+AhciHybridHardDiskSupport (
+ IN AHCI_CONTEXT *Ahci
+ );
+
+#endif
diff --git a/ReferenceCode/RapidStart/Pei/RapidStartPei.c b/ReferenceCode/RapidStart/Pei/RapidStartPei.c
new file mode 100644
index 0000000..08d05e8
--- /dev/null
+++ b/ReferenceCode/RapidStart/Pei/RapidStartPei.c
@@ -0,0 +1,2379 @@
+/** @file
+ This Peim driver will do RapidStart Entry or RapidStart Exit transition
+
+@copyright
+ Copyright (c) 1999 - 2013 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 Reference Module" and is
+ licensed for Intel 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 "EdkIIGluePeim.h"
+#include "RapidStartConfig.h"
+#include EFI_PPI_DEFINITION (RapidStart)
+#include EFI_PROTOCOL_DEFINITION (RapidStartGlobalNvsArea)
+#include EFI_PPI_DEFINITION (Heci)
+#include <MeChipset.h>
+
+#include <PchAccess.h>
+#include <SaAccess.h>
+#include <PchPlatformLib.h>
+
+#include "GfxDisplayLibPei.h"
+#include EFI_PPI_DEFINITION (PeiGfxPpi)
+#ifdef RAPID_START_ON_MEMORY_INSTALLED
+#include EFI_GUID_DEFINITION (AcpiVariable)
+#endif
+#include EFI_PPI_DEFINITION (EndOfPeiSignal)
+#include EFI_GUID_DEFINITION (RapidStartTransition)
+#include "RapidStartPeiLib.h"
+#include "RapidStartData.h"
+#include "RapidStartAhci.h"
+#include "RapidStartCommonLib.h"
+
+#endif
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+
+
+#define PAM_COUNT 7
+
+#define ME_FID_TIMEOUT 10000
+
+#define MAX_MEMORY_RANGES (MAX_GFX_MEMORY_RANGES + 0x08)
+#define MAX_SMRAM_RANGES 2
+#define DPR_RANGES 1
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
+#endif
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
+#define POOL_SIZE(a) (((((EFI_HOB_GENERIC_HEADER*)a - 1)->HobLength) - sizeof(EFI_HOB_GENERIC_HEADER)) / sizeof (*(a)))
+#define VARIABLE_SIZE(a) (ARRAY_SIZE(a) > 0) ? ARRAY_SIZE(a) : POOL_SIZE(a)
+
+#define END_RANGES ((UINT64) (INT64) (-1))
+#define RANGE_LENGTH(r) ((r)->End - (r)->Start)
+
+EFI_GUID gEfiAcpiVariableGuid = EFI_ACPI_VARIABLE_GUID;
+
+typedef struct {
+ UINT64 Start;
+ UINT64 End;
+} MEMORY_RANGE;
+
+#define RAPID_START_INSTANCE_SIGNATURE EFI_SIGNATURE_32 ('i', 'R', 'S', 'T')
+
+typedef struct _RAPID_START_INSTANCE {
+ RAPID_START_PPI Ppi;
+ EFI_PEI_PPI_DESCRIPTOR PpiDesc;
+ UINT32 Signature;
+ BOOLEAN Enabled;
+ RAPID_START_PERSISTENT_DATA Data;
+ RAPID_START_TRANSITION Transition;
+ RAPID_START_GLOBAL_NVS_AREA *RapidStartGlobalNvs;
+ AHCI_CONTEXT Ahci;
+ CHAR8 HddPassword[ATA_PASSWORD_LEN];
+ EFI_STATUS PwdStatus;
+ BOOLEAN FreezeLock;
+#ifndef RAPID_START_NO_SMRAM_INTEGRITY_CHECK
+ UINT8 SmRamHash[RAPID_START_SECURE_HASH_LENGTH];
+#endif
+ UINT64 NotUsedLba;
+ UINT32 IedSize;
+} RAPID_START_INSTANCE;
+
+#define RAPID_START_INSTANCE_FROM_THIS(a) CR (a, RAPID_START_INSTANCE, Ppi, RAPID_START_INSTANCE_SIGNATURE)
+
+EFI_STATUS
+RapidStartClearAndEnablePmeEvent (
+ IN BOOLEAN EnablePme
+ );
+
+STATIC
+EFI_STATUS
+RapidStartExitAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ );
+
+STATIC
+EFI_STATUS
+RapidStartRecoveryAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ );
+
+STATIC
+EFI_STATUS
+RapidStartS4AtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ );
+
+STATIC
+EFI_STATUS
+RapidStartMemoryInstalled (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ );
+
+STATIC
+EFI_STATUS
+InstallRapidStartPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ );
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mRapidStartExitNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEndOfPeiSignalPpiGuid,
+ RapidStartExitAtEndOfPei
+};
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mRapidStartRecoveryNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEndOfPeiSignalPpiGuid,
+ RapidStartRecoveryAtEndOfPei
+};
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mRapidStartS4NotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEndOfPeiSignalPpiGuid,
+ RapidStartS4AtEndOfPei
+};
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mRapidStartTransitionPpiNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gRapidStartTransitionPpiGuid,
+ RapidStartMemoryInstalled
+};
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mInstallRapidStartPpiNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gPeiHeciPpiGuid,
+ InstallRapidStartPpi
+};
+
+STATIC
+EFI_STATUS
+RapidStartDoTransition (
+ IN RAPID_START_PPI *This
+ );
+
+#if !defined(RAPID_START_NO_SMRAM_INTEGRITY_CHECK) && defined(BUILD_WITH_GLUELIB)
+#undef SetMem
+/**
+ SetMem alternative in case GlueLib defines SetMem as a macro.
+ Required by CryptoLib.
+
+ @param[out] Buffer - Pointer to the memory buffer
+ @param[in] Length - The length for setting memory
+ @param[in] Value - The value that will be set to memory buffer
+**/
+VOID *
+SetMem (
+ OUT VOID *Buffer,
+ IN UINTN Length,
+ IN UINT8 Value
+ )
+{
+ return GlueSetMem (Buffer, Length, Value);
+}
+
+#undef CopyMem
+/**
+ Copy Length bytes from Source to Destination.
+
+ @param[out] DestinationBuffer - Target of copy
+ @param[in] SourceBuffer - Place to copy from
+ @param[in] Length - Number of bytes to copy
+
+ @retval Status code
+**/
+VOID *
+EFIAPI
+CopyMem (
+ OUT VOID *DestinationBuffer,
+ IN CONST VOID *SourceBuffer,
+ IN UINTN Length
+ )
+{
+ return GlueCopyMem (DestinationBuffer, SourceBuffer, Length);
+}
+#endif
+
+#ifndef EFI_DEBUG
+#define PrintRanges(r)
+#else
+/**
+ Show memory range information by debug macro
+
+ @param[in] ranges - Memory range information structure
+**/
+VOID
+PrintRanges (
+ IN MEMORY_RANGE *ranges
+ )
+{
+ while (ranges->Start != END_RANGES) {
+ DEBUG ((EFI_D_INFO, "%08lx - %08lx\n", ranges->Start, ranges->End));
+ ++ranges;
+ }
+}
+#endif
+
+/**
+ Sort memory ranges.
+
+ @param[in][out] MemoryRanges - Memory Ranges
+ @param[in] MemoryRangesSize - Number of entries in Memory Ranges
+
+ @retval Status code
+
+--*/
+EFI_STATUS
+SortRanges (
+ IN OUT MEMORY_RANGE *MemoryRanges,
+ IN UINTN MemoryRangesSize
+ )
+{
+ UINT32 Count, Index;
+ MEMORY_RANGE TempRange;
+ MEMORY_RANGE *Range;
+
+ Range = MemoryRanges;
+
+ if (MemoryRangesSize == 0) {
+ while (Range->Start != END_RANGES) {
+ MemoryRangesSize++;
+ Range++;
+ }
+ }
+
+ for (Count = 1; Count < MemoryRangesSize; Count++) {
+ for (Index = 0; Index < MemoryRangesSize - Count; Index++) {
+ if (MemoryRanges[Index].Start > MemoryRanges[Index + 1].Start) {
+ TempRange.Start = MemoryRanges[Index].Start;
+ TempRange.End = MemoryRanges[Index].End;
+ MemoryRanges[Index].Start = MemoryRanges[Index + 1].Start;
+ MemoryRanges[Index].End = MemoryRanges[Index + 1].End;
+ MemoryRanges[Index + 1].Start = TempRange.Start;
+ MemoryRanges[Index + 1].End = TempRange.End;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Subtracts set of memory ranges from other set of memory ranges.
+ Resulting set will contain ranges covering InputRanges with SubRanges excluded.
+
+ Both InputRanges and SubRanges must be provided in ascending order
+ by Start address. Output set is also sorted.
+
+ All sets end with a range which Start address is END_RANGES.
+
+ @param[out] OutputRanges - Output buffer
+ @param[in] OutputRangesSize - Number of entries in output buffer
+ @param[in] InputRanges - Input ranges to substract from
+ @param[in] SubRanges - Ranges to be excluded from InputRanges
+
+ @retval EFI_SUCCESS - Success
+ @retval EFI_BUFFER_TOO_SMALL - Not enough space in output buffer
+**/
+STATIC
+EFI_STATUS
+SubtractRanges (
+ OUT MEMORY_RANGE *OutputRanges,
+ IN UINTN OutputRangesSize,
+ IN MEMORY_RANGE *InputRanges,
+ IN MEMORY_RANGE *SubRanges
+ )
+{
+ MEMORY_RANGE *SubRange;
+ MEMORY_RANGE Current;
+ UINTN OutIndex;
+
+ ASSERT (OutputRanges != InputRanges);
+ ASSERT (OutputRanges != SubRanges);
+
+ DEBUG ((EFI_D_INFO, "Sub ranges Before Sorting:\n"));
+ PrintRanges (SubRanges);
+ SortRanges (SubRanges, 0);
+ DEBUG ((EFI_D_INFO, "Sub ranges After Sorting:\n"));
+ PrintRanges (SubRanges);
+
+ OutIndex = 0;
+ while (InputRanges->Start != END_RANGES) {
+ Current.Start = InputRanges->Start;
+ Current.End = InputRanges->End;
+ SubRange = SubRanges;
+ while (SubRange->Start != END_RANGES) {
+ if ((Current.Start < SubRange->End) && (Current.End > SubRange->Start)) {
+ if (Current.Start < SubRange->Start) {
+ if (OutIndex + 1 >= OutputRangesSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ OutputRanges[OutIndex].Start = Current.Start;
+ OutputRanges[OutIndex].End = MIN (Current.End, SubRange->Start);
+ ++OutIndex;
+ }
+
+ if (Current.End > SubRange->End) {
+ Current.Start = SubRange->End;
+ } else {
+ Current.Start = END_RANGES;
+ }
+ }
+
+ ++SubRange;
+ }
+
+ if (Current.Start != END_RANGES) {
+ if (OutIndex + 1 >= OutputRangesSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ OutputRanges[OutIndex].Start = Current.Start;
+ OutputRanges[OutIndex].End = Current.End;
+ ++OutIndex;
+ }
+
+ ++InputRanges;
+ }
+
+ ASSERT (OutIndex < OutputRangesSize);
+ OutputRanges[OutIndex].Start = END_RANGES;
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns total length of ranges in the set Ranges.
+
+ @param[in] Ranges - Array of memory ranges.
+
+ @retval The size of memory range
+**/
+STATIC
+UINT64
+SumRanges (
+ IN MEMORY_RANGE *Ranges
+ )
+{
+ UINT64 Size;
+ Size = 0;
+ while (Ranges->Start != END_RANGES) {
+ Size += RANGE_LENGTH (Ranges);
+ ++Ranges;
+ }
+
+ return Size;
+}
+
+
+/**
+ This routing is executed to clear all pending wake events and then enable wake events.
+
+ @param[in] EnablePme - set to TRUE to enable PME event
+
+ @retval EFI_SUCCESS - Operation successfully performed
+**/
+EFI_STATUS
+RapidStartClearAndEnablePmeEvent (
+ IN BOOLEAN EnablePme
+ )
+{
+ RAPID_START_PPI *This;
+ EFI_STATUS Status;
+ RAPID_START_INSTANCE *Instance;
+ RAPID_START_PERSISTENT_DATA *RapidStartData;
+ RAPID_START_MEM_DATA *RapidStartMemData;
+ PCH_SERIES PchSeries;
+ UINT32 PmBase;
+
+ PchSeries = GetPchSeries();
+ PmBase = MmioRead32 (
+ MmPciAddress (
+ 0,
+ 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;
+
+ Status = PeiServicesLocatePpi (&gRapidStartPpiGuid, 0, NULL, (VOID **) &This);
+ ASSERT_EFI_ERROR (Status);
+ Instance = RAPID_START_INSTANCE_FROM_THIS (This);
+ RapidStartData = &Instance->Data;
+ RapidStartMemData = RAPID_START_MEM_DATA_PTR (RapidStartData);
+ DEBUG ((EFI_D_ERROR, "RapidStart: RapidStartMemData @ %X\n", RapidStartMemData));
+
+ ///
+ /// Clear all pending wake events
+ ///
+ RapidStartClearOemPmeEvent ();
+ if (PchSeries == PchLp) {
+ IoWrite32 (PmBase + R_PCH_ACPI_GPE0_STS_127_96, ~0u);
+ } else if (PchSeries == PchH) {
+ IoWrite32 (PmBase + R_PCH_ACPI_GPE0a_STS, ~0u);
+ IoWrite32 (PmBase + R_PCH_ACPI_GPE0b_STS, ~0u);
+ }
+ IoWrite16 (
+ PmBase + R_PCH_ACPI_PM1_STS,
+ B_PCH_ACPI_PM1_STS_WAK | B_PCH_ACPI_PM1_STS_RTC | B_PCH_ACPI_PM1_STS_PWRBTN
+ );
+
+ ///
+ /// Enable wake events
+ ///
+ if (EnablePme == TRUE) {
+ if (PchSeries == PchLp) {
+ IoOr32 (PmBase + R_PCH_ACPI_GPE0_EN_127_96, RapidStartMemData->GPE0);
+ } else if (PchSeries == PchH) {
+ IoOr32 (PmBase + R_PCH_ACPI_GPE0a_EN, RapidStartMemData->GPE0a);
+ IoOr32 (PmBase + R_PCH_ACPI_GPE0b_EN, RapidStartMemData->GPE0b);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ RapidStart End of PEI handler.
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS - Ppi callback function executed successfully
+**/
+STATIC
+EFI_STATUS
+RapidStartS4AtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ UINT32 PmBase;
+ EFI_STATUS Status;
+ RAPID_START_PPI *This;
+ RAPID_START_INSTANCE *Instance;
+ RAPID_START_PERSISTENT_DATA *RapidStartData;
+
+ DEBUG ((EFI_D_INFO, "RapidStartS4AtEndOfPei ()\n"));
+
+ PmBase = MmioRead32 (
+ MmPciAddress (
+ 0,
+ 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;
+
+ Status = PeiServicesLocatePpi (&gRapidStartPpiGuid, 0, NULL, (VOID **) &This);
+ ASSERT_EFI_ERROR (Status);
+ Instance = RAPID_START_INSTANCE_FROM_THIS (This);
+ RapidStartData = &Instance->Data;
+
+ RapidStartWANetDetect (PeiServices, RapidStartData->WlanMmioSpace);
+ RapidStartClearAndEnablePmeEvent (TRUE);
+
+ DEBUG ((EFI_D_ERROR, "RapidStart: Switching to S4\n"));
+ IoAndThenOr32 (
+ PmBase + R_PCH_ACPI_PM1_CNT,
+ (UINT32)~B_PCH_ACPI_PM1_CNT_SLP_TYP,
+ (UINT32) (V_PCH_ACPI_PM1_CNT_S4 | B_PCH_ACPI_PM1_CNT_SLP_EN)
+ );
+
+ EFI_DEADLOOP ();
+ return EFI_SUCCESS;
+}
+
+/**
+ RapidStart End of PEI handler.
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS - Ppi callback function executed successfully
+**/
+STATIC
+EFI_STATUS
+RapidStartRecoveryAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ UINT32 PmBase;
+
+ DEBUG ((EFI_D_INFO, "RapidStartRecoveryAtEndOfPei ()\n"));
+
+ RapidStartClearAndEnablePmeEvent (TRUE);
+
+ PmBase = MmioRead32 (
+ MmPciAddress (
+ 0,
+ 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;
+
+ DEBUG ((EFI_D_ERROR, "RapidStart: Switching state back to S3\n"));
+ IoAndThenOr32 (
+ PmBase + R_PCH_ACPI_PM1_CNT,
+ (UINT32)~B_PCH_ACPI_PM1_CNT_SLP_TYP,
+ (UINT32) (V_PCH_ACPI_PM1_CNT_S3 | B_PCH_ACPI_PM1_CNT_SLP_EN)
+ );
+
+ EFI_DEADLOOP ();
+ return EFI_SUCCESS;
+}
+
+/**
+ Executes necessary RapidStart late initialization after Boot Script done.
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS - RapidStart initialization successful
+**/
+STATIC
+EFI_STATUS
+RapidStartExitAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ DEBUG ((EFI_D_INFO, "RapidStartExitAtEndOfPei ()\n"));
+ return RapidStartEnableAcpi (PeiServices);
+}
+
+/**
+ PEI_PERMANENT_MEMORY_INSTALLED_PPI handler.
+ RapidStart transition is triggered here in case RapidStart is postoponed untill memory available in PEI.
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS
+**/
+STATIC
+EFI_STATUS
+RapidStartMemoryInstalled (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ RAPID_START_PPI *RapidStartPpi;
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "RapidStartMemoryInstalled ()\n"));
+ Status = (*PeiServices)->LocatePpi (PeiServices, &gRapidStartPpiGuid, 0, NULL, (VOID **) &RapidStartPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ RapidStartDoTransition (RapidStartPpi);
+
+ return EFI_SUCCESS;
+}
+
+#ifdef EFI_DEBUG
+/**
+ Dump MCH relevant registers
+**/
+STATIC
+VOID
+DumpMcRegisters (
+ VOID
+ )
+{
+ UINTN MchBase;
+ MchBase = MmPciAddress (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, 0);
+
+ DEBUG ((EFI_D_INFO, "TOM : %lx\n", MmioRead64 (MchBase + R_SA_TOM)));
+ DEBUG ((EFI_D_INFO, "TSEGMB : %x\n", MmioRead32 (MchBase + R_SA_TSEGMB)));
+ DEBUG ((EFI_D_INFO, "TOLUD : %x\n", MmioRead32 (MchBase + R_SA_TOLUD)));
+ DEBUG ((EFI_D_INFO, "TOUUD : %lx\n", MmioRead64 (MchBase + R_SA_TOUUD)));
+ DEBUG ((EFI_D_INFO, "BDSM : %x\n", MmioRead32 (MchBase + R_SA_BDSM)));
+ DEBUG ((EFI_D_INFO, "BGSM : %x\n", MmioRead32 (MchBase + R_SA_BGSM)));
+ DEBUG ((EFI_D_INFO, "DPR : %x\n", MmioRead32 (MchBase + R_SA_DPR)));
+ DEBUG ((EFI_D_INFO, "MESEG_B : %lx\n", MmioRead64 (MchBase + R_SA_MESEG_BASE)));
+ DEBUG ((EFI_D_INFO, "MESEG_M : %lx\n", MmioRead64 (MchBase + R_SA_MESEG_MASK)));
+ DEBUG ((EFI_D_INFO, "REMAPBASE: %lx\n", MmioRead64 (MchBase + R_SA_REMAPBASE)));
+ DEBUG ((EFI_D_INFO, "REMAPLIM : %lx\n", MmioRead64 (MchBase + R_SA_REMAPLIMIT)));
+ DEBUG ((EFI_D_INFO, "SMRAMC : %02x\n", MmioRead8 (MchBase + R_SA_SMRAMC)));
+ DEBUG ((EFI_D_INFO, "GGC : %04x\n", MmioRead16 (MchBase + R_SA_GGC)));
+}
+
+/**
+ Show Hexadecimal number by debug macro
+
+ @param[in] Ptr - Pointer to buffer of number that will be showed
+ @param[in] Length - The length of the number buffer
+**/
+VOID
+PrintHex (
+ IN UINT8 *Ptr,
+ IN UINTN Length
+ )
+{
+ while (Length--) {
+ DEBUG ((EFI_D_INFO, "%02x", *Ptr++));
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+}
+#endif
+
+/**
+ Retrieves SMRAM areas ffrom SMRAM HOB, and places the ranges found in
+ SmRamRanges array.
+
+ @param[out] SmRamRanges - Output buffer
+ @param[in] SmRamRangesSize - Number of entries in output buffer
+
+ @retval EFI_SUCCESS
+ @retval EFI_NOT_FOUND
+ @retval EFI_BUFFER_TOO_SMALL
+**/
+STATIC
+EFI_STATUS
+GetSmRamRanges (
+ OUT MEMORY_RANGE *SmRamRanges,
+ IN UINTN SmRamRangesSize,
+ IN UINT32 IedSize
+ )
+{
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmmDescBlock;
+ UINTN Index;
+ VOID *Hob;
+
+ Hob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserve);
+ if (Hob == NULL) {
+ DEBUG ((EFI_D_ERROR, "SMRAM HOB not found!\n"));
+ ASSERT (0);
+ return EFI_NOT_FOUND;
+ }
+
+ SmmDescBlock = (VOID *) ((UINT8 *) Hob + sizeof (EFI_HOB_GUID_TYPE));
+
+ DEBUG ((EFI_D_INFO, "Found %d SMM ranges\n", SmmDescBlock->NumberOfSmmReservedRegions));
+
+ ASSERT (SmRamRangesSize > SmmDescBlock->NumberOfSmmReservedRegions);
+ if (SmRamRangesSize <= SmmDescBlock->NumberOfSmmReservedRegions) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ for (Index = 0; Index < SmmDescBlock->NumberOfSmmReservedRegions; ++Index) {
+ SmRamRanges[Index].Start = SmmDescBlock->Descriptor[Index].PhysicalStart;
+ if (SmRamRanges[Index].Start > 0x100000) {
+ //
+ // This is TSEG SMRAM range.
+ // IED region is also part of SMRAM but not reported in SMRAM Hob so here include IED for Rapid Start saving/restoring.
+ //
+ DEBUG ((EFI_D_INFO, "Ied size %X\n", IedSize));
+ SmRamRanges[Index].End = SmRamRanges[Index].Start + SmmDescBlock->Descriptor[Index].PhysicalSize + IedSize;
+ }
+ }
+
+ SmRamRanges[Index].Start = END_RANGES;
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves DPR areas from SA register, and places the ranges found in
+ DprRanges array.
+
+ @param[out] DprRanges - Output buffer
+
+ @retval EFI_SUCCESS
+ @retval EFI_NOT_FOUND
+**/
+STATIC
+EFI_STATUS
+GetDprRanges (
+ OUT MEMORY_RANGE *DprRanges
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN MchBase;
+ UINT32 DprData;
+ UINT32 DprSize;
+
+ Status = EFI_NOT_FOUND;
+ Index = 0;
+
+ MchBase = MmPciAddress (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, 0);
+ DprData = MmioRead32 (MchBase + R_SA_DPR);
+ DprSize = (DprData & V_DPR_DPRSIZE_MASK) << (N_SA_DPR_TOPOFDPR_OFFSET - N_DPR_DPRSIZE_OFFSET);
+
+ ///
+ /// Check whether DPR protection and DPR is enabled or not.
+ ///
+ if ((DprData & (B_SA_DPR_PRS_MASK + B_SA_DPR_EPM_MASK)) == (B_SA_DPR_PRS_MASK + B_SA_DPR_EPM_MASK)) {
+ DprRanges[Index].Start = (DprData & B_SA_DPR_TOPOFDPR_MASK) - DprSize;
+ DprRanges[Index].End = DprData & B_SA_DPR_TOPOFDPR_MASK;
+ DEBUG ((EFI_D_INFO, "DPR Start = %08lx, End = %08lx\n", DprRanges[Index].Start, DprRanges[Index].End));
+
+ Index ++;
+ Status = EFI_SUCCESS;
+ }
+
+ DprRanges[Index].Start = END_RANGES;
+ return Status;
+}
+
+/**
+ Constructs memory ranges to be saved/restored by RapidStart.
+ Reserved areas are excluded.
+
+ @param[out] OutMemoryRanges - Output buffer
+ @param[in] OutMemoryRangesSize - Number of entries in output buffer
+ @param[in] RapidStartData - A data buffer stored RapidStart internal non-volatile information.
+
+ @retval EFI_SUCCESS
+**/
+STATIC
+EFI_STATUS
+BuildMemoryRanges (
+ OUT MEMORY_RANGE *OutMemoryRanges,
+ IN UINTN OutMemoryRangesSize,
+ IN RAPID_START_PERSISTENT_DATA *RapidStartData
+ )
+{
+ MEMORY_RANGE MainRanges[4];
+ MEMORY_RANGE ResvRanges[3];
+ EFI_STATUS Status;
+ UINTN Index;
+
+ ///
+ /// Always exclude Legacy SMRAM ranges (A0000~BFFFF) since this range can not perform DMA.
+ /// If Legacy SMRAM is used it will be handled separately.
+ ///
+ Index = 0;
+ MainRanges[Index].Start = 0;
+ MainRanges[Index].End = LEGACY_SMRAM_BASE;
+ ++Index;
+ MainRanges[Index].Start = LEGACY_SMRAM_BASE + LEGACY_SMRAM_SIZE;
+ MainRanges[Index].End = RapidStartData->Tolm;
+ ++Index;
+ if (RapidStartData->Tohm > MEM_EQU_4GB) {
+ MainRanges[Index].Start = MEM_EQU_4GB;
+ MainRanges[Index].End = RapidStartData->Tohm;
+ ++Index;
+ }
+
+ ASSERT (Index < VARIABLE_SIZE (MainRanges));
+ MainRanges[Index].Start = END_RANGES;
+
+ Index = 0;
+ ResvRanges[Index].Start = RapidStartData->RapidStartMem;
+ ResvRanges[Index].End = RapidStartData->RapidStartMem + RapidStartData->RapidStartMemSize;
+ ++Index;
+#ifdef RAPID_START_ON_MEMORY_INSTALLED
+ ResvRanges[Index].Start = RapidStartData->AcpiReservedMemoryBase;
+ ResvRanges[Index].End = RapidStartData->AcpiReservedMemoryBase + RapidStartData->AcpiReservedMemorySize;
+ ++Index;
+#endif
+ ASSERT (Index < VARIABLE_SIZE (ResvRanges));
+ ResvRanges[Index].Start = END_RANGES;
+
+ ///
+ /// Exclude reserved ranges
+ ///
+ Status = SubtractRanges (
+ OutMemoryRanges,
+ OutMemoryRangesSize,
+ MainRanges,
+ ResvRanges
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+#ifdef RAPID_START_NO_SMRAM_INTEGRITY_CHECK
+#define HASHING_CONTEXT typedef enum { EMPTY }
+#define HashingInit(c, r) EFI_SUCCESS
+#define HashingProcessChunk(c) TRUE
+#define HashingCompleteAndVerify(c, t) EFI_SUCCESS
+#else
+
+typedef struct {
+ MEMORY_RANGE *Range;
+ UINT8 *Ptr;
+ VOID *HashState;
+} HASHING_CONTEXT;
+
+#define HASHING_CHUNK (4 * EFI_PAGE_SIZE)
+
+/**
+ Initializes secure hash algorithm.
+
+ @param[in] Context - Hashing context
+ @param[in] Ranges - Memory ranges to be included in resulting hash
+
+ @retval EFI_SUCCESS Hashing process completed
+ @retval ERROR Return the error code if PeiServicesAllocatePool () failed
+**/
+STATIC
+EFI_STATUS
+HashingInit (
+ HASHING_CONTEXT *Context,
+ MEMORY_RANGE *Ranges
+ )
+{
+ UINTN HashStatetSize;
+ EFI_STATUS Status;
+
+ Context->Range = Ranges;
+ Context->Ptr = (VOID *) (UINTN) Ranges->Start;
+
+ HashStatetSize = IfsSecureHashGetContextSize ();
+ ASSERT (HashStatetSize != 0);
+
+ Status = PeiServicesAllocatePool (HashStatetSize, &Context->HashState);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ RapidStartSecureHashInit (Context->HashState);
+ return EFI_SUCCESS;
+}
+
+/**
+ Processes next chunk of memory.
+
+ @param[in] Context - Hashing context
+
+ @retval TRUE if hashing complete, FALSE othervise.
+**/
+STATIC
+BOOLEAN
+HashingProcessChunk (
+ HASHING_CONTEXT *Context
+ )
+{
+ UINTN Size;
+ if (Context->Range->Start == END_RANGES) {
+ return TRUE;
+ }
+
+ DEBUG ((EFI_D_INFO, "#"));
+ Size = (UINTN) Context->Range->End - (UINTN) Context->Ptr;
+ if (Size > HASHING_CHUNK) {
+ Size = HASHING_CHUNK;
+ }
+
+ RapidStartSecureHashUpdate (Context->HashState, (VOID *) Context->Ptr, Size);
+ Context->Ptr += Size;
+ if ((UINTN) Context->Ptr == (UINTN) Context->Range->End) {
+ ++Context->Range;
+ Context->Ptr = (VOID *) (UINTN) Context->Range->Start;
+ }
+
+ return FALSE;
+}
+
+/**
+ Finishes hashing and saves/verifies resulting value depending on RapidStart transition.
+
+ @param[in] Context - Hashing context
+ @param[in] Instance - RapidStart instance
+
+ @retval EFI_SECURITY_VIOLATION - SMRAM content has changed.
+ @retval EFI_SUCCESS - SMRAM content no change.
+**/
+STATIC
+EFI_STATUS
+HashingCompleteAndVerify (
+ HASHING_CONTEXT *Context,
+ RAPID_START_INSTANCE *Instance
+ )
+{
+ UINT8 Hash[RAPID_START_SECURE_HASH_LENGTH];
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "HashingCompleteAndVerify...\n"));
+
+ Status = EFI_SUCCESS;
+ while (!HashingProcessChunk (Context)) {
+ }
+
+ RapidStartSecureHashFinal (Context->HashState, Hash);
+
+#ifdef EFI_DEBUG
+ PrintHex (Hash, RAPID_START_SECURE_HASH_LENGTH);
+#endif
+
+ if (Instance->Transition == RapidStartExit) {
+ if (CompareMem (Hash, Instance->SmRamHash, RAPID_START_SECURE_HASH_LENGTH) != 0) {
+ DEBUG ((EFI_D_ERROR, "Error: SMRAM content has changed!\n"));
+ Status = EFI_SECURITY_VIOLATION;
+ }
+
+ ZeroMem (Instance->SmRamHash, RAPID_START_SECURE_HASH_LENGTH);
+ } else {
+ Status = RapidStartSaveSecureHash (Hash);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ ZeroMem (Hash, RAPID_START_SECURE_HASH_LENGTH);
+ ZeroMem (Context->HashState, IfsSecureHashGetContextSize ());
+
+ return Status;
+}
+
+#endif
+
+/**
+ Check ME status and wait for ME init done
+
+ @retval EFI_SUCCESS - ME Init done
+ @retval EFI_TIMEOUT - ME is not ready after timeout occurred
+ @retval EFI_DEVICE_ERROR - Error reported by ME F/W
+**/
+STATIC
+EFI_STATUS
+WaitMeInitDone (
+ VOID
+ )
+{
+ EFI_PEI_SERVICES **PeiServices;
+ PEI_HECI_PPI *HeciPpi;
+ EFI_STATUS Status;
+ UINT32 MeStatus;
+ UINT32 MeMode;
+ UINTN Timeout;
+
+ DEBUG ((EFI_D_INFO, "WaitMeInitDone()\n"));
+
+ PeiServices = GetPeiServicesTablePointer ();
+
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gPeiHeciPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &HeciPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = HeciPpi->GetMeMode (PeiServices, &MeMode);
+ ASSERT_EFI_ERROR (Status);
+ ///
+ /// If ME is in ME_DEBUG mode, return success.
+ ///
+ if (MeMode == ME_MODE_DEBUG) {
+ return EFI_SUCCESS;
+ }
+
+ if (MeMode != ME_MODE_NORMAL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Timeout = 0;
+ while (Timeout < ME_FID_TIMEOUT) {
+ Status = HeciPpi->GetMeStatus (PeiServices, &MeStatus);
+ ASSERT_EFI_ERROR (Status);
+
+ if (ME_STATUS_IS_ME_FW_INIT_COMPLETE (MeStatus)) {
+ return EFI_SUCCESS;;
+ }
+
+ PchPmTimerStall (1000);
+ Timeout++;
+ }
+
+ DEBUG ((EFI_D_ERROR, "ME init timeout!\n"));
+ return EFI_TIMEOUT;
+}
+
+/**
+ Calls Func for each port in PortMap.
+
+ @param[in] Ahci - SATA controller information structure
+ @param[in] Func - Pointer to function to be called with Ahci and port number passed as arguments
+ @param[in] PortMap - Bitmap of ports for wich Func is to be called
+**/
+STATIC
+VOID
+ForEachAhciPort (
+ IN AHCI_CONTEXT *Ahci,
+ IN EFI_STATUS (*Func) (AHCI_CONTEXT*, UINTN),
+ IN UINT32 PortMap
+ )
+{
+ UINTN Port;
+
+ for (Port = 0; Port <= 31; ++Port) {
+ if (PortMap & (1u << Port)) {
+ Func (Ahci, Port);
+ }
+ }
+ return;
+}
+
+/**
+ Issues STANDBY_IMMEDIATE command to given SATA port.
+ Port is initialized first and disabled afterwards.
+
+ @param Ahci - SATA controller information structure
+ @param Port - Port number to issue command to
+
+ @retval EFI_SUCCESS - fucntion executed successfully
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_DEVICE_ERROR - AHCI port initialization failed or Command failed
+**/
+STATIC
+EFI_STATUS
+StandbyAhciPort (
+ IN AHCI_CONTEXT *Ahci,
+ IN UINTN Port
+ )
+{
+ AHCI_CONTEXT AhciTmp;
+ EFI_STATUS Status;
+ DEBUG ((EFI_D_INFO, "StandbyAhciPort(%d)\n", Port));
+
+ AhciTmp = *Ahci;
+ AhciTmp.Port = Port;
+ Status = AhciPortInit (&AhciTmp);
+ if (Status == EFI_SUCCESS) {
+ Status = AhciSimpleCommand (&AhciTmp, ATA_CMD_STANDBY_IMMEDIATE);
+ }
+ AhciPortDone (&AhciTmp);
+ return Status;
+}
+
+/**
+ Initialize Ahci port for RapidStart accessing SSD in early stage.
+
+ @param[in] Instance - Instance contains required data and function for RapidStart
+**/
+STATIC
+VOID
+RapidStartInitAhci (
+ IN RAPID_START_INSTANCE *Instance
+ )
+{
+ AHCI_CONTEXT *Ahci;
+ RAPID_START_PERSISTENT_DATA *RapidStartData;
+
+ DEBUG ((EFI_D_INFO, "InitAhci\n"));
+
+ Ahci = &Instance->Ahci;
+ RapidStartData = &Instance->Data;
+
+ Ahci->Abar = (UINT32) RapidStartData->MmioSpace;
+ Ahci->PortBase = (UINT32) RapidStartData->RapidStartMem;
+ Ahci->PortSize = RapidStartData->RapidStartMemSize -
+ sizeof (RAPID_START_MEM_DATA) -
+ RapidStartData->ZeroBitmapSize -
+ RapidStartData->Crc32RecordSize;
+ Ahci->Port = RapidStartData->StoreSataPort;
+
+ DEBUG ((EFI_D_INFO, "Ahci.Abar = %08x\n", Ahci->Abar));
+ DEBUG ((EFI_D_INFO, "Ahci.Port = %d\n", Ahci->Port));
+ DEBUG ((EFI_D_INFO, "Ahci.PortBase = %08x\n", Ahci->PortBase));
+ DEBUG ((EFI_D_INFO, "Ahci.PortSize = %08x\n", Ahci->PortSize));
+
+ ///
+ /// Restore SATA ports configuration
+ ///
+ MmioWrite8 (
+ MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_SATA,
+ PCI_FUNCTION_NUMBER_PCH_SATA,
+ R_PCH_SATA_PCS),
+ RapidStartData->SataPortConfiguration
+ );
+
+ AhciInit (Ahci);
+ AhciSpinUp (Ahci);
+}
+
+#define RETURN_ON_ERROR(expr) \
+ do { \
+ EFI_STATUS _status; \
+ _status = (expr); \
+ if (EFI_ERROR (_status)) { \
+ return _status; \
+ } \
+ } while (0)
+
+/**
+ Transfer SMRAM ranges to/from RapidStart partition.
+
+ Legacy SMRAM 0xA0000-0xC0000 is handled indirectly.
+
+ @param[in] Ahci - AHCI context
+ @param[in,out] AtaCmd - ATA command structure
+ @param[in] Transition - RapidStart transition
+ @param[in] SmRamRanges - Array of SMRAM ranges
+
+ @retval EFI_STATUS - the error code returned by AhciPostCommand () if failed.
+ @retval EFI_SUCCESS - Hasing SMRAM process completed.
+**/
+STATIC
+EFI_STATUS
+RapidStartHandleSmRam (
+ IN AHCI_CONTEXT *Ahci,
+ IN OUT ATA_COMMAND *AtaCmd,
+ IN RAPID_START_TRANSITION Transition,
+ IN MEMORY_RANGE *SmRamRanges
+ )
+{
+ MEMORY_RANGE *Range;
+ UINTN CmdMask;
+
+ DEBUG ((EFI_D_INFO, "SMRAM handling...\n"));
+ PrintRanges (SmRamRanges);
+
+ if (Transition == RapidStartEntry) {
+ ///
+ /// Ensure original LEGACY_SMRAM_BUFFER data has been stored into RapidStart Store before we modifying it.
+ ///
+ RETURN_ON_ERROR (AhciWaitAllComplete (Ahci));
+ CopyMem ((VOID *) LEGACY_SMRAM_BUFFER, (VOID *) LEGACY_SMRAM_BASE, (UINTN) LEGACY_SMRAM_SIZE);
+ }
+
+ CmdMask = 0;
+ Range = SmRamRanges;
+ while (Range->Start != END_RANGES) {
+ AtaCmd->SectorCount = MEM_TO_SECT (RANGE_LENGTH (Range));
+ if (Range->Start == LEGACY_SMRAM_BASE) {
+ ASSERT (Range->End == LEGACY_SMRAM_BASE + LEGACY_SMRAM_SIZE);
+ AtaCmd->MemAddr = LEGACY_SMRAM_BUFFER;
+ RETURN_ON_ERROR (AhciPostCommand (Ahci, AtaCmd, &CmdMask));
+ } else {
+ AtaCmd->MemAddr = Range->Start;
+ CmdMask = ~CmdMask;
+ RETURN_ON_ERROR (AhciPostCommand (Ahci, AtaCmd, &CmdMask));
+ CmdMask = ~CmdMask;
+ }
+
+ ++Range;
+ }
+
+ AhciWaitComplete (Ahci, CmdMask);
+ if (Transition == RapidStartExit) {
+ CopyMem ((VOID *) LEGACY_SMRAM_BASE, (VOID *) LEGACY_SMRAM_BUFFER, (UINTN) LEGACY_SMRAM_SIZE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Performs AHCI commands required to save or restore memory content.
+
+ @param[in] Instance - RapidStart instance
+ @param[in] MainRanges - Ranges of memory to be transferred
+ @param[in] SmRamRanges - SMRAM ranges, to by handled by RapidStartHandleSmRam
+
+ @retval EFI_SUCCESS - RapidStart transition succeeded
+ @retval EFI_TIMEOUT - AHCI timeout occured
+ @retval EFI_DEVICE_ERROR - AHCI device not ready
+ @retval EFI_NOT_STARTED - Transition cancellation happened, abort the transition.
+ @retval EFI_NO_MEDIA - No RapidStart Store available or RapidStart store has been changed. Abort RapidStart transition.
+ @retval EFI_BAD_BUFFER_SIZE - Memory configuration changed. Abort RapidStart transition.
+**/
+STATIC
+EFI_STATUS
+RapidStartMemoryDiskTransfer (
+ IN RAPID_START_INSTANCE *Instance,
+ IN MEMORY_RANGE *MainRanges,
+ IN MEMORY_RANGE *SmRamRanges
+ )
+{
+ RAPID_START_PERSISTENT_DATA *RapidStartData;
+ AHCI_CONTEXT *Ahci;
+ RAPID_START_TRANSITION Transition;
+ ATA_COMMAND AtaCmd;
+ MEMORY_RANGE *MemRanges;
+ MEMORY_RANGE *Range;
+ EFI_STATUS Status;
+ UINT32 *ZeroPageBitMap;
+ UINT32 SectorsLeft;
+ HASHING_CONTEXT Hashing;
+ BOOLEAN HashingDone;
+ UINT64 DataCount;
+ UINT32 *SmramBuffer;
+ UINT32 ZeroBitmapForSmramBuffer;
+ UINT64 LbaForData;
+ UINT64 SmRamBufferLba;
+ EFI_STATUS GfxDisplayStatus;
+ PEI_GFX_PPI *PeiGfxPpi;
+ GFX_RESTORE_MEM_TABLE *GfxRestoreMemTable;
+ GFX_RESTORE_MEM_TABLE *FbRestoreMemTable;
+ UINT32 Index, GfxIndex, MemIndex;
+ MEMORY_RANGE *GfxResvRanges;
+ MEMORY_RANGE *TempMemRanges;
+ UINT64 PageAlignedDssAddr;
+ UINT64 PageAlignedDssSize;
+
+ MemRanges = (MEMORY_RANGE *) AllocatePool (sizeof(MEMORY_RANGE) * (MAX_MEMORY_RANGES + 1));
+ if (MemRanges == NULL) {
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for MemRanges! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ GfxResvRanges = (MEMORY_RANGE *) AllocatePool (sizeof(MEMORY_RANGE) * (MAX_GFX_MEMORY_RANGES + 1));
+ if (GfxResvRanges == NULL) {
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for GfxResvRanges! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TempMemRanges = (MEMORY_RANGE *) AllocatePool (sizeof(MEMORY_RANGE) * (MAX_MEMORY_RANGES + 1));
+ if (GfxResvRanges == NULL) {
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for TempMemRanges! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RapidStartData = &Instance->Data;
+ Ahci = &Instance->Ahci;
+ Transition = Instance->Transition;
+
+ ///
+ /// Exclude SMRAM ranges as they are handled separetely
+ ///
+ Status = SubtractRanges (
+ MemRanges,
+ VARIABLE_SIZE (MemRanges),
+ MainRanges,
+ SmRamRanges
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ AtaCmd.Auxiliary.Data = 0;
+ if (Transition == RapidStartEntry) {
+ if (RapidStartData->HybridHardDisk == 1) {
+ Status = AhciHybridHardDiskSupport (Ahci);
+ if (Status == EFI_SUCCESS) {
+ if (Ahci->TotalRemainingCacheCapacityInSector < RapidStartData->StoreSectors) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ AtaCmd.Auxiliary.r.HybridPriority = Ahci->HybridInfo.HybridPriority;
+ AtaCmd.Auxiliary.r.HybridInfoValid = 1;
+ } else if (Status != EFI_UNSUPPORTED) {
+ return Status;
+ }
+ }
+
+ Ahci->PollCancellation = TRUE;
+ AtaCmd.Command = ATA_CMD_WRITE_DMA_EXT;
+ AtaCmd.Direction = AHCI_DIR_HOST2DEV;
+ } else {
+ Ahci->PollCancellation = FALSE;
+ AtaCmd.Command = ATA_CMD_READ_DMA_EXT;
+ AtaCmd.Direction = AHCI_DIR_DEV2HOST;
+ if (RapidStartData->HybridHardDisk == 1) {
+ if (((Ahci->Identify[ATA_ID_DEV_HYBRID_FEATURE_SUPPORT] & B_ATA_ID_DEV_HYBRID_FEATURE_SUPPORT) &
+ (Ahci->Identify[ATA_ID_DEV_HYBRID_FEATURE_ENABLE] & B_ATA_ID_DEV_HYBRID_FEATURE_ENABLE))
+ ) {
+ AtaCmd.Auxiliary.r.HybridPriority = 0;
+ AtaCmd.Auxiliary.r.HybridInfoValid = 1;
+ }
+ }
+ }
+
+ AtaCmd.Feature = 0;
+
+#ifdef RAPID_START_WHOLE_MEMORY_CHECK
+ ///
+ /// Save CRC32 for memory below 4GB
+ ///
+ if (Transition == RapidStartEntry) {
+ SaveOrCompareCrc32 (FALSE, 0, RapidStartData->Tolm, RapidStartData);
+ }
+#endif
+ ///
+ /// Head sector store the Zero Page Bitmap, so save/restore it first
+ ///
+ ZeroPageBitMap = RAPID_START_ZERO_PAGE_BITMAP_PTR (RapidStartData);
+ ///
+ /// For Entry, store RapidStart Store UID in the head of Zero Page Bitmap.
+ ///
+ if (Transition == RapidStartEntry) {
+ *(UINT64 *) (ZeroPageBitMap) = RapidStartData->RapidStartStoreUid;
+ }
+
+ AtaCmd.MemAddr = (UINTN) ZeroPageBitMap;
+ AtaCmd.Lba = RapidStartData->StoreLbaAddr;
+ AtaCmd.SectorCount = MEM_TO_SECT (RapidStartData->ZeroBitmapSize + RapidStartData->Crc32RecordSize);
+ RETURN_ON_ERROR (AhciPostCommand (Ahci, &AtaCmd, NULL));
+
+ LbaForData = RapidStartData->StoreLbaAddr + MEM_TO_SECT (RapidStartData->ZeroBitmapSize + RapidStartData->Crc32RecordSize);
+ GfxDisplayStatus = EFI_UNSUPPORTED;
+ if (RapidStartData->DssAddress != (UINT64)NULL) {
+ PageAlignedDssAddr = RapidStartData->DssAddress & ~EFI_PAGE_MASK;
+ PageAlignedDssSize = (EFI_SIZE_TO_PAGES(PageAlignedDssAddr) < EFI_SIZE_TO_PAGES(RapidStartData->DssAddress) ) ? EFI_PAGE_SIZE : 0;
+ PageAlignedDssSize += RapidStartData->DssSize;
+ AtaCmd.MemAddr = (UINTN) PageAlignedDssAddr;
+ AtaCmd.Lba = LbaForData;
+ AtaCmd.SectorCount = MEM_TO_SECT (PageAlignedDssSize);
+ RETURN_ON_ERROR (AhciPostCommand (Ahci, &AtaCmd, NULL));
+ LbaForData += MEM_TO_SECT (PageAlignedDssSize);
+
+ GfxIndex = 0;
+ GfxResvRanges[GfxIndex].Start = PageAlignedDssAddr;
+ GfxResvRanges[GfxIndex].End = PageAlignedDssAddr + PageAlignedDssSize;
+ ++GfxIndex;
+
+ //
+ // save/restore GTT, GMM... ets Gfx memory related Range
+ //
+ GfxDisplayStatus = PeiServicesLocatePpi (&gPeiGfxPpiGuid, 0, NULL, &PeiGfxPpi);
+ ASSERT_EFI_ERROR (GfxDisplayStatus);
+ if (!EFI_ERROR (GfxDisplayStatus)) {
+ if (Transition == RapidStartExit) {
+ RETURN_ON_ERROR (AhciWaitAllComplete (Ahci));
+ }
+ GfxDisplayStatus = PeiGfxPpi->GetRestoreMemTable (GetPeiServicesTablePointer (), &GfxRestoreMemTable);
+ DEBUG ((EFI_D_ERROR, "Gfx GetRestoreMemTable Status = %r, NumberofEntry = %x\n", GfxDisplayStatus, GfxRestoreMemTable->NumOfEntry));
+ if (!EFI_ERROR (GfxDisplayStatus) && (GfxRestoreMemTable->NumOfEntry <= GFX_RESTORE_RANGE)) {
+ for (Index = 0; Index < GfxRestoreMemTable->NumOfEntry; Index++) {
+ DEBUG ((EFI_D_ERROR, "Gfx related memory Ranges [%x] - BaseAddress is %lx, Size is %lx\n", Index, GfxRestoreMemTable->MemRangeEntry[Index].BaseAddress, GfxRestoreMemTable->MemRangeEntry[Index].Size));
+
+ GfxResvRanges[GfxIndex].Start = GfxRestoreMemTable->MemRangeEntry[Index].BaseAddress;
+ GfxResvRanges[GfxIndex].End = GfxRestoreMemTable->MemRangeEntry[Index].BaseAddress + GfxRestoreMemTable->MemRangeEntry[Index].Size;
+
+ MemIndex = 0;
+ while (MemRanges[MemIndex].Start != END_RANGES) {
+ if (GfxResvRanges[GfxIndex].Start >= MemRanges[MemIndex].Start && GfxResvRanges[GfxIndex].End <= MemRanges[MemIndex].End) {
+ DEBUG ((EFI_D_ERROR, "Gfx related memory Ranges [%x] - BaseAddress is %lx, Size is %lx has been save(restore).\n", Index, GfxRestoreMemTable->MemRangeEntry[Index].BaseAddress, GfxRestoreMemTable->MemRangeEntry[Index].Size));
+
+ AtaCmd.MemAddr = (UINTN) GfxRestoreMemTable->MemRangeEntry[Index].BaseAddress;
+ AtaCmd.Lba = LbaForData;
+ AtaCmd.SectorCount = MEM_TO_SECT (GfxRestoreMemTable->MemRangeEntry[Index].Size);
+ RETURN_ON_ERROR (AhciPostCommand (Ahci, &AtaCmd, NULL));
+ LbaForData += MEM_TO_SECT (GfxRestoreMemTable->MemRangeEntry[Index].Size);
+ ++GfxIndex;
+ break;
+ }
+ ++MemIndex;
+ }
+ }
+ }
+ //
+ // save/restore Gfx Frame Buffer Ranges
+ //
+ if (RapidStartData->DisplayType == 1 && !EFI_ERROR (GfxDisplayStatus)) {
+ if (Transition == RapidStartExit) {
+ RETURN_ON_ERROR (AhciWaitAllComplete (Ahci));
+ }
+ GfxDisplayStatus = PeiGfxPpi->GetRestoreFbRange (GetPeiServicesTablePointer (), &FbRestoreMemTable);
+ DEBUG ((EFI_D_ERROR, "Gfx GetRestoreFbRange Status = %r, NumberofEntry = %x\n", GfxDisplayStatus, FbRestoreMemTable->NumOfEntry));
+ if (!EFI_ERROR (GfxDisplayStatus) && (FbRestoreMemTable->NumOfEntry <= FB_RESTORE_RANGE)) {
+ for (Index = 0; Index < FbRestoreMemTable->NumOfEntry; Index++) {
+ DEBUG ((EFI_D_ERROR, "Gfx FB memory Ranges [%x] - BaseAddress is %lx, Size is %lx\n", Index, FbRestoreMemTable->MemRangeEntry[Index].BaseAddress, FbRestoreMemTable->MemRangeEntry[Index].Size));
+
+ GfxResvRanges[GfxIndex].Start = FbRestoreMemTable->MemRangeEntry[Index].BaseAddress;
+ GfxResvRanges[GfxIndex].End = FbRestoreMemTable->MemRangeEntry[Index].BaseAddress + FbRestoreMemTable->MemRangeEntry[Index].Size;
+
+ MemIndex = 0;
+ while (MemRanges[MemIndex].Start != END_RANGES) {
+ if (GfxResvRanges[GfxIndex].Start >= MemRanges[MemIndex].Start && GfxResvRanges[GfxIndex].End <= MemRanges[MemIndex].End) {
+ DEBUG ((EFI_D_ERROR, "Gfx FB memory Ranges [%x] - BaseAddress is %lx, Size is %lx has been save(restore).\n", Index, FbRestoreMemTable->MemRangeEntry[Index].BaseAddress, FbRestoreMemTable->MemRangeEntry[Index].Size));
+
+ AtaCmd.MemAddr = (UINTN) FbRestoreMemTable->MemRangeEntry[Index].BaseAddress;
+ AtaCmd.Lba = LbaForData;
+ AtaCmd.SectorCount = MEM_TO_SECT (FbRestoreMemTable->MemRangeEntry[Index].Size);
+ RETURN_ON_ERROR (AhciPostCommand (Ahci, &AtaCmd, NULL));
+ LbaForData += MEM_TO_SECT (FbRestoreMemTable->MemRangeEntry[Index].Size);
+ ++GfxIndex;
+ break;
+ }
+ ++MemIndex;
+ }
+ }
+ }
+ }
+ ASSERT (GfxIndex < VARIABLE_SIZE (GfxResvRanges));
+ GfxResvRanges[GfxIndex].Start = END_RANGES;
+
+ //
+ // Copy MemRanges to TempMemRanges
+ //
+ GfxDisplayStatus = SubtractRanges (
+ TempMemRanges,
+ VARIABLE_SIZE (TempMemRanges),
+ MainRanges,
+ SmRamRanges
+ );
+ ASSERT_EFI_ERROR (GfxDisplayStatus);
+
+ //
+ // Exclude Gfx related memory ranges as they are handled separetely
+ //
+ GfxDisplayStatus = SubtractRanges (
+ MemRanges,
+ VARIABLE_SIZE (MemRanges),
+ TempMemRanges,
+ GfxResvRanges
+ );
+ ASSERT_EFI_ERROR (GfxDisplayStatus);
+
+ }
+ }
+
+ if (RapidStartData->DssAddress != (UINT64)NULL) {
+ if (!EFI_ERROR (GfxDisplayStatus)) {
+ switch(Transition) {
+ case RapidStartEntry:
+ DEBUG ((EFI_D_INFO, "Calling GfxDisplay in RapidStart entry flow...\n"));
+// GfxDisplayStatus = RapidStartGfxDisplayScreen();
+ break;
+ case RapidStartExit:
+ DEBUG ((EFI_D_INFO, "Calling GfxDisplay in RapidStart exit flow...\n"));
+ if (RapidStartUnattendedWake() == FALSE) {
+ GfxDisplayStatus = RapidStartGfxDisplayScreen();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (Transition == RapidStartExit) {
+ AtaCmd.Lba = LbaForData;
+ if ((RapidStartHandleSmRam (Ahci, &AtaCmd, Transition, SmRamRanges) == EFI_DEVICE_ERROR) ||
+ (AhciWaitAllComplete (Ahci) == EFI_DEVICE_ERROR)
+ ) {
+ DEBUG (
+ (
+ EFI_D_ERROR,
+ "\nEFI_DEVICE_ERROR in first DMA command, probably RapidStart Store changed. Aborted RapidStart resume.\n"
+ )
+ );
+ RapidStartSetFlag (RAPID_START_FLAG_STORE_CHANGE);
+ return EFI_NO_MEDIA;
+ }
+
+ if (*(UINT64 *) (ZeroPageBitMap) != RapidStartData->RapidStartStoreUid) {
+ DEBUG ((EFI_D_ERROR, "\nRapidStart Store UID Mismatched! Aborted RapidStart resume.\n"));
+ RapidStartSetFlag (RAPID_START_FLAG_STORE_CHANGE);
+ return EFI_NO_MEDIA;
+ }
+ }
+
+ ZeroPageBitMap += 2;
+ DEBUG ((EFI_D_INFO, "Transfer ranges:\n"));
+ PrintRanges (MemRanges);
+
+ RETURN_ON_ERROR (HashingInit (&Hashing, SmRamRanges));
+
+ DataCount = 0;
+
+ HashingDone = FALSE;
+ AtaCmd.Lba = LbaForData + MEM_TO_SECT (SumRanges (SmRamRanges));
+ Range = MemRanges;
+ SmRamBufferLba = AtaCmd.Lba;
+ ///
+ /// Log the last Lba which not in used.
+ ///
+ Instance->NotUsedLba = AtaCmd.Lba;
+ PERF_START_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2510);
+ while (Range->Start != END_RANGES) {
+ AtaCmd.MemAddr = Range->Start;
+ SectorsLeft = MEM_TO_SECT (RANGE_LENGTH (Range));
+ while (SectorsLeft > 0) {
+ if (HashingDone || AhciHasFreeCmdSlot (Ahci)) {
+ if (SectorsLeft > AHCI_MAX_SECTORS) {
+ AtaCmd.SectorCount = AHCI_MAX_SECTORS;
+ } else {
+ AtaCmd.SectorCount = SectorsLeft;
+ }
+
+ SectorsLeft -= AtaCmd.SectorCount;
+ RETURN_ON_ERROR (AhciPostCommandWithZeroFilter (Ahci, &AtaCmd, NULL, ZeroPageBitMap, &SmRamBufferLba));
+ DataCount += AtaCmd.SectorCount << SECTOR_SHIFT;
+ } else {
+ if (Ahci->PollCancellation && RapidStartShouldCancelEntry ()) {
+ return EFI_NOT_STARTED;
+ }
+
+ HashingDone = HashingProcessChunk (&Hashing);
+ }
+ ///
+ /// Log the last Lba which not in used.
+ ///
+ Instance->NotUsedLba = AtaCmd.Lba;
+ }
+
+ ++Range;
+ }
+
+ RETURN_ON_ERROR (HashingCompleteAndVerify (&Hashing, Instance));
+ PERF_END_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2511);
+
+ if (Transition == RapidStartEntry) {
+ Ahci->PollCancellation = FALSE;
+ AtaCmd.Lba = LbaForData;
+ RETURN_ON_ERROR (RapidStartHandleSmRam (Ahci, &AtaCmd, Transition, SmRamRanges));
+ ///
+ /// Restore LEGACY_SMRAM_BUFFER
+ ///
+ AtaCmd.Command = ATA_CMD_READ_DMA_EXT;
+ AtaCmd.Direction = AHCI_DIR_DEV2HOST;
+ AtaCmd.MemAddr = LEGACY_SMRAM_BUFFER;
+ AtaCmd.SectorCount = MEM_TO_SECT (LEGACY_SMRAM_SIZE);
+ AtaCmd.Lba = SmRamBufferLba;
+ RETURN_ON_ERROR (AhciPostCommandWithZeroFilter (Ahci, &AtaCmd, NULL, ZeroPageBitMap, NULL));
+ }
+ ///
+ /// If LEGACY_SMRAM_BUFFER contained zero pages, they have to be zero-ed
+ ///
+ ZeroBitmapForSmramBuffer = *(ZeroPageBitMap + (LEGACY_SMRAM_BUFFER / EFI_PAGE_SIZE / 8 / 4));
+ SmramBuffer = (UINT32 *) LEGACY_SMRAM_BUFFER;
+ if (ZeroBitmapForSmramBuffer != 0) {
+ while (SmramBuffer < (UINT32 *) (LEGACY_SMRAM_BUFFER + LEGACY_SMRAM_SIZE)) {
+ if (ZeroBitmapForSmramBuffer & 1) {
+ ZeroMem (SmramBuffer, EFI_PAGE_SIZE);
+ }
+
+ ZeroBitmapForSmramBuffer >>= 1;
+ SmramBuffer += (EFI_PAGE_SIZE / 4);
+ }
+ }
+
+ PERF_START_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2520);
+ Status = AhciWaitAllComplete (Ahci);
+ PERF_END_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2521);
+
+#ifdef RAPID_START_WHOLE_MEMORY_CHECK
+ ///
+ /// Verify CRC32 for memory below 4GB
+ ///
+ if (Transition == RapidStartExit) {
+ SaveOrCompareCrc32 (TRUE, 0, RapidStartData->Tolm, RapidStartData);
+ }
+#endif
+
+ return Status;
+}
+
+/**
+ Save/Restore memory content to/from RapidStart Store
+
+ @param[in] Instance - RapidStart instance
+
+ @retval EFI_SUCCESS - RapidStart transition succeeded
+ @retval EFI_BAD_BUFFER_SIZE - Memory configuration changed. Abort RapidStart transition.
+ @retval EFI_BUFFER_TOO_SMALL - RapidStart Store size is too small to store memory content
+ @retval EFI_TIMEOUT - AHCI timeout occured
+ @retval EFI_DEVICE_ERROR - AHCI device not ready
+**/
+STATIC
+EFI_STATUS
+RapidStartTransitionInternal (
+ IN RAPID_START_INSTANCE *Instance
+ )
+{
+ RAPID_START_PERSISTENT_DATA *RapidStartData;
+ AHCI_CONTEXT *Ahci;
+ UINTN MchBase;
+ UINT8 OldSmramControl;
+ UINT32 OldTseg;
+ UINT8 OldPam[PAM_COUNT];
+ MEMORY_RANGE *MemRanges;
+ MEMORY_RANGE SmRamRanges[MAX_SMRAM_RANGES + 1];
+ UINTN Index;
+ EFI_STATUS Status;
+ UINT32 OldDpr;
+
+ MemRanges = (MEMORY_RANGE *) AllocatePool (sizeof(MEMORY_RANGE) * (MAX_MEMORY_RANGES + 1));
+ if (MemRanges == NULL) {
+ DEBUG ((EFI_D_ERROR, "Failed to allocate memory for MemRanges! \n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RapidStartData = &Instance->Data;
+ Ahci = &Instance->Ahci;
+
+#ifdef EFI_DEBUG
+ DumpMcRegisters ();
+#endif
+ DEBUG ((EFI_D_INFO, "Mem : %x\n", (UINT32) RapidStartData->RapidStartMem));
+ DEBUG ((EFI_D_INFO, "Io : %x\n", (UINT32) RapidStartData->MmioSpace));
+ DEBUG (
+ (EFI_D_INFO,
+ "Store: port=%d start=%lx size=%x\n",
+ RapidStartData->StoreSataPort,
+ RapidStartData->StoreLbaAddr,
+ RapidStartData->StoreSectors)
+ );
+
+ MchBase = MmPciAddress (0, SA_MC_BUS, SA_MC_DEV, SA_MC_FUN, 0);
+ if (RapidStartData->Tolm != (MmioRead32 (MchBase + R_SA_BDSM) & B_SA_BDSM_BDSM_MASK)) {
+ DEBUG ((EFI_D_ERROR, "Memory Tolm changed\n"));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (RapidStartData->Tohm != (MmioRead64 (MchBase + R_SA_TOUUD) & B_SA_TOUUD_TOUUD_MASK)) {
+ DEBUG ((EFI_D_ERROR, "Memory Tohm changed\n"));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ DEBUG ((EFI_D_INFO, "Total Memory: %lx\n", RapidStartData->TotalMem));
+
+ Status = GetSmRamRanges (SmRamRanges, VARIABLE_SIZE (SmRamRanges), Instance->IedSize);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "SMRAM ranges:\n"));
+ PrintRanges (SmRamRanges);
+
+ Status = BuildMemoryRanges (
+ MemRanges,
+ VARIABLE_SIZE (MemRanges),
+ RapidStartData
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((EFI_D_INFO, "Memory ranges:\n"));
+ PrintRanges (MemRanges);
+
+ ///
+ /// Save and open SMRAM
+ ///
+ OldSmramControl = MmioRead8 (MchBase + R_SA_SMRAMC);
+ MmioWrite8 (MchBase + R_SA_SMRAMC, B_SA_SMRAMC_D_OPEN_MASK | B_SA_SMRAMC_G_SMRAME_MASK);
+
+ ///
+ /// Open PAM regions
+ ///
+ for (Index = 0; Index < PAM_COUNT; ++Index) {
+ OldPam[Index] = MmioRead8 (MchBase + R_SA_PAM0 + Index);
+ MmioWrite8 (MchBase + R_SA_PAM0 + Index, B_SA_PAM1_HIENABLE_MASK | B_SA_PAM1_LOENABLE_MASK);
+ }
+ ///
+ /// Disable TSEG and DPR
+ ///
+ OldTseg = MmioRead32 (MchBase + R_SA_TSEGMB);
+ MmioWrite32 (MchBase + R_SA_TSEGMB, RapidStartData->Tolm);
+ OldDpr = MmioRead32 (MchBase + R_SA_DPR);
+ MmioAnd32 (MchBase + R_SA_DPR, (UINT32) ~B_SA_DPR_EPM_MASK);
+
+ PERF_START_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2500);
+ Status = AhciPortInit (Ahci);
+ PERF_END_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2501);
+
+ //
+ // Unlock device if password locked
+ //
+ PERF_START_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2530);
+ if (Status == EFI_SUCCESS) {
+ Status = AhciGetLockStatus (Ahci);
+ if (Status == EFI_ACCESS_DENIED) {
+ if (Instance->Transition == RapidStartEntry) {
+ Instance->PwdStatus = RapidStartGetDriveUnlockPassword (
+ GetPeiServicesTablePointer (),
+ Instance->Transition,
+ Instance->Data.StoreSataPort,
+ (UINT8 *) Instance->HddPassword,
+ &Instance->FreezeLock
+ );
+ }
+
+ if (Instance->PwdStatus == EFI_SUCCESS) {
+ Status = AhciSecurityUnlock (Ahci, Instance->HddPassword);
+ if (Instance->FreezeLock) {
+ AhciSimpleCommand (Ahci, ATA_CMD_SECURITY_FREEZE_LOCK);
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "RapidStart: No drive password provided!"));
+ }
+ }
+ }
+ ZeroMem (Instance->HddPassword, ATA_PASSWORD_LEN);
+ PERF_END_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2531);
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // DPR will be disable temporary, so we won't exculde this region.
+ // To save/restore DPR region as normal memory does.
+ //
+
+ Instance->NotUsedLba = RapidStartData->StoreLbaAddr;
+
+ PERF_START_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2540);
+ Status = RapidStartMemoryDiskTransfer (Instance, MemRanges, SmRamRanges);
+ PERF_END_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2541);
+
+ if ((Instance->Transition == RapidStartEntry) && (Status == EFI_SUCCESS)) {
+ AhciSimpleCommand (Ahci, ATA_CMD_FLUSH_CACHE);
+ AhciSimpleCommand (Ahci, ATA_CMD_STANDBY_IMMEDIATE);
+ AhciPortDone (Ahci);
+ ForEachAhciPort (Ahci, StandbyAhciPort, AhciGetPresentPorts () & ~(1u << Ahci->Port));
+ } else {
+ ///
+ /// 1. In RapidStart Entry, if user has canceled RapidStart Entry flow, TRIM RapidStart Store.
+ /// 2. In RapidStart Resume, only TRIM when Resume successfully, SMRAM content changed.
+ ///
+#ifdef RAPID_START_TRIM_ON_RESUME
+ if (((Instance->Transition == RapidStartEntry) && (Status == EFI_NOT_STARTED)) ||
+ ((Instance->Transition == RapidStartExit) && ((Status == EFI_SUCCESS) || (Status == EFI_SECURITY_VIOLATION)))
+ ) {
+ DEBUG ((EFI_D_INFO, "\nNot used LBA in RapidStart store = %lX\n", Instance->NotUsedLba));
+ ASSERT (Instance->NotUsedLba > RapidStartData->StoreLbaAddr);
+ Ahci->PollCancellation = FALSE;
+
+ PERF_START_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2550);
+ AhciTrimRange (
+ Ahci,
+ RapidStartData->StoreLbaAddr,
+ (UINT32) (Instance->NotUsedLba - RapidStartData->StoreLbaAddr)
+ );
+ PERF_END_EX (NULL, L"EventRec", NULL, AsmReadTsc (), 0x2551);
+ }
+#endif
+ }
+ AhciPortDone (Ahci);
+ }
+
+ AhciDone (Ahci);
+
+ //
+ // Restore TSEG
+ //
+ MmioWrite32 (MchBase + R_SA_TSEGMB, OldTseg);
+ MmioWrite32 (MchBase + R_SA_DPR, OldDpr);
+
+ //
+ // Restore PAM regions
+ //
+ for (Index = 0; Index < PAM_COUNT; ++Index) {
+ MmioWrite8 (MchBase + R_SA_PAM0 + Index, OldPam[Index]);
+ }
+ //
+ // Restore SMRAMC
+ //
+ MmioWrite8 (MchBase + R_SA_SMRAMC, OldSmramControl);
+
+ return Status;
+}
+
+/**
+ Restores Memory pointers required by MemoryInit to install S3 reserved area on S3 resume.
+
+ @param[in] This - RapidStart PPI
+**/
+STATIC
+VOID
+RapidStartRestoreS3Pointers (
+ IN RAPID_START_PPI *This
+ )
+{
+ RAPID_START_INSTANCE *Instance;
+ RAPID_START_PERSISTENT_DATA *RapidStartData;
+ UINT64 AcpiVariableSet64;
+ ACPI_VARIABLE_SET *AcpiVariableSet;
+ EFI_PEI_READ_ONLY_VARIABLE_PPI *ReadOnlyVariable;
+ UINTN VarSize;
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "RapidStartRestoreS3Pointers\n"));
+
+ Instance = RAPID_START_INSTANCE_FROM_THIS (This);
+ RapidStartData = &Instance->Data;
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariablePpiGuid, 0, NULL, (VOID **) &ReadOnlyVariable);
+ ASSERT_EFI_ERROR (Status);
+
+ VarSize = sizeof (AcpiVariableSet64);
+ Status = ReadOnlyVariable->PeiGetVariable (
+ GetPeiServicesTablePointer (),
+ ACPI_GLOBAL_VARIABLE,
+ &gEfiAcpiVariableGuid,
+ NULL,
+ &VarSize,
+ &AcpiVariableSet64
+ );
+
+ AcpiVariableSet = (ACPI_VARIABLE_SET *) (UINTN) AcpiVariableSet64;
+
+ ASSERT (!EFI_ERROR (Status) && AcpiVariableSet != NULL);
+ if (EFI_ERROR (Status) || AcpiVariableSet == NULL) {
+ return;
+ }
+
+#ifdef RAPID_START_USE_OLD_ACPI_VARIABLE_SET
+ AcpiVariableSet->SystemMemoryLength = RapidStartData->SystemMemoryLengthBelow4GB;
+#else
+ AcpiVariableSet->SystemMemoryLengthBelow4GB = RapidStartData->SystemMemoryLengthBelow4GB;
+ AcpiVariableSet->SystemMemoryLengthAbove4GB = RapidStartData->SystemMemoryLengthAbove4GB;
+#endif
+ AcpiVariableSet->AcpiReservedMemoryBase = RapidStartData->AcpiReservedMemoryBase;
+ AcpiVariableSet->AcpiReservedMemorySize = RapidStartData->AcpiReservedMemorySize;
+
+ DEBUG ((EFI_D_INFO, "SystemMemoryLengthBelow4GB %lx\n", RapidStartData->SystemMemoryLengthBelow4GB));
+ DEBUG ((EFI_D_INFO, "SystemMemoryLengthAbove4GB %lx\n", RapidStartData->SystemMemoryLengthAbove4GB));
+ DEBUG ((EFI_D_INFO, "AcpiReservedMemoryBase %lx\n", RapidStartData->AcpiReservedMemoryBase));
+ DEBUG ((EFI_D_INFO, "AcpiReservedMemorySize %x\n", RapidStartData->AcpiReservedMemorySize));
+
+}
+
+/**
+ Check if RapidStart support is enabled.
+
+ @param[in] This - Pointer to RapidStart PPI
+
+ @retval TRUE if RapidStart support is enabled FALSE otherwise
+**/
+BOOLEAN
+RapidStartIsEnabled (
+ IN RAPID_START_PPI *This
+ )
+{
+ RAPID_START_INSTANCE *Instance;
+ Instance = RAPID_START_INSTANCE_FROM_THIS (This);
+ return Instance->Enabled;
+}
+
+/**
+ Detremines RapidStart transition.
+
+ @param[in] This - Pointer to RapidStart PPI
+
+ @retval RapidStart_TRANSITION - The RapidStart transition being performed
+**/
+RAPID_START_TRANSITION
+RapidStartGetMode (
+ IN RAPID_START_PPI *This
+ )
+{
+ RAPID_START_INSTANCE *Instance;
+ DEBUG ((EFI_D_INFO, "RapidStartGetMode()\n"));
+ Instance = RAPID_START_INSTANCE_FROM_THIS (This);
+ ASSERT (Instance->Transition != RapidStartTransitionMax);
+ return Instance->Transition;
+}
+
+/**
+ Performs actual RapidStart transition.
+
+ @param[in] This - RapidStart PPI
+
+ @retval EFI_ABORTED - RapidStart Entry or Resume failed
+ @retval EFI_SUCCESS - RapidStart Entry/Resume successfully
+**/
+STATIC
+EFI_STATUS
+RapidStartDoTransition (
+ IN RAPID_START_PPI *This
+ )
+{
+ RAPID_START_INSTANCE *Instance;
+ RAPID_START_PERSISTENT_DATA *RapidStartData;
+ RAPID_START_MEM_DATA *RapidStartMemData;
+ EFI_PEI_SERVICES **PeiServices;
+ EFI_STATUS Status;
+ EFI_STATUS MeStatus;
+ UINT32 PmBase;
+
+ ///
+ /// 1857 = Intel Rapid Start Technology
+ ///
+ IoWrite16 (0x80, 0x1857);
+
+ DEBUG ((EFI_D_INFO, "RapidStartDoTransition()\n"));
+
+ PmBase = MmioRead32 (
+ MmPciAddress (
+ 0,
+ 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;
+
+ PeiServices = GetPeiServicesTablePointer ();
+ Instance = RAPID_START_INSTANCE_FROM_THIS (This);
+ RapidStartData = &Instance->Data;
+
+ RapidStartMemData = RAPID_START_MEM_DATA_PTR (RapidStartData);
+
+ Status = RapidStartBeforeTransition (
+ GetPeiServicesTablePointer (),
+ Instance->Transition,
+ Instance->Data.StoreSataPort
+ );
+ if (EFI_ERROR (Status)) {
+ Instance->Transition = RapidStartNone;
+ }
+
+ switch (Instance->Transition) {
+
+ case RapidStartEntry:
+ DEBUG ((EFI_D_ERROR, "RapidStart ENTRY\n"));
+
+ ///
+ /// Clear all GPE events before SIM enabling
+ ///
+ RapidStartClearAndEnablePmeEvent (FALSE);
+
+ RapidStartMemData->EntryCanceled = 0;
+
+ Status = RapidStartTransitionInternal (Instance);
+
+ MeStatus = EFI_SUCCESS;
+ MeStatus = WaitMeInitDone ();
+ if (RapidStartMemData->OsWakeTimeEnabled && (Status != EFI_NOT_STARTED)) {
+ DEBUG (
+ (EFI_D_INFO,
+ "Setting RTC alarm to OS provided value %02d-%02d:%02d:%02d\n",
+ RapidStartMemData->OsWakeTime.Date,
+ RapidStartMemData->OsWakeTime.Hour,
+ RapidStartMemData->OsWakeTime.Minute,
+ RapidStartMemData->OsWakeTime.Second)
+ );
+
+ RtcSetAlarm (&RapidStartMemData->OsWakeTime);
+
+ //
+ // 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)
+ );
+ }
+ if (EFI_ERROR (Status) || EFI_ERROR (MeStatus)) {
+ if (Status == EFI_NOT_STARTED) {
+ ///
+ /// RapidStart Entry flow has been canceled, do S3 resume.
+ ///
+ DEBUG ((EFI_D_ERROR, "User canceled RapidStart!\n"));
+ RapidStartMemData->EntryCanceled = 1;
+ } else {
+ DEBUG ((EFI_D_ERROR, "RapidStart entry failed!\n"));
+ Instance->RapidStartGlobalNvs->EventsEnabled = 0;
+ Instance->RapidStartGlobalNvs->EventsAvailable = 0;
+ }
+
+ Status = PeiServicesNotifyPpi (&mRapidStartRecoveryNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ RapidStartAfterTransition (PeiServices, RapidStartEntry, Status, RapidStartData->StoreSataPort);
+ break;
+ }
+
+ RapidStartSetFlag (RAPID_START_FLAG_ENTRY_DONE);
+
+ RapidStartAfterTransition (PeiServices, RapidStartEntry, Status, RapidStartData->StoreSataPort);
+
+ Status = PeiServicesNotifyPpi (&mRapidStartS4NotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ break;
+
+ case RapidStartExit:
+ DEBUG ((EFI_D_ERROR, "RapidStart EXIT\n"));
+
+ Status = PeiServicesNotifyPpi (&mRapidStartExitNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = RapidStartTransitionInternal (Instance);
+
+ MeStatus = EFI_SUCCESS;
+
+ if (EFI_ERROR (Status) || EFI_ERROR (MeStatus)) {
+ DEBUG ((EFI_D_ERROR, "RapidStart exit failed!\n"));
+ if (EFI_ERROR (Status)) {
+ RapidStartAfterTransition (PeiServices, RapidStartExit, Status, RapidStartData->StoreSataPort);
+ }
+
+ if (EFI_ERROR (MeStatus)) {
+ RapidStartAfterTransition (PeiServices, RapidStartExit, MeStatus, RapidStartData->StoreSataPort);
+ }
+
+ PeiServicesResetSystem ();
+ EFI_DEADLOOP ();
+ }
+ ///
+ /// Set DISB
+ ///
+ MmioOr16 (
+ MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_GEN_PMCON_2),
+ B_PCH_LPC_GEN_PMCON_DRAM_INIT
+ );
+
+ RapidStartAfterTransition (PeiServices, RapidStartExit, EFI_SUCCESS, RapidStartData->StoreSataPort);
+ break;
+
+ case RapidStartNone:
+ ///
+ /// Cancelled
+ ///
+ Status = EFI_ABORTED;
+ break;
+
+ default:
+ ASSERT (0);
+ }
+
+ IoWrite16 (0x80, 0);
+
+ return Status;
+}
+
+/**
+ Executes or schedules RapidStart transition if appropriate.
+
+ @param[in] This - Pointer to RapidStart PPI
+ @param[out] BootMode - Boot mode that may be overridden
+
+ @retval EFI_SUCCESS - RapidStart transition performed/scheduled successfully
+ @retval EFI_ABORTED - RapidStart transition aborted
+**/
+STATIC
+EFI_STATUS
+RapidStartTransitionEntryPoint (
+ IN RAPID_START_PPI *This,
+ OUT EFI_BOOT_MODE *BootMode
+ )
+{
+ EFI_STATUS Status;
+ RAPID_START_TRANSITION Transition;
+
+ DEBUG ((EFI_D_INFO, "RapidStartTransitionEntryPoint\n"));
+
+ Transition = RapidStartGetMode (This);
+ Status = EFI_SUCCESS;
+
+ if (Transition != RapidStartNone) {
+#ifdef RAPID_START_ON_MEMORY_INSTALLED
+ RapidStartRestoreS3Pointers (This);
+ Status = PeiServicesNotifyPpi (&mRapidStartTransitionPpiNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+#else
+ Status = RapidStartDoTransition (This);
+#endif
+ if (Transition == RapidStartExit && BootMode != NULL) {
+ *BootMode = BOOT_ON_S3_RESUME;
+ ///
+ /// Update Boot Mode
+ ///
+ Status = PeiServicesSetBootMode (BOOT_ON_S3_RESUME);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Checks power button override status.
+
+ @retval TRUE if power button override has taken place, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsPowerButtonOverride (
+ VOID
+ )
+{
+ UINT32 PmBase;
+ PmBase = MmioRead32 (
+ MmPciAddress (
+ 0,
+ 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;
+
+ return (IoRead16 (PmBase + R_PCH_ACPI_PM1_STS) & B_PCH_ACPI_PM1_STS_PRBTNOR) != 0;
+}
+
+/**
+ Retrieves RapidStart non-volatile flag and data,
+ initializes RapidStart instance,
+ handles RapidStart entry conditions and prerequisites.
+
+ @param[in,out] Instance - RapidStart instance
+**/
+STATIC
+VOID
+RapidStartInitInstance (
+ IN OUT RAPID_START_INSTANCE *Instance
+ )
+{
+ EFI_PEI_READ_ONLY_VARIABLE_PPI *ReadOnlyVariable;
+ UINTN Size;
+ EFI_STATUS Status;
+ BOOLEAN RapidStartFlag;
+ UINT8 EventsEnabled;
+ UINT32 PmBase;
+ EFI_BOOT_MODE BootMode;
+ SA_PLATFORM_POLICY_PPI *SaPlatformPolicyPpi;
+
+ Instance->Signature = RAPID_START_INSTANCE_SIGNATURE;
+ Instance->Transition = RapidStartNone;
+ Instance->Enabled = FALSE;
+ Instance->FreezeLock = TRUE;
+ Instance->PwdStatus = EFI_NOT_FOUND;
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariablePpiGuid, 0, NULL, (VOID **) &ReadOnlyVariable);
+ ASSERT_EFI_ERROR (Status);
+
+ Size = sizeof (RAPID_START_PERSISTENT_DATA);
+ Status = ReadOnlyVariable->PeiGetVariable (
+ GetPeiServicesTablePointer (),
+ gRapidStartPersistentDataName,
+ &gRapidStartPersistentDataGuid,
+ NULL,
+ &Size,
+ &Instance->Data
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "RapidStart disabled (No RapidStart variable found)\n"));
+ return ;
+ }
+
+ Instance->Enabled = TRUE;
+ Instance->RapidStartGlobalNvs = (RAPID_START_GLOBAL_NVS_AREA *) Instance->Data.RapidStartGlobalNvsPtr;
+ DEBUG ((EFI_D_INFO, "RapidStartGlobalNVS: %x\n", Instance->RapidStartGlobalNvs));
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get IED size through the SaPlatformPolicy PPI
+ //
+ SaPlatformPolicyPpi = NULL;
+ Status = PeiServicesLocatePpi (
+ &gSaPlatformPolicyPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &SaPlatformPolicyPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+ if ((SaPlatformPolicyPpi != NULL) && (SaPlatformPolicyPpi->Revision >= SA_PLATFORM_POLICY_PPI_REVISION_9)) {
+ Instance->IedSize = SaPlatformPolicyPpi->PlatformData->IedSize;
+ } else {
+ Instance->IedSize = 0x400000;
+ }
+
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ DEBUG ((EFI_D_INFO, "S3 resume\n"));
+
+ PmBase = MmioRead32 (
+ MmPciAddress (
+ 0,
+ 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;
+
+ Status = RapidStartGetConfig (&EventsEnabled);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Check RTC alarm wake event
+ ///
+ if (IoRead16 (PmBase + R_PCH_ACPI_PM1_STS) & B_PCH_ACPI_PM1_STS_RTC) {
+ ///
+ /// Clear RTC Alarm Flag
+ ///
+ RtcRead (R_PCH_RTC_REGC);
+ if (EventsEnabled & RAPID_START_ACPI_RTC_WAKE) {
+ DEBUG ((EFI_D_INFO, "RapidStart on RTC wake\n"));
+ Instance->Transition = RapidStartEntry;
+ } else {
+ DEBUG ((EFI_D_INFO, "Boot from RapidStart cancellation or this is waking by OS timer\n"));
+ }
+ }
+ ///
+ /// Check for critical battery wake event
+ ///
+ else if ((EventsEnabled & RAPID_START_ACPI_BATT_WAKE) && RapidStartCheckCriticalBatteryWakeupEvent ()) {
+ DEBUG ((EFI_D_INFO, "RapidStart on critical battery wake from EC.\n"));
+ RapidStartInitializeCriticalBatteryWakeupEvent (FALSE);
+ RapidStartClearAllKscWakeStatus ();
+ Instance->Transition = RapidStartEntry;
+ }
+
+ return ;
+ }
+ ///
+ /// Check RapidStart non-volatile flag
+ ///
+ Status = RapidStartGetFlag (&RapidStartFlag);
+ if (EFI_ERROR (Status) || ((RapidStartFlag & RAPID_START_FLAG_ENTRY_DONE) == 0)) {
+ DEBUG ((EFI_D_INFO, "No RapidStart flag set\n"));
+ return ;
+ }
+ ///
+ /// RapidStart exit path (Cold boot assumed)
+ /// For security reasones need to clear SMRAM hash and drive password from non-volatile
+ /// memory first.
+ ///
+#ifndef RAPID_START_NO_SMRAM_INTEGRITY_CHECK
+ Status = RapidStartRestoreAndClearSecureHash (Instance->SmRamHash);
+#endif
+
+ Instance->PwdStatus = RapidStartGetDriveUnlockPassword (
+ GetPeiServicesTablePointer (),
+ RapidStartExit,
+ Instance->Data.StoreSataPort,
+ (UINT8 *) Instance->HddPassword,
+ &Instance->FreezeLock
+ );
+
+ ///
+ /// This is either RapidStart Resume flow or non-RapidStart transition
+ /// Clear RapidStart flag in the start point.
+ ///
+ RapidStartSetFlag (0);
+
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ if (IsPowerButtonOverride ()) {
+ DEBUG ((EFI_D_INFO, "PWRBTN override\n"));
+ return ;
+ }
+
+ DEBUG ((EFI_D_INFO, "RapidStart exit\n"));
+ Instance->Transition = RapidStartExit;
+}
+
+/**
+ Install RapiStartPpi.
+
+ @param[in] PeiServices - Pointer to PEI Services Table.
+ @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that caused this function to execute.
+ @param[in] Ppi - Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS
+**/
+STATIC
+EFI_STATUS
+InstallRapidStartPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ RAPID_START_INSTANCE *Instance;
+ EFI_STATUS Status;
+
+ Instance = AllocateZeroPool (sizeof (RAPID_START_INSTANCE));
+ ASSERT (Instance != NULL);
+ if (Instance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Instance->Ppi.Revision = RAPID_START_PPI_REVISION_1;
+ Instance->Ppi.GetMode = RapidStartGetMode;
+ Instance->Ppi.TransitionEntryPoint = RapidStartTransitionEntryPoint;
+ Instance->Ppi.IsEnabled = RapidStartIsEnabled;
+
+ Instance->PpiDesc.Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
+ Instance->PpiDesc.Guid = &gRapidStartPpiGuid;
+ Instance->PpiDesc.Ppi = &Instance->Ppi;
+
+ RapidStartInitInstance (Instance);
+
+ if (Instance->Transition != RapidStartNone) {
+ RapidStartInitAhci (Instance);
+ }
+ if (Instance->Transition == RapidStartEntry) {
+ ForEachAhciPort (
+ &Instance->Ahci,
+ AhciSpinUpPort,
+ AhciGetEnabledPorts () & ~(1u << Instance->Ahci.Port)
+ );
+ }
+
+ Status = PeiServicesInstallPpi (&Instance->PpiDesc);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ RapidStart PEIM entry point driver
+
+ @param[in] FfsHeader - FFS file header pointer of this driver
+ @param[in] PeiServices - Pointer to PEI service table
+
+ @retval EFI_SUCCESS - RapidStart PPI installed successfully
+ @retval EFI_OUT_OF_RESOURCES - Error in allocate required resource.
+**/
+EFI_STATUS
+RapidStartPeiEntryPoint (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ PEI_HECI_PPI *HeciPpi;
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "RapidStart: RapidStartPeiEntryPoint\n"));
+
+ ///
+ /// Install RapiStart Ppi when Heci Ppi is ready.
+ ///
+
+ Status = (*PeiServices)->LocatePpi (
+ PeiServices,
+ &gPeiHeciPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &HeciPpi
+ );
+ if (EFI_ERROR(Status)) {
+ Status = PeiServicesNotifyPpi (&mInstallRapidStartPpiNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+ return EFI_SUCCESS;
+ }
+
+ return InstallRapidStartPpi (PeiServices, NULL, NULL);
+} \ No newline at end of file
diff --git a/ReferenceCode/RapidStart/Pei/RapidStartPei.cif b/ReferenceCode/RapidStart/Pei/RapidStartPei.cif
new file mode 100644
index 0000000..e2f18c8
--- /dev/null
+++ b/ReferenceCode/RapidStart/Pei/RapidStartPei.cif
@@ -0,0 +1,14 @@
+<component>
+ name = "RapidStartPei"
+ category = ModulePart
+ LocalRoot = "ReferenceCode\RapidStart\Pei"
+ RefName = "RapidStartPei"
+[files]
+"RapidStartPei.sdl"
+"RapidStartPei.mak"
+"RapidStartPei.dxs"
+"RapidStartPei.c"
+"RapidStartAhci.c"
+"RapidStartAhci.h"
+"RapidStartPei.inf"
+<endComponent>
diff --git a/ReferenceCode/RapidStart/Pei/RapidStartPei.dxs b/ReferenceCode/RapidStart/Pei/RapidStartPei.dxs
new file mode 100644
index 0000000..9c903ca
--- /dev/null
+++ b/ReferenceCode/RapidStart/Pei/RapidStartPei.dxs
@@ -0,0 +1,41 @@
+/** @file
+ Dependency expression source file.
+
+@copyright
+ Copyright (c) 1999 - 2013 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 a 'Sample Driver' and is licensed as such
+ under the terms of your license agreement with Intel or your
+ vendor. This file may be modified by the user, subject to
+ the additional terms of the license agreement
+
+**/
+
+
+#include "AutoGen.h"
+#include "PeimDepex.h"
+#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB)
+#include "EfiDepex.h"
+#include "RapidStartConfig.h"
+#include EFI_PPI_DEPENDENCY (BootMode)
+#include EFI_PPI_DEPENDENCY (Variable)
+#include EFI_PPI_DEPENDENCY (Stall)
+
+#include EFI_PPI_DEPENDENCY (PchPeiInitDone)
+#include EFI_PPI_DEPENDENCY (SaPlatformPolicy)
+#endif
+
+DEPENDENCY_START
+ PEI_MASTER_BOOT_MODE_PEIM_PPI AND
+ PEI_STALL_PPI_GUID AND
+ PEI_READ_ONLY_VARIABLE_ACCESS_PPI_GUID AND
+ SA_PLATFORM_POLICY_PPI_GUID AND
+ PCH_PEI_INIT_DONE_PPI_GUID
+DEPENDENCY_END
diff --git a/ReferenceCode/RapidStart/Pei/RapidStartPei.inf b/ReferenceCode/RapidStart/Pei/RapidStartPei.inf
new file mode 100644
index 0000000..752c1ea
--- /dev/null
+++ b/ReferenceCode/RapidStart/Pei/RapidStartPei.inf
@@ -0,0 +1,119 @@
+## @file
+# Component description file for the RapidStart PEIM.
+#
+#@copyright
+# Copyright (c) 2004 - 2013 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 a 'Sample Driver' and is licensed as such
+# under the terms of your license agreement with Intel or your
+# vendor. This file may be modified by the user, subject to
+# the additional terms of the license agreement
+#
+
+[defines]
+BASE_NAME = RapidStartPei
+FILE_GUID = 53f019e9-bb0c-424b-870a-1faf10b1cb4c
+COMPONENT_TYPE = PE32_PEIM
+
+[sources.common]
+ RapidStartAhci.h
+ RapidStartAhci.c
+ RapidStartPei.c
+#
+# Edk II Glue Driver Entry Point
+#
+ EdkIIGluePeimEntryPoint.c
+
+[includes.common]
+ .
+ $(EDK_SOURCE)/Foundation/Efi
+ $(EDK_SOURCE)/Foundation/Include
+ $(EDK_SOURCE)/Foundation/Efi/Include
+ $(EDK_SOURCE)/Foundation/Framework/Include
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library
+ $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT)/Samplecode
+ $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT)/Samplecode/Include
+ $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT)/Samplecode/Library/RapidStartCommonLib
+ $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT)/Samplecode/Library/RapidStartPlatformLib/Pei
+ $(EFI_SOURCE)/$(PROJECT_RAPID_START_ROOT)/GfxDisplay/Library/Pei
+ $(EFI_SOURCE)/$(PROJECT_ME_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/Library/MeKernel/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/Include
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Api
+ $(EFI_SOURCE)/$(PROJECT_SA_ROOT)/$(PROJECT_SA_MRC)/Pei/Source/Include
+#
+# EDK II Glue Library utilizes some standard headers from EDK
+#
+ $(EFI_SOURCE)
+ $(EDK_SOURCE)/Foundation
+ $(EDK_SOURCE)/Foundation/Framework
+ $(EDK_SOURCE)/Foundation/Include/IndustryStandard
+ $(EDK_SOURCE)/Foundation/Core/Dxe
+ $(EDK_SOURCE)/Foundation/Include/Pei
+ $(EDK_SOURCE)/Foundation/Library/Dxe/Include
+ $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include
+ $(EFI_SOURCE)/Include
+
+[libraries.common]
+ EdkIIGlueBaseIoLibIntrinsic
+ EdkIIGlueBaseMemoryLib
+ EdkIIGluePeiDebugLibReportStatusCode
+ EdkIIGlueBaseLib
+ EdkIIGluePeiDxePostCodeLibReportStatusCode
+ EdkIIGluePeiReportStatusCodeLib
+ EdkIIGluePeiServicesLib
+ EdkIIGluePeiMemoryAllocationLib
+ EdkIIGlueBasePciLibPciExpress
+ EdkIIGlueBasePrintLib
+ RapidStartPpiLib
+#
+# Uncomment this only when ME is implemented
+#
+ MeLibPpi
+
+ EdkFrameworkPpiLib
+ IntelPchPpiLib
+ RapidStartCommonLib
+ RapidStartGuidLib
+ RapidStartPeiLib
+ GfxDisplayLibPei
+ PchPlatformLib
+ EdkIIGluePeiHobLib
+#
+# CryptoLib is required for SMRAM integrity check
+#
+ PeiCryptLib
+ OpensslLib
+ EdkIIGluePeiFirmwarePerformanceLib
+ IntelSaPpiLib
+
+[nmake.common]
+ IMAGE_ENTRY_POINT = _ModuleEntryPoint
+ DPX_SOURCE = RapidStartPei.dxs
+#
+# Module Entry Point
+#
+ C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=RapidStartPeiEntryPoint
+ C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ -D __EDKII_GLUE_BASE_MEMORY_LIB__ \
+ -D __EDKII_GLUE_PEI_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ -D __EDKII_GLUE_PEI_REPORT_STATUS_CODE_LIB__ \
+ -D __EDKII_GLUE_PEI_SERVICES_LIB__ \
+ -D __EDKII_GLUE_PEI_MEMORY_ALLOCATION_LIB__ \
+ -D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \
+ -D __EDKII_GLUE_BASE_PRINT_LIB__ \
+ -D __EDKII_GLUE_PEI_HOB_LIB__ \
+ -DRAPID_START_USE_OLD_ACPI_VARIABLE_SET
+
diff --git a/ReferenceCode/RapidStart/Pei/RapidStartPei.mak b/ReferenceCode/RapidStart/Pei/RapidStartPei.mak
new file mode 100644
index 0000000..52015a3
--- /dev/null
+++ b/ReferenceCode/RapidStart/Pei/RapidStartPei.mak
@@ -0,0 +1,151 @@
+#*************************************************************************
+#*************************************************************************
+#** **
+#** (C)Copyright 1985-2012, American Megatrends, Inc. **
+#** **
+#** All Rights Reserved. **
+#** **
+#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+#** **
+#** Phone: (770)-246-8600 **
+#** **
+#*************************************************************************
+#*************************************************************************
+
+#*************************************************************************
+# $Header: /Alaska/SOURCE/Modules/Intel Fast Flash Standby/iRST_SharkBay/RapidStartPei/RapidStartPei.mak 7 11/07/13 2:47a Joshchou $
+#
+# $Revision: 7 $
+#
+# $Date: 11/07/13 2:47a $
+#*************************************************************************
+# Revision History
+# ----------------
+# $Log: /Alaska/SOURCE/Modules/Intel Fast Flash Standby/iRST_SharkBay/RapidStartPei/RapidStartPei.mak $
+#
+# 7 11/07/13 2:47a Joshchou
+# [TAG] EIP142523
+# [Category] Spec Update
+# [Severity] Important
+# [Description] Update to RC 1.7.0
+#
+# 6 1/13/13 7:38a Bensonlai
+# [TAG] EIP112060
+# [Category] Spec Update
+# [Severity] Normal
+# [Description] [SBY]Intel Rapid Start Technology Framework Reference
+# Code Production Candidate 0.9.0
+# [Files] RapidStartDxe.c, RapidStartConfig.h, RapidStartDxe.dsc,
+# RapidStartPei.dsc, RapidStartPei.c, RapidStartPei.inf,
+# RapidStartPei.mak, RapidStartInfo.h
+#
+# 5 10/15/12 5:45a Bensonlai
+# [Category] Improvement
+# [Severity] Important
+# [Description] Rename all IFFS sting to Rapid Start.
+# [Files] Board\EM\RapidStartWrapper\*.*, ReferenceCode\RapidStart\*.*
+#
+# 4 9/26/12 3:26a Yurenlai
+# [TAG] None
+# [Category] Improvement
+# [Severity] Important
+# [Description] Update Intel Rapid Start Technology Framework Reference
+# Code Beta Version 0.7.0.
+# [Description] ReferenceCode\RapidStart\*.*, RapidStartPeiLib.h
+#
+# 2 5/14/12 11:26p Yurenlai
+# [TAG] EIP90075
+# [Category] Improvement
+# [Severity] Important
+# [Description] Update Intel Rapid Start Technology Framework Reference
+# Code Alpha 2 Version 0.5.6.
+# [Description] ReferenceCode\RapidStart\*.*,
+# Board\EM\iFfsWrapper\Library\*.*
+#
+# 1 4/19/12 7:50a Yurenlai
+# Initial check in.
+#
+#*************************************************************************
+
+all : RapidStartPei
+RapidStartPei : $(BUILD_DIR)\RapidStartPei.mak RapidStartPeiBin
+
+$(BUILD_DIR)\RapidStartPei.mak : $(RapidStartPei_DIR)\$(@B).cif $(RapidStartPei_DIR)\$(@B).mak $(BUILD_RULES)
+ $(CIF2MAK) $(RapidStartPei_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS)
+
+RapidStartPei_INCLUDES=\
+ $(EdkIIGlueLib_INCLUDES)\
+ $(INTEL_PCH_INCLUDES)\
+ $(INTEL_MCH_INCLUDES)\
+ $(ME_INCLUDES)\
+ /I$(GfxDisplayLibPei_DIR)\
+ $(RAPIDSTART_INCLUDES)\
+ /I$(IntelPlatformProtocolLib_DIR)\
+
+RapidStartPei_DEFINES=\
+ $(MY_DEFINES)\
+ /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=RapidStartPeiEntryPoint"\
+ /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \
+ /D __EDKII_GLUE_BASE_MEMORY_LIB__\
+ /D __EDKII_GLUE_PEI_DEBUG_LIB_REPORT_STATUS_CODE__ \
+ /D __EDKII_GLUE_PEI_REPORT_STATUS_CODE_LIB__ \
+ /D __EDKII_GLUE_PEI_SERVICES_LIB__ \
+ /D __EDKII_GLUE_PEI_MEMORY_ALLOCATION_LIB__ \
+ /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \
+ /D __EDKII_GLUE_PEI_HOB_LIB__ \
+!IF "$(iME_SUPPORT)"=="1"
+ /D ME_SUPPORT_FLAG\
+!ENDIF
+
+RapidStartPei_LIBS =\
+ $(EdkIIGlueBaseIoLibIntrinsic_LIB)\
+ $(EdkIIGlueBaseLib_LIB)\
+ $(EdkIIGlueBaseLibIA32_LIB)\
+ $(EdkIIGlueBasePrintLib_LIB)\
+ $(EdkIIGluePeiMemoryAllocationLib_LIB)\
+ $(EdkIIGluePeiDebugLibReportStatusCode_LIB)\
+ $(EdkIIGluePeiReportStatusCodeLib_LIB)\
+ $(EdkIIGluePeiServicesLib_LIB)\
+ $(EdkIIGlueBasePciLibPciExpress_LIB)\
+ $(EdkIIGlueBasePostCodeLibPort80_LIB)\
+ $(EDKFRAMEWORKPPILIB)\
+ $(PchPlatformPeiLib_LIB)\
+ $(IntelPchPpiLib_LIB)\
+ $(MeGuidLib_LIB)\
+ $(MeLibPpi_LIB)\
+ $(RapidStartPpiLib_LIB)\
+ $(RapidStartPeiLib_LIB)\
+ $(RapidStartCommonPeiLib_LIB)\
+ $(RapidStartGuidLib_LIB)\
+ $(EdkIIGluePeiHobLib_LIB)\
+ $(GfxDisplayLibPei_LIB)\
+ $(EdkIIGluePeiFirmwarePerformanceLib_LIB)\
+ $(INTEL_SA_PPI_LIB)\
+
+RapidStartPeiBin : $(RapidStartPei_LIBS) $(PEILIB)
+ $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS) \
+ /f $(BUILD_DIR)\RapidStartPei.mak all \
+ NAME=RapidStartPei \
+ MAKEFILE=$(BUILD_DIR)\RapidStartPei.mak \
+ GUID=53f019e9-bb0c-424b-870a-1faf10b1cb4c \
+ ENTRY_POINT=_ModuleEntryPoint \
+ "MY_INCLUDES = $(RapidStartPei_INCLUDES)" \
+ "MY_DEFINES = $(RapidStartPei_DEFINES)" \
+ TYPE=PEIM \
+ EDKIIModule=PEIM \
+ DEPEX1=$(RapidStartPei_DIR)\RapidStartPei.dxs \
+ DEPEX1_TYPE=EFI_SECTION_PEI_DEPEX \
+ COMPRESS=0
+#*************************************************************************
+#*************************************************************************
+#** **
+#** (C)Copyright 1985-2012, American Megatrends, Inc. **
+#** **
+#** All Rights Reserved. **
+#** **
+#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+#** **
+#** Phone: (770)-246-8600 **
+#** **
+#*************************************************************************
+#*************************************************************************
diff --git a/ReferenceCode/RapidStart/Pei/RapidStartPei.sdl b/ReferenceCode/RapidStart/Pei/RapidStartPei.sdl
new file mode 100644
index 0000000..008fedb
--- /dev/null
+++ b/ReferenceCode/RapidStart/Pei/RapidStartPei.sdl
@@ -0,0 +1,68 @@
+#*************************************************************************
+#*************************************************************************
+#** **
+#** (C)Copyright 1985-2011, American Megatrends, Inc. **
+#** **
+#** All Rights Reserved. **
+#** **
+#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+#** **
+#** Phone: (770)-246-8600 **
+#** **
+#*************************************************************************
+#*************************************************************************
+
+#*************************************************************************
+# $Header: /Alaska/SOURCE/Modules/Intel Fast Flash Standby/iRST_SharkBay/RapidStartPei/RapidStartPei.sdl 1 4/19/12 7:50a Yurenlai $
+#
+# $Revision: 1 $
+#
+# $Date: 4/19/12 7:50a $
+#*************************************************************************
+# Revision History
+# ----------------
+# $Log: /Alaska/SOURCE/Modules/Intel Fast Flash Standby/iRST_SharkBay/RapidStartPei/RapidStartPei.sdl $
+#
+# 1 4/19/12 7:50a Yurenlai
+# Initial check in.
+#
+#*************************************************************************
+TOKEN
+ Name = "RapidStartPei_SUPPORT"
+ Value = "1"
+ TokenType = Boolean
+ TargetEQU = Yes
+ TargetMAK = Yes
+ TargetH = Yes
+ Master = Yes
+ Help = "Main switch to enable iFFS support in PEI Phase"
+End
+
+MODULE
+ Help = "Includes RapidStartPei.mak to Project"
+ File = "RapidStartPei.mak"
+End
+
+PATH
+ Name = "RapidStartPei_DIR"
+ Help = "RapidStartPei dir"
+End
+
+ELINK
+ Name = "$(BUILD_DIR)\RapidStartPei.ffs"
+ Parent = "FV_BB"
+ InvokeOrder = AfterParent
+End
+#*************************************************************************
+#*************************************************************************
+#** **
+#** (C)Copyright 1985-2011, American Megatrends, Inc. **
+#** **
+#** All Rights Reserved. **
+#** **
+#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+#** **
+#** Phone: (770)-246-8600 **
+#** **
+#*************************************************************************
+#*************************************************************************