1 /** @file
2 
3   Copyright (c) 2004  - 2014, Intel Corporation. All rights reserved.<BR>
4 
5 
6   This program and the accompanying materials are licensed and made available under
7 
8   the terms and conditions of the BSD License that accompanies this distribution.
9 
10   The full text of the license may be found at
11 
12   http://opensource.org/licenses/bsd-license.php.
13 
14 
15 
16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 
18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 
20 
21 
22 
23 Module Name:
24 
25   AcpiPlatformHooks.c
26 
27 Abstract:
28 
29   ACPI Platform Driver Hooks
30 
31 --*/
32 
33 //
34 // Statements that include other files.
35 //
36 #include "AcpiPlatform.h"
37 #include "AcpiPlatformHooks.h"
38 #include "Platform.h"
39 
40 //
41 // Prototypes of the various hook functions.
42 //
43 #include "AcpiPlatformHooksLib.h"
AppendCpuMapTableEntry(IN EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE * AcpiLocalApic)44 
45 extern EFI_GLOBAL_NVS_AREA_PROTOCOL  mGlobalNvsArea;
46 extern SYSTEM_CONFIGURATION             mSystemConfiguration;
47 
48 ENHANCED_SPEEDSTEP_PROTOCOL             *mEistProtocol  = NULL;
49 
50 EFI_CPU_ID_MAP              mCpuApicIdAcpiIdMapTable[MAX_CPU_NUM];
51 
52 EFI_STATUS
53 AppendCpuMapTableEntry (
54   IN EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE   *AcpiLocalApic
55   )
56 {
57   BOOLEAN Added;
58   UINTN   Index;
59 
60   for (Index = 0; Index < MAX_CPU_NUM; Index++) {
61     if ((mCpuApicIdAcpiIdMapTable[Index].ApicId == AcpiLocalApic->ApicId) && mCpuApicIdAcpiIdMapTable[Index].Flags) {
62       return EFI_SUCCESS;
63     }
64   }
65 
66   Added = FALSE;
67   for (Index = 0; Index < MAX_CPU_NUM; Index++) {
68       if (!mCpuApicIdAcpiIdMapTable[Index].Flags) {
69         mCpuApicIdAcpiIdMapTable[Index].Flags           = 1;
70         mCpuApicIdAcpiIdMapTable[Index].ApicId          = AcpiLocalApic->ApicId;
71         mCpuApicIdAcpiIdMapTable[Index].AcpiProcessorId = AcpiLocalApic->AcpiProcessorId;
72       Added = TRUE;
ProcessorId2ApicId(UINT32 AcpiProcessorId)73       break;
74     }
75   }
76 
77   ASSERT (Added);
78   return EFI_SUCCESS;
79 }
80 
81 UINT32
82 ProcessorId2ApicId (
83   UINT32  AcpiProcessorId
84   )
85 {
86   UINTN Index;
87 
88   ASSERT (AcpiProcessorId < MAX_CPU_NUM);
89   for (Index = 0; Index < MAX_CPU_NUM; Index++) {
GetProcNumberInPackage(IN UINT8 Package)90     if (mCpuApicIdAcpiIdMapTable[Index].Flags && (mCpuApicIdAcpiIdMapTable[Index].AcpiProcessorId == AcpiProcessorId)) {
91       return mCpuApicIdAcpiIdMapTable[Index].ApicId;
92     }
93   }
94 
95   return (UINT32) -1;
96 }
97 
98 UINT8
99 GetProcNumberInPackage (
100   IN UINT8  Package
101   )
102 {
103   UINTN Index;
104   UINT8 Number;
105 
106   Number = 0;
107   for (Index = 0; Index < MAX_CPU_NUM; Index++) {
LocateCpuEistProtocol(IN UINT32 CpuIndex,OUT ENHANCED_SPEEDSTEP_PROTOCOL ** EistProtocol)108     if (mCpuApicIdAcpiIdMapTable[Index].Flags && (((mCpuApicIdAcpiIdMapTable[Index].ApicId >> 0x04) & 0x01) == Package)) {
109       Number++;
110     }
111   }
112 
113   return Number;
114 }
115 
116 EFI_STATUS
117 LocateCpuEistProtocol (
118   IN UINT32                           CpuIndex,
119   OUT ENHANCED_SPEEDSTEP_PROTOCOL     **EistProtocol
120   )
121 {
122   UINTN                       HandleCount;
123   EFI_HANDLE                  *HandleBuffer;
124   ENHANCED_SPEEDSTEP_PROTOCOL *EistProt;
125   UINTN                       Index;
126   UINT32                      ApicId;
127   EFI_STATUS                  Status;
128 
129   HandleCount = 0;
130   gBS->LocateHandleBuffer (
131          ByProtocol,
132          &gEnhancedSpeedstepProtocolGuid,
133          NULL,
134          &HandleCount,
135          &HandleBuffer
136          );
137 
138   Index     = 0;
139   EistProt  = NULL;
140   Status    = EFI_NOT_FOUND;
141   while (Index < HandleCount) {
142     gBS->HandleProtocol (
143            HandleBuffer[Index],
144            &gEnhancedSpeedstepProtocolGuid,
145           (VOID **) &EistProt
146            );
147     //
148     // Adjust the CpuIndex by +1 due to the AcpiProcessorId is 1 based.
149     //
150     ApicId = ProcessorId2ApicId (CpuIndex+1);
151     if (ApicId == (UINT32) -1) {
152       break;
153     }
154 
155     if (EistProt->ProcApicId == ApicId) {
156       Status = EFI_SUCCESS;
157       break;
158     }
159 
160     Index++;
161   }
162 
163   if (HandleBuffer != NULL) {
164     gBS->FreePool (HandleBuffer);
165   }
166 
167   if (!EFI_ERROR (Status)) {
PlatformHookInit(VOID)168     *EistProtocol = EistProt;
169   } else {
170     *EistProtocol = NULL;
171   }
172 
173   return Status;
174 }
175 
176 EFI_STATUS
177 PlatformHookInit (
178   VOID
179   )
180 {
181   EFI_STATUS  Status;
182 
183   Status = gBS->LocateProtocol (
184                   &gEnhancedSpeedstepProtocolGuid,
185                   NULL,
186                   (VOID **) &mEistProtocol
187                   );
188 
189   ASSERT_EFI_ERROR (Status);
190 
191   return Status;
192 }
193 
194 /**
195   Called for every ACPI table found in the BIOS flash.
196   Returns whether a table is active or not. Inactive tables
197   are not published in the ACPI table list.
198 
199   This hook can be used to implement optional SSDT tables or
200   enabling/disabling specific functionality (e.g. SPCR table)
201   based on a setup switch or platform preference. In case of
202   optional SSDT tables,the platform flash will include all the
203   SSDT tables but will return EFI_SUCCESS only for those tables
AcpiPlatformHooksIsActiveTable(IN OUT EFI_ACPI_COMMON_HEADER * Table)204   that need to be published.
205 
206   @param[in]  *Table         Pointer to the active table.
207 
208   @retval  EFI_SUCCESS       if the table is active.
209   @retval  EFI_UNSUPPORTED   if the table is not active.
210 
211 **/
212 EFI_STATUS
213 AcpiPlatformHooksIsActiveTable (
214   IN OUT EFI_ACPI_COMMON_HEADER     *Table
215   )
216 {
217   EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
218 
219   TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
220 
221   if (TableHeader->Signature == EFI_ACPI_2_0_STATIC_RESOURCE_AFFINITY_TABLE_SIGNATURE) {
222 
223   }
224 
225   if ((mSystemConfiguration.ENDBG2 == 0) && (CompareMem (&TableHeader->OemTableId, "INTLDBG2", 8) == 0)) {
226     return EFI_UNSUPPORTED;
227   }
228   return EFI_SUCCESS;
229 }
230 
PatchGv3SsdtTable(IN OUT EFI_ACPI_DESCRIPTION_HEADER * TableHeader)231 /**
232     Update the GV3 SSDT table.
233 
234     @param[in][out]  *TableHeader   The table to be set.
235 
236     @retval  EFI_SUCCESS            Returns Success.
237 
238 **/
239 EFI_STATUS
240 PatchGv3SsdtTable (
241   IN OUT   EFI_ACPI_DESCRIPTION_HEADER  *TableHeader
242   )
243 {
244   EFI_STATUS                  Status;
245   UINT8                       *CurrPtr;
246   UINT8                       *SsdtPointer;
247   UINT32                      Signature;
248   UINT32                      CpuFixes;
249   UINT32                      NpssFixes;
250   UINT32                      SpssFixes;
251   UINT32                      CpuIndex;
252   UINT32                      PackageSize;
253   UINT32                      NewPackageSize;
254   UINT32                      AdjustSize;
255   UINTN                       EntryIndex;
256   UINTN                       TableIndex;
257   EFI_ACPI_NAME_COMMAND       *PssTable;
258   EFI_PSS_PACKAGE             *PssTableItemPtr;
259   ENHANCED_SPEEDSTEP_PROTOCOL *EistProt;
260   EIST_INFORMATION            *EistInfo;
261   EFI_ACPI_CPU_PSS_STATE      *PssState;
262   EFI_ACPI_NAMEPACK_DWORD     *NamePtr;
263   //
264   // Loop through the ASL looking for values that we must fix up.
265   //
266   NpssFixes = 0;
267   SpssFixes = 0;
268   CpuFixes  = 0;
269   CpuIndex  = 0;
270   CurrPtr   = (UINT8 *) TableHeader;
271 
272   EistProt  = NULL;
273   for (SsdtPointer = CurrPtr; SsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); SsdtPointer++) {
274     Signature = *(UINT32 *) SsdtPointer;
275     switch (Signature) {
276 
277     case SIGNATURE_32 ('_', 'P', 'R', '_'):
278       //
279       // _CPUX ('0' to '0xF')
280       //
281       CpuIndex = *(SsdtPointer + 7);
282       if (CpuIndex >= '0' && CpuIndex <= '9') {
283         CpuIndex -= '0';
284       } else {
285         if (CpuIndex > '9') {
286           CpuIndex -= '7';
287         }
288       }
289 
290       CpuFixes++;
291       LocateCpuEistProtocol (CpuIndex, &EistProt);
292       break;
293 
294     case SIGNATURE_32 ('D', 'O', 'M', 'N'):
295 
296       NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer);
297       if (NamePtr->StartByte != AML_NAME_OP) {
298         continue;
299       }
300 
301       if (NamePtr->Size != AML_NAME_DWORD_SIZE) {
302         continue;
303       }
304 
305       NamePtr->Value = 0;
306 
307         if (mCpuApicIdAcpiIdMapTable[CpuIndex].Flags) {
308           NamePtr->Value = (mCpuApicIdAcpiIdMapTable[CpuIndex].ApicId >> 0x04) & 0x01;
309       }
310       break;
311 
312     case SIGNATURE_32 ('N', 'C', 'P', 'U'):
313 
314       NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer);
315       if (NamePtr->StartByte != AML_NAME_OP) {
316         continue;
317       }
318 
319       if (NamePtr->Size != AML_NAME_DWORD_SIZE) {
320         continue;
321       }
322 
323         NamePtr->Value = 0;
324         if (mCpuApicIdAcpiIdMapTable[CpuIndex].Flags) {
325           NamePtr->Value = GetProcNumberInPackage ((mCpuApicIdAcpiIdMapTable[CpuIndex].ApicId >> 0x04) & 0x01);
326       }
327       break;
328 
329     case SIGNATURE_32 ('N', 'P', 'S', 'S'):
330     case SIGNATURE_32 ('S', 'P', 'S', 'S'):
331       if (EistProt == NULL) {
332         continue;
333       }
334 
335       PssTable = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer);
336       if (PssTable->StartByte != AML_NAME_OP) {
337         continue;
338       }
339 
340       Status      = EistProt->GetEistTable (EistProt, &EistInfo, (VOID **) &PssState);
341 
342       AdjustSize  = PssTable->NumEntries * sizeof (EFI_PSS_PACKAGE);
343       AdjustSize -= EistInfo->NumStates * sizeof (EFI_PSS_PACKAGE);
344       PackageSize     = (PssTable->Size & 0xF) + ((PssTable->Size & 0xFF00) >> 4);
345       NewPackageSize  = PackageSize - AdjustSize;
346       PssTable->Size  = (UINT16) ((NewPackageSize & 0xF) + ((NewPackageSize & 0x0FF0) << 4));
347 
348       //
349       // Set most significant two bits of byte zero to 01, meaning two bytes used.
350       //
351       PssTable->Size |= 0x40;
352 
353       //
354       // Set unused table to Noop Code.
355       //
356       SetMem( (UINT8 *) PssTable + NewPackageSize + AML_NAME_PREFIX_SIZE, AdjustSize, AML_NOOP_OP);
357       PssTable->NumEntries  = (UINT8) EistInfo->NumStates;
358       PssTableItemPtr       = (EFI_PSS_PACKAGE *) ((UINT8 *) PssTable + sizeof (EFI_ACPI_NAME_COMMAND));
359 
360       //
361       // Update the size.
362       //
363       for (TableIndex = 0; TableIndex < EistInfo->NumStates; TableIndex++) {
364         EntryIndex                = EistInfo->NumStates - TableIndex - 1;
365         PssTableItemPtr->CoreFreq = PssState[EntryIndex].CoreFrequency * PssState[EntryIndex].Control;
366         PssTableItemPtr->Power    = PssState[EntryIndex].Power * 1000;
367         if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) {
368           PssTableItemPtr->BMLatency    = PssState[EntryIndex].BusMasterLatency;
369           PssTableItemPtr->TransLatency = PssState[EntryIndex].TransitionLatency;
370         } else {
371           //
372           // This method should be supported by SMM PPM Handler.
373           //
374           PssTableItemPtr->BMLatency    = PssState[EntryIndex].BusMasterLatency * 2;
375           PssTableItemPtr->TransLatency = PssState[EntryIndex].TransitionLatency * 10;
376         }
377 
378         PssTableItemPtr->Control  = PssState[EntryIndex].Control;
379         PssTableItemPtr->Status   = PssState[EntryIndex].Status;
380         PssTableItemPtr++;
381       }
382 
383       if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) {
384         NpssFixes++;
385       } else {
386         SpssFixes++;
387       }
388 
389       SsdtPointer = (UINT8 *) PssTable + PackageSize;
390       break;
391     }
392   }
393 
394   //
395   // N fixes together currently.
396   //
397   ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM);
398   ASSERT (SpssFixes == NpssFixes);
399   ASSERT (CpuFixes >= SpssFixes);
400 
401   return EFI_SUCCESS;
402 }
403 
PatchDsdtTable(IN OUT EFI_ACPI_DESCRIPTION_HEADER * TableHeader)404 /**
405     Update the DSDT table.
406 
407     @param[in][out]  *TableHeader   The table to be set.
408 
409     @retval  EFI_SUCCESS            Returns EFI_SUCCESS.
410 
411 **/
412 EFI_STATUS
413 PatchDsdtTable (
414   IN OUT   EFI_ACPI_DESCRIPTION_HEADER  *TableHeader
415   )
416 {
417 
418   UINT8                              *CurrPtr;
419   UINT8                              *DsdtPointer;
420   UINT32                             *Signature;
421   UINT8                              *EndPtr;
422   UINT8   *Operation;
423   UINT32  *Address;
424   UINT16  *Size;
425 
426   //
427   // Fix PCI32 resource "FIX0" -- PSYS system status area
428   //
429   CurrPtr = (UINT8*) &((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)[0];
430   EndPtr = (UINT8*) TableHeader;
431   EndPtr = EndPtr + TableHeader->Length;
432   while (CurrPtr < (EndPtr-2)) {
433     //
434     // Removed the _S3 tag to indicate that we do not support S3. The 4th byte is blank space
435     // since there are only 3 char "_S3".
436     //
437     if (mSystemConfiguration.AcpiSuspendState == 0) {
438       //
439       // For iasl compiler version 20061109.
440       //
441       if ((CurrPtr[0] == '_') && (CurrPtr[1] == 'S') && (CurrPtr[2] == '3') && (CurrPtr[3] == '_')) {
442         break;
443       }
444       //
445       // For iasl compiler version 20040527.
446       //
447       if ((CurrPtr[0] == '\\') && (CurrPtr[1] == '_') && (CurrPtr[2] == 'S') && (CurrPtr[3] == '3')) {
448         break;
449       }
450     }
451     CurrPtr++;
452   }
453   CurrPtr = (UINT8*) &((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)[0];
454   EndPtr = (UINT8*) TableHeader;
455   EndPtr = EndPtr + TableHeader->Length;
456   while (CurrPtr < (EndPtr-2)) {
457     //
458     // For mipi dsi port select _DEP.
459     //
460     if (mSystemConfiguration.MipiDsi== 1) {
461       //
462       // For iasl compiler version 20061109.
463       //
464       if ((CurrPtr[0] == 'N') && (CurrPtr[1] == 'D') && (CurrPtr[2] == 'E') && (CurrPtr[3] == 'P')) {
465         CurrPtr[0] = '_';
466         break;
467       }
468 
469     } else {
470       if ((CurrPtr[0] == 'P') && (CurrPtr[1] == 'D') && (CurrPtr[2] == 'E') && (CurrPtr[3] == 'P')) {
471         CurrPtr[0] = '_';
472         break;
473       }
474 
475     }
476     CurrPtr++;
477   }
478   //
479   // Loop through the ASL looking for values that we must fix up.
480   //
481   CurrPtr = (UINT8 *) TableHeader;
482   for (DsdtPointer = CurrPtr; DsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); DsdtPointer++) {
483     Signature = (UINT32 *) DsdtPointer;
484 
485     switch (*Signature) {
486     //
487     // GNVS operation region.
488     //
489     case (SIGNATURE_32 ('G', 'N', 'V', 'S')):
490       //
491       // Conditional match.  For Region Objects, the Operator will always be the
492       // byte immediately before the specific name.  Therefore, subtract 1 to check
493       // the Operator.
494       //
495       Operation = DsdtPointer - 1;
496       if (*Operation == AML_OPREGION_OP) {
497         Address   = (UINT32 *) (DsdtPointer + 6);
498         *Address  = (UINT32) (UINTN) mGlobalNvsArea.Area;
499         Size      = (UINT16 *) (DsdtPointer + 11);
500         *Size     = sizeof (EFI_GLOBAL_NVS_AREA);
501       }
502       break;
503     default:
504       break;
505     }
506   }
507   return EFI_SUCCESS;
508 }
509 
510