Ppm.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /** @file
  2. Processor power management initialization code.
  3. Copyright (c) 2013-2016 Intel Corporation.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "SmmPowerManagement.h"
  7. //
  8. // Global variables
  9. //
  10. extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdt;
  11. extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable;
  12. extern EFI_GUID gPowerManagementAcpiTableStorageGuid;
  13. /**
  14. This function is the entry of processor power management initialization code.
  15. It initializes the processor's power management features based on the user
  16. configurations and hardware capabilities.
  17. **/
  18. VOID
  19. PpmInit (
  20. VOID
  21. )
  22. {
  23. //
  24. // Processor Power Management Flags
  25. //
  26. mGlobalNvsAreaPtr->Cfgd = PcdGet32(PcdPpmFlags);
  27. //
  28. // Patch and publish power management related acpi tables
  29. //
  30. PpmPatchAndPublishAcpiTables();
  31. }
  32. /**
  33. This function is to patch and publish power management related acpi tables.
  34. **/
  35. VOID
  36. PpmPatchAndPublishAcpiTables (
  37. VOID
  38. )
  39. {
  40. //
  41. // Patch FADT table to enable C2,C3
  42. //
  43. PpmPatchFadtTable();
  44. //
  45. // Load all the power management acpi tables and patch IST table
  46. //
  47. PpmLoadAndPatchPMTables();
  48. }
  49. /**
  50. This function is to patch PLvl2Lat and PLvl3Lat to enable C2, C3 support in OS.
  51. **/
  52. VOID
  53. PpmPatchFadtTable (
  54. VOID
  55. )
  56. {
  57. EFI_STATUS Status;
  58. EFI_ACPI_DESCRIPTION_HEADER *Table;
  59. EFI_ACPI_SDT_HEADER *CurrentTable;
  60. EFI_ACPI_TABLE_VERSION Version;
  61. UINTN Index;
  62. UINTN Handle;
  63. //
  64. // Scan all the acpi tables to find FADT 2.0
  65. //
  66. Index = 0;
  67. do {
  68. Status = mAcpiSdt->GetAcpiTable (
  69. Index,
  70. &CurrentTable,
  71. &Version,
  72. &Handle
  73. );
  74. if (Status == EFI_NOT_FOUND) {
  75. break;
  76. }
  77. ASSERT_EFI_ERROR (Status);
  78. Index++;
  79. } while (CurrentTable->Signature != EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE || CurrentTable->Revision != 0x03);
  80. ASSERT (CurrentTable->Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
  81. Table = NULL;
  82. Status = gBS->AllocatePool (EfiBootServicesData, CurrentTable->Length, (VOID **) &Table);
  83. ASSERT (Table != NULL);
  84. CopyMem (Table, CurrentTable, CurrentTable->Length);
  85. //
  86. // Update the ACPI table and recalculate checksum
  87. //
  88. Status = mAcpiTable->UninstallAcpiTable (mAcpiTable, Handle);
  89. if (EFI_ERROR (Status)) {
  90. //
  91. // Should not get an error here ever, but abort if we do.
  92. //
  93. return ;
  94. }
  95. //
  96. // Update the check sum
  97. // It needs to be zeroed before the checksum calculation
  98. //
  99. ((EFI_ACPI_SDT_HEADER *)Table)->Checksum = 0;
  100. ((EFI_ACPI_SDT_HEADER *)Table)->Checksum =
  101. CalculateCheckSum8 ((VOID *)Table, Table->Length);
  102. //
  103. // Add the table
  104. //
  105. Status = mAcpiTable->InstallAcpiTable (
  106. mAcpiTable,
  107. Table,
  108. Table->Length,
  109. &Handle
  110. );
  111. ASSERT_EFI_ERROR (Status);
  112. gBS->FreePool (Table);
  113. }
  114. VOID
  115. SsdtTableUpdate (
  116. IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader
  117. )
  118. /*++
  119. Routine Description:
  120. Update the SSDT table
  121. Arguments:
  122. Table - The SSDT table to be patched
  123. Returns:
  124. None
  125. --*/
  126. {
  127. UINT8 *CurrPtr;
  128. UINT8 *SsdtPointer;
  129. UINT32 *Signature;
  130. //
  131. // Loop through the ASL looking for values that we must fix up.
  132. //
  133. CurrPtr = (UINT8 *) TableHeader;
  134. for (SsdtPointer = CurrPtr;
  135. SsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length);
  136. SsdtPointer++
  137. )
  138. {
  139. Signature = (UINT32 *) SsdtPointer;
  140. if ((*Signature) == SIGNATURE_32 ('P', 'M', 'B', 'A')) {
  141. switch (*(Signature+1)) {
  142. case (SIGNATURE_32 ('L', 'V', 'L', '0')):
  143. Signature[0] = PcdGet16(PcdPmbaIoBaseAddress);
  144. Signature[1] = 0;
  145. break;
  146. case (SIGNATURE_32 ('L', 'V', 'L', '2')):
  147. Signature[0] = PcdGet16(PcdPmbaIoLVL2);
  148. Signature[1] = 0;
  149. break;
  150. }
  151. }
  152. }
  153. }
  154. EFI_STATUS
  155. LocateSupportProtocol (
  156. IN EFI_GUID *Protocol,
  157. OUT VOID **Instance,
  158. IN UINT32 Type
  159. )
  160. /*++
  161. Routine Description:
  162. Locate the first instance of a protocol. If the protocol requested is an
  163. FV protocol, then it will return the first FV that contains the ACPI table
  164. storage file.
  165. Arguments:
  166. Protocol The protocol to find.
  167. Instance Return pointer to the first instance of the protocol
  168. Returns:
  169. EFI_SUCCESS The function completed successfully.
  170. EFI_NOT_FOUND The protocol could not be located.
  171. EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
  172. --*/
  173. {
  174. EFI_STATUS Status;
  175. EFI_HANDLE *HandleBuffer;
  176. UINTN NumberOfHandles;
  177. EFI_FV_FILETYPE FileType;
  178. UINT32 FvStatus;
  179. EFI_FV_FILE_ATTRIBUTES Attributes;
  180. UINTN Size;
  181. UINTN i;
  182. FvStatus = 0;
  183. //
  184. // Locate protocol.
  185. //
  186. Status = gBS->LocateHandleBuffer (
  187. ByProtocol,
  188. Protocol,
  189. NULL,
  190. &NumberOfHandles,
  191. &HandleBuffer
  192. );
  193. if (EFI_ERROR (Status)) {
  194. //
  195. // Defined errors at this time are not found and out of resources.
  196. //
  197. return Status;
  198. }
  199. //
  200. // Looking for FV with ACPI storage file
  201. //
  202. for (i = 0; i < NumberOfHandles; i++) {
  203. //
  204. // Get the protocol on this handle
  205. // This should not fail because of LocateHandleBuffer
  206. //
  207. Status = gBS->HandleProtocol (
  208. HandleBuffer[i],
  209. Protocol,
  210. Instance
  211. );
  212. ASSERT_EFI_ERROR (Status);
  213. if (!Type) {
  214. //
  215. // Not looking for the FV protocol, so find the first instance of the
  216. // protocol. There should not be any errors because our handle buffer
  217. // should always contain at least one or LocateHandleBuffer would have
  218. // returned not found.
  219. //
  220. break;
  221. }
  222. //
  223. // See if it has the ACPI storage file
  224. //
  225. Status = ((EFI_FIRMWARE_VOLUME2_PROTOCOL*) (*Instance))->ReadFile (*Instance,
  226. &gPowerManagementAcpiTableStorageGuid,
  227. NULL,
  228. &Size,
  229. &FileType,
  230. &Attributes,
  231. &FvStatus
  232. );
  233. //
  234. // If we found it, then we are done
  235. //
  236. if (Status == EFI_SUCCESS) {
  237. break;
  238. }
  239. }
  240. //
  241. // Our exit status is determined by the success of the previous operations
  242. // If the protocol was found, Instance already points to it.
  243. //
  244. //
  245. // Free any allocated buffers
  246. //
  247. gBS->FreePool (HandleBuffer);
  248. return Status;
  249. }
  250. /**
  251. This function is to load all the power management acpi tables and patch IST table.
  252. **/
  253. VOID
  254. PpmLoadAndPatchPMTables (
  255. VOID
  256. )
  257. {
  258. EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
  259. EFI_STATUS Status;
  260. INTN Instance;
  261. EFI_ACPI_COMMON_HEADER *CurrentTable;
  262. UINTN TableHandle;
  263. UINT32 FvStatus;
  264. UINTN Size;
  265. Status = LocateSupportProtocol (&gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol, 1);
  266. if (EFI_ERROR (Status)) {
  267. return;
  268. }
  269. //
  270. // Read tables from the storage file.
  271. //
  272. Instance = 0;
  273. CurrentTable = NULL;
  274. while (Status == EFI_SUCCESS) {
  275. Status = FwVol->ReadSection (
  276. FwVol,
  277. &gPowerManagementAcpiTableStorageGuid,
  278. EFI_SECTION_RAW,
  279. Instance,
  280. (VOID**)&CurrentTable,
  281. &Size,
  282. &FvStatus
  283. );
  284. if (!EFI_ERROR(Status)) {
  285. SsdtTableUpdate ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable);
  286. //
  287. // Update the check sum
  288. // It needs to be zeroed before the checksum calculation
  289. //
  290. ((EFI_ACPI_SDT_HEADER *)CurrentTable)->Checksum = 0;
  291. ((EFI_ACPI_SDT_HEADER *)CurrentTable)->Checksum = (UINT8)
  292. CalculateCheckSum8 ((VOID *)CurrentTable, CurrentTable->Length);
  293. //
  294. // Add the table
  295. //
  296. TableHandle = 0;
  297. Status = mAcpiTable->InstallAcpiTable (
  298. mAcpiTable,
  299. CurrentTable,
  300. CurrentTable->Length,
  301. &TableHandle
  302. );
  303. ASSERT_EFI_ERROR (Status);
  304. //
  305. // Increment the instance
  306. //
  307. Instance++;
  308. CurrentTable = NULL;
  309. }
  310. }
  311. }