Home | History | Annotate | Download | only in AcpiS3SaveDxe
      1 /** @file
      2   This is an implementation of the AcpiVariable platform field for ECP platform.
      3 
      4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions
      8 of the BSD License which accompanies this distribution.  The
      9 full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 ==
     16 
     17 typedef struct {
     18   EFI_PHYSICAL_ADDRESS  AcpiReservedMemoryBase;  <<===
     19   UINT32                AcpiReservedMemorySize;  <<===
     20   EFI_PHYSICAL_ADDRESS  S3ReservedLowMemoryBase;
     21   EFI_PHYSICAL_ADDRESS  AcpiBootScriptTable;
     22   EFI_PHYSICAL_ADDRESS  RuntimeScriptTableBase;
     23   EFI_PHYSICAL_ADDRESS  AcpiFacsTable;
     24   UINT64                SystemMemoryLength;      <<===
     25   ACPI_CPU_DATA_COMPATIBILITY         AcpiCpuData;
     26   EFI_PHYSICAL_ADDRESS  VideoOpromAddress;
     27   UINT32                VideoOpromSize;
     28   EFI_PHYSICAL_ADDRESS  S3DebugBufferAddress;
     29   EFI_PHYSICAL_ADDRESS  S3ResumeNvsEntryPoint;
     30 } ACPI_VARIABLE_SET_COMPATIBILITY;
     31 
     32 **/
     33 
     34 #include <FrameworkDxe.h>
     35 #include <Library/BaseLib.h>
     36 #include <Library/BaseMemoryLib.h>
     37 #include <Library/UefiBootServicesTableLib.h>
     38 #include <Library/UefiRuntimeServicesTableLib.h>
     39 #include <Library/HobLib.h>
     40 #include <Library/PcdLib.h>
     41 #include <Library/DebugLib.h>
     42 #include <Library/UefiLib.h>
     43 #include <Protocol/FrameworkMpService.h>
     44 #include <Protocol/VariableLock.h>
     45 #include <Guid/AcpiVariableCompatibility.h>
     46 #include <Guid/AcpiS3Context.h>
     47 
     48 GLOBAL_REMOVE_IF_UNREFERENCED
     49 ACPI_VARIABLE_SET_COMPATIBILITY               *mAcpiVariableSetCompatibility = NULL;
     50 
     51 /**
     52   Allocate memory below 4G memory address.
     53 
     54   This function allocates memory below 4G memory address.
     55 
     56   @param  MemoryType   Memory type of memory to allocate.
     57   @param  Size         Size of memory to allocate.
     58 
     59   @return Allocated address for output.
     60 
     61 **/
     62 VOID*
     63 AllocateMemoryBelow4G (
     64   IN EFI_MEMORY_TYPE    MemoryType,
     65   IN UINTN              Size
     66   );
     67 
     68 /**
     69   Hook point for AcpiVariableThunkPlatform for S3Ready.
     70 
     71   @param AcpiS3Context   ACPI s3 context
     72 **/
     73 VOID
     74 S3ReadyThunkPlatform (
     75   IN ACPI_S3_CONTEXT      *AcpiS3Context
     76   )
     77 {
     78   EFI_PHYSICAL_ADDRESS                          AcpiMemoryBase;
     79   UINT32                                        AcpiMemorySize;
     80   EFI_PEI_HOB_POINTERS                          Hob;
     81   UINT64                                        MemoryLength;
     82 
     83   DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n"));
     84 
     85   if (mAcpiVariableSetCompatibility == NULL) {
     86     return;
     87   }
     88 
     89   //
     90   // Allocate ACPI reserved memory under 4G
     91   //
     92   AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3AcpiReservedMemorySize));
     93   ASSERT (AcpiMemoryBase != 0);
     94   AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize);
     95 
     96   //
     97   // Calculate the system memory length by memory hobs
     98   //
     99   MemoryLength  = 0x100000;
    100   Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
    101   ASSERT (Hob.Raw != NULL);
    102   while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) {
    103     if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
    104       //
    105       // Skip the memory region below 1MB
    106       //
    107       if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {
    108         MemoryLength += Hob.ResourceDescriptor->ResourceLength;
    109       }
    110     }
    111     Hob.Raw = GET_NEXT_HOB (Hob);
    112     Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
    113   }
    114 
    115   mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase;
    116   mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize;
    117   mAcpiVariableSetCompatibility->SystemMemoryLength     = MemoryLength;
    118 
    119   DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase));
    120   DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize));
    121   DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength));
    122 
    123   return ;
    124 }
    125 
    126 /**
    127   Register callback function upon VariableLockProtocol
    128   to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it.
    129 
    130   @param[in] Event    Event whose notification function is being invoked.
    131   @param[in] Context  Pointer to the notification function's context.
    132 **/
    133 VOID
    134 EFIAPI
    135 VariableLockAcpiGlobalVariable (
    136   IN  EFI_EVENT                             Event,
    137   IN  VOID                                  *Context
    138   )
    139 {
    140   EFI_STATUS                    Status;
    141   EDKII_VARIABLE_LOCK_PROTOCOL  *VariableLock;
    142   //
    143   // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists
    144   //
    145   Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
    146   if (!EFI_ERROR (Status)) {
    147     Status = VariableLock->RequestToLock (VariableLock, ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid);
    148     ASSERT_EFI_ERROR (Status);
    149   }
    150 }
    151 
    152 /**
    153   Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.
    154 **/
    155 VOID
    156 InstallAcpiS3SaveThunk (
    157   VOID
    158   )
    159 {
    160   EFI_STATUS                           Status;
    161   FRAMEWORK_EFI_MP_SERVICES_PROTOCOL   *FrameworkMpService;
    162   UINTN                                VarSize;
    163   VOID                                 *Registration;
    164 
    165   Status = gBS->LocateProtocol (
    166                   &gFrameworkEfiMpServiceProtocolGuid,
    167                   NULL,
    168                   (VOID**) &FrameworkMpService
    169                   );
    170   if (!EFI_ERROR (Status)) {
    171     //
    172     // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set
    173     // should be produced by CPU driver.
    174     //
    175     VarSize = sizeof (mAcpiVariableSetCompatibility);
    176     Status = gRT->GetVariable (
    177                     ACPI_GLOBAL_VARIABLE,
    178                     &gEfiAcpiVariableCompatiblityGuid,
    179                     NULL,
    180                     &VarSize,
    181                     &mAcpiVariableSetCompatibility
    182                     );
    183     if (EFI_ERROR (Status) || (VarSize != sizeof (mAcpiVariableSetCompatibility))) {
    184       DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility was not saved by CPU driver correctly. OS S3 may fail!\n"));
    185       mAcpiVariableSetCompatibility = NULL;
    186     }
    187   } else {
    188     //
    189     // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform
    190     // driver need this variable. ACPI_GLOBAL_VARIABLE variable is not used in runtime phase,
    191     // so RT attribute is not needed for it.
    192     //
    193     mAcpiVariableSetCompatibility = AllocateMemoryBelow4G (EfiACPIMemoryNVS, sizeof(ACPI_VARIABLE_SET_COMPATIBILITY));
    194     Status = gRT->SetVariable (
    195                     ACPI_GLOBAL_VARIABLE,
    196                     &gEfiAcpiVariableCompatiblityGuid,
    197                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    198                     sizeof(mAcpiVariableSetCompatibility),
    199                     &mAcpiVariableSetCompatibility
    200                     );
    201     if (!EFI_ERROR (Status)) {
    202       //
    203       // Register callback function upon VariableLockProtocol
    204       // to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it.
    205       //
    206       EfiCreateProtocolNotifyEvent (
    207         &gEdkiiVariableLockProtocolGuid,
    208         TPL_CALLBACK,
    209         VariableLockAcpiGlobalVariable,
    210         NULL,
    211         &Registration
    212         );
    213     } else {
    214       DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility cannot be saved: %r. OS S3 may fail!\n", Status));
    215       gBS->FreePages (
    216              (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiVariableSetCompatibility,
    217              EFI_SIZE_TO_PAGES (sizeof (ACPI_VARIABLE_SET_COMPATIBILITY))
    218              );
    219       mAcpiVariableSetCompatibility = NULL;
    220     }
    221   }
    222 
    223   DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility));
    224 }
    225