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