TdxAcpiTable.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /** @file
  2. OVMF ACPI QEMU support
  3. Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
  4. Copyright (C) 2012-2014, Red Hat, Inc.
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <Library/DebugLib.h>
  8. #include <Library/BaseLib.h>
  9. #include <Library/BaseMemoryLib.h>
  10. #include <Library/MemoryAllocationLib.h>
  11. #include <Library/QemuFwCfgLib.h>
  12. #include <Library/DxeServicesTableLib.h>
  13. #include <Library/PcdLib.h>
  14. #include <Library/OrderedCollectionLib.h>
  15. #include <Library/TdxLib.h>
  16. #include <IndustryStandard/Acpi.h>
  17. #include <Protocol/AcpiSystemDescriptionTable.h>
  18. #include <Protocol/AcpiTable.h>
  19. #include <Library/UefiBootServicesTableLib.h>
  20. #include <Library/UefiLib.h>
  21. #include <Library/TdxMailboxLib.h>
  22. #include <Protocol/Cpu.h>
  23. #include <Uefi.h>
  24. #include <TdxAcpiTable.h>
  25. /**
  26. At the beginning of system boot, a 4K-aligned, 4K-size memory (Td mailbox) is
  27. pre-allocated by host VMM. BSP & APs do the page accept together in that memory
  28. region.
  29. After that TDVF is designed to relocate the mailbox to a 4K-aligned, 4K-size
  30. memory block which is allocated in the ACPI Nvs memory. APs are waken up and
  31. spin around the relocated mailbox for further command.
  32. @return EFI_PHYSICAL_ADDRESS Address of the relocated mailbox
  33. **/
  34. EFI_PHYSICAL_ADDRESS
  35. EFIAPI
  36. RelocateMailbox (
  37. VOID
  38. )
  39. {
  40. EFI_PHYSICAL_ADDRESS Address;
  41. VOID *ApLoopFunc;
  42. UINT32 RelocationPages;
  43. MP_RELOCATION_MAP RelocationMap;
  44. MP_WAKEUP_MAILBOX *RelocatedMailBox;
  45. EFI_STATUS Status;
  46. Address = 0;
  47. ApLoopFunc = NULL;
  48. ZeroMem (&RelocationMap, sizeof (RelocationMap));
  49. //
  50. // Get information needed to setup aps running in their
  51. // run loop in allocated acpi reserved memory
  52. // Add another page for mailbox
  53. //
  54. AsmGetRelocationMap (&RelocationMap);
  55. if ((RelocationMap.RelocateApLoopFuncAddress == 0) || (RelocationMap.RelocateApLoopFuncSize == 0)) {
  56. DEBUG ((DEBUG_ERROR, "Failed to get the RelocationMap.\n"));
  57. return 0;
  58. }
  59. RelocationPages = EFI_SIZE_TO_PAGES ((UINT32)RelocationMap.RelocateApLoopFuncSize) + 1;
  60. Status = gBS->AllocatePages (AllocateAnyPages, EfiACPIMemoryNVS, RelocationPages, &Address);
  61. if (EFI_ERROR (Status)) {
  62. DEBUG ((DEBUG_ERROR, "Failed to allocate pages for MailboxRelocation. %r\n", Status));
  63. return 0;
  64. }
  65. ZeroMem ((VOID *)Address, EFI_PAGES_TO_SIZE (RelocationPages));
  66. ApLoopFunc = (VOID *)((UINTN)Address + EFI_PAGE_SIZE);
  67. CopyMem (
  68. ApLoopFunc,
  69. RelocationMap.RelocateApLoopFuncAddress,
  70. RelocationMap.RelocateApLoopFuncSize
  71. );
  72. DEBUG ((
  73. DEBUG_INFO,
  74. "Ap Relocation: mailbox %llx, loop %p\n",
  75. Address,
  76. ApLoopFunc
  77. ));
  78. //
  79. // Initialize mailbox
  80. //
  81. RelocatedMailBox = (MP_WAKEUP_MAILBOX *)Address;
  82. RelocatedMailBox->Command = MpProtectedModeWakeupCommandNoop;
  83. RelocatedMailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID;
  84. RelocatedMailBox->WakeUpVector = 0;
  85. //
  86. // Wakup APs and have been move to the finalized run loop
  87. // They will spin until guest OS wakes them
  88. //
  89. MpSerializeStart ();
  90. MpSendWakeupCommand (
  91. MpProtectedModeWakeupCommandWakeup,
  92. (UINT64)ApLoopFunc,
  93. (UINT64)RelocatedMailBox,
  94. 0,
  95. 0,
  96. 0
  97. );
  98. return Address;
  99. }
  100. /**
  101. Alter the MADT when ACPI Table from QEMU is available.
  102. @param[in] Event Event whose notification function is being invoked
  103. @param[in] Context Pointer to the notification function's context
  104. **/
  105. VOID
  106. EFIAPI
  107. AlterAcpiTable (
  108. IN EFI_EVENT Event,
  109. IN VOID *Context
  110. )
  111. {
  112. EFI_ACPI_SDT_PROTOCOL *AcpiSdtProtocol;
  113. EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
  114. EFI_STATUS Status;
  115. UINTN Index;
  116. EFI_ACPI_SDT_HEADER *Table;
  117. EFI_ACPI_TABLE_VERSION Version;
  118. UINTN OriginalTableKey;
  119. UINTN NewTableKey;
  120. UINT8 *NewMadtTable;
  121. UINTN NewMadtTableLength;
  122. EFI_PHYSICAL_ADDRESS RelocateMailboxAddress;
  123. EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *MadtMpWk;
  124. EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader;
  125. Index = 0;
  126. NewMadtTable = NULL;
  127. MadtHeader = NULL;
  128. Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (void **)&AcpiSdtProtocol);
  129. if (EFI_ERROR (Status)) {
  130. DEBUG ((DEBUG_ERROR, "Unable to locate ACPI SDT protocol.\n"));
  131. return;
  132. }
  133. RelocateMailboxAddress = RelocateMailbox ();
  134. if (RelocateMailboxAddress == 0) {
  135. ASSERT (FALSE);
  136. DEBUG ((DEBUG_ERROR, "Failed to relocate Td mailbox\n"));
  137. return;
  138. }
  139. do {
  140. Status = AcpiSdtProtocol->GetAcpiTable (Index, &Table, &Version, &OriginalTableKey);
  141. if (!EFI_ERROR (Status) && (Table->Signature == EFI_ACPI_1_0_APIC_SIGNATURE)) {
  142. Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (void **)&AcpiTableProtocol);
  143. if (EFI_ERROR (Status)) {
  144. DEBUG ((DEBUG_ERROR, "Unable to locate ACPI Table protocol.\n"));
  145. break;
  146. }
  147. NewMadtTableLength = Table->Length + sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE);
  148. NewMadtTable = AllocatePool (NewMadtTableLength);
  149. if (NewMadtTable == NULL) {
  150. DEBUG ((DEBUG_ERROR, "%a: OUT_OF_SOURCES error.\n", __FUNCTION__));
  151. break;
  152. }
  153. CopyMem (NewMadtTable, (UINT8 *)Table, Table->Length);
  154. MadtHeader = (EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)NewMadtTable;
  155. MadtHeader->Header.Length = (UINT32)NewMadtTableLength;
  156. MadtMpWk = (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *)(NewMadtTable + Table->Length);
  157. MadtMpWk->Type = EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP;
  158. MadtMpWk->Length = sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE);
  159. MadtMpWk->MailBoxVersion = 1;
  160. MadtMpWk->Reserved = 0;
  161. MadtMpWk->MailBoxAddress = RelocateMailboxAddress;
  162. Status = AcpiTableProtocol->InstallAcpiTable (AcpiTableProtocol, NewMadtTable, NewMadtTableLength, &NewTableKey);
  163. if (EFI_ERROR (Status)) {
  164. DEBUG ((DEBUG_ERROR, "Failed to install new MADT table. %r\n", Status));
  165. break;
  166. }
  167. Status = AcpiTableProtocol->UninstallAcpiTable (AcpiTableProtocol, OriginalTableKey);
  168. if (EFI_ERROR (Status)) {
  169. DEBUG ((DEBUG_ERROR, "Uninstall old MADT table error.\n"));
  170. }
  171. break;
  172. }
  173. Index++;
  174. } while (!EFI_ERROR (Status));
  175. if (NewMadtTable != NULL) {
  176. FreePool (NewMadtTable);
  177. }
  178. }