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 - 2016, 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 
     47 GLOBAL_REMOVE_IF_UNREFERENCED
     48 ACPI_VARIABLE_SET_COMPATIBILITY               *mAcpiVariableSetCompatibility = NULL;
     49 
     50 /**
     51   Allocate memory below 4G memory address.
     52 
     53   This function allocates memory below 4G memory address.
     54 
     55   @param  MemoryType   Memory type of memory to allocate.
     56   @param  Size         Size of memory to allocate.
     57 
     58   @return Allocated address for output.
     59 
     60 **/
     61 VOID*
     62 AllocateMemoryBelow4G (
     63   IN EFI_MEMORY_TYPE    MemoryType,
     64   IN UINTN              Size
     65   );
     66 
     67 /**
     68   Hook point for AcpiVariableThunkPlatform for S3Ready.
     69 
     70 **/
     71 VOID
     72 S3ReadyThunkPlatform (
     73   VOID
     74   )
     75 {
     76   EFI_PHYSICAL_ADDRESS                          AcpiMemoryBase;
     77   UINT32                                        AcpiMemorySize;
     78   EFI_PEI_HOB_POINTERS                          Hob;
     79   UINT64                                        MemoryLength;
     80 
     81   DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n"));
     82 
     83   if (mAcpiVariableSetCompatibility == NULL) {
     84     return;
     85   }
     86 
     87   //
     88   // Allocate ACPI reserved memory under 4G
     89   //
     90   AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3AcpiReservedMemorySize));
     91   ASSERT (AcpiMemoryBase != 0);
     92   AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize);
     93 
     94   //
     95   // Calculate the system memory length by memory hobs
     96   //
     97   MemoryLength  = 0x100000;
     98   Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
     99   ASSERT (Hob.Raw != NULL);
    100   while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) {
    101     if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
    102       //
    103       // Skip the memory region below 1MB
    104       //
    105       if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {
    106         MemoryLength += Hob.ResourceDescriptor->ResourceLength;
    107       }
    108     }
    109     Hob.Raw = GET_NEXT_HOB (Hob);
    110     Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
    111   }
    112 
    113   mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase;
    114   mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize;
    115   mAcpiVariableSetCompatibility->SystemMemoryLength     = MemoryLength;
    116 
    117   DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase));
    118   DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize));
    119   DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength));
    120 
    121   return ;
    122 }
    123 
    124 /**
    125   Register callback function upon VariableLockProtocol
    126   to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it.
    127 
    128   @param[in] Event    Event whose notification function is being invoked.
    129   @param[in] Context  Pointer to the notification function's context.
    130 **/
    131 VOID
    132 EFIAPI
    133 VariableLockAcpiGlobalVariable (
    134   IN  EFI_EVENT                             Event,
    135   IN  VOID                                  *Context
    136   )
    137 {
    138   EFI_STATUS                    Status;
    139   EDKII_VARIABLE_LOCK_PROTOCOL  *VariableLock;
    140   //
    141   // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists
    142   //
    143   Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
    144   if (!EFI_ERROR (Status)) {
    145     Status = VariableLock->RequestToLock (VariableLock, ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid);
    146     ASSERT_EFI_ERROR (Status);
    147   }
    148 }
    149 
    150 /**
    151   Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.
    152 **/
    153 VOID
    154 InstallAcpiS3SaveThunk (
    155   VOID
    156   )
    157 {
    158   EFI_STATUS                           Status;
    159   FRAMEWORK_EFI_MP_SERVICES_PROTOCOL   *FrameworkMpService;
    160   UINTN                                VarSize;
    161   VOID                                 *Registration;
    162 
    163   Status = gBS->LocateProtocol (
    164                   &gFrameworkEfiMpServiceProtocolGuid,
    165                   NULL,
    166                   (VOID**) &FrameworkMpService
    167                   );
    168   if (!EFI_ERROR (Status)) {
    169     //
    170     // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set
    171     // should be produced by CPU driver.
    172     //
    173     VarSize = sizeof (mAcpiVariableSetCompatibility);
    174     Status = gRT->GetVariable (
    175                     ACPI_GLOBAL_VARIABLE,
    176                     &gEfiAcpiVariableCompatiblityGuid,
    177                     NULL,
    178                     &VarSize,
    179                     &mAcpiVariableSetCompatibility
    180                     );
    181     if (EFI_ERROR (Status) || (VarSize != sizeof (mAcpiVariableSetCompatibility))) {
    182       DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility was not saved by CPU driver correctly. OS S3 may fail!\n"));
    183       mAcpiVariableSetCompatibility = NULL;
    184     }
    185   } else {
    186     //
    187     // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform
    188     // driver need this variable. ACPI_GLOBAL_VARIABLE variable is not used in runtime phase,
    189     // so RT attribute is not needed for it.
    190     //
    191     mAcpiVariableSetCompatibility = AllocateMemoryBelow4G (EfiACPIMemoryNVS, sizeof(ACPI_VARIABLE_SET_COMPATIBILITY));
    192     Status = gRT->SetVariable (
    193                     ACPI_GLOBAL_VARIABLE,
    194                     &gEfiAcpiVariableCompatiblityGuid,
    195                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    196                     sizeof(mAcpiVariableSetCompatibility),
    197                     &mAcpiVariableSetCompatibility
    198                     );
    199     if (!EFI_ERROR (Status)) {
    200       //
    201       // Register callback function upon VariableLockProtocol
    202       // to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it.
    203       //
    204       EfiCreateProtocolNotifyEvent (
    205         &gEdkiiVariableLockProtocolGuid,
    206         TPL_CALLBACK,
    207         VariableLockAcpiGlobalVariable,
    208         NULL,
    209         &Registration
    210         );
    211     } else {
    212       DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility cannot be saved: %r. OS S3 may fail!\n", Status));
    213       gBS->FreePages (
    214              (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiVariableSetCompatibility,
    215              EFI_SIZE_TO_PAGES (sizeof (ACPI_VARIABLE_SET_COMPATIBILITY))
    216              );
    217       mAcpiVariableSetCompatibility = NULL;
    218     }
    219   }
    220 
    221   DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility));
    222 }
    223