1/** @file
2  This is an implementation of the AcpiVariable platform field for ECP platform.
3
4Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5
6This program and the accompanying materials
7are licensed and made available under the terms and conditions
8of the BSD License which accompanies this distribution.  The
9full text of the license may be found at
10http://opensource.org/licenses/bsd-license.php
11
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15==
16
17typedef 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
48GLOBAL_REMOVE_IF_UNREFERENCED
49ACPI_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**/
62VOID*
63AllocateMemoryBelow4G (
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**/
73VOID
74S3ReadyThunkPlatform (
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**/
133VOID
134EFIAPI
135VariableLockAcpiGlobalVariable (
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**/
155VOID
156InstallAcpiS3SaveThunk (
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