1 /** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 9 The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php. 13 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 21 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" 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; 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++) { 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++) { 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)) { 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 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 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 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