AmdSevDxe.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /** @file
  2. AMD Sev Dxe driver. This driver is dispatched early in DXE, due to being list
  3. in APRIORI. It clears C-bit from MMIO and NonExistent Memory space when SEV
  4. is enabled.
  5. Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. #include <IndustryStandard/Q35MchIch9.h>
  9. #include <Library/BaseLib.h>
  10. #include <Library/BaseMemoryLib.h>
  11. #include <Library/DebugLib.h>
  12. #include <Library/DxeServicesTableLib.h>
  13. #include <Library/MemEncryptSevLib.h>
  14. #include <Library/MemoryAllocationLib.h>
  15. #include <Library/PcdLib.h>
  16. EFI_STATUS
  17. EFIAPI
  18. AmdSevDxeEntryPoint (
  19. IN EFI_HANDLE ImageHandle,
  20. IN EFI_SYSTEM_TABLE *SystemTable
  21. )
  22. {
  23. EFI_STATUS Status;
  24. EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDescMap;
  25. UINTN NumEntries;
  26. UINTN Index;
  27. //
  28. // Do nothing when SEV is not enabled
  29. //
  30. if (!MemEncryptSevIsEnabled ()) {
  31. return EFI_UNSUPPORTED;
  32. }
  33. //
  34. // Iterate through the GCD map and clear the C-bit from MMIO and NonExistent
  35. // memory space. The NonExistent memory space will be used for mapping the
  36. // MMIO space added later (eg PciRootBridge). By clearing both known MMIO and
  37. // NonExistent memory space can gurantee that current and furture MMIO adds
  38. // will have C-bit cleared.
  39. //
  40. Status = gDS->GetMemorySpaceMap (&NumEntries, &AllDescMap);
  41. if (!EFI_ERROR (Status)) {
  42. for (Index = 0; Index < NumEntries; Index++) {
  43. CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
  44. Desc = &AllDescMap[Index];
  45. if ((Desc->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) ||
  46. (Desc->GcdMemoryType == EfiGcdMemoryTypeNonExistent))
  47. {
  48. Status = MemEncryptSevClearMmioPageEncMask (
  49. 0,
  50. Desc->BaseAddress,
  51. EFI_SIZE_TO_PAGES (Desc->Length)
  52. );
  53. ASSERT_EFI_ERROR (Status);
  54. }
  55. }
  56. FreePool (AllDescMap);
  57. }
  58. //
  59. // If PCI Express is enabled, the MMCONFIG area has been reserved, rather
  60. // than marked as MMIO, and so the C-bit won't be cleared by the above walk
  61. // through the GCD map. Check for the MMCONFIG area and clear the C-bit for
  62. // the range.
  63. //
  64. if (PcdGet16 (PcdOvmfHostBridgePciDevId) == INTEL_Q35_MCH_DEVICE_ID) {
  65. Status = MemEncryptSevClearMmioPageEncMask (
  66. 0,
  67. FixedPcdGet64 (PcdPciExpressBaseAddress),
  68. EFI_SIZE_TO_PAGES (SIZE_256MB)
  69. );
  70. ASSERT_EFI_ERROR (Status);
  71. }
  72. //
  73. // When SMM is enabled, clear the C-bit from SMM Saved State Area
  74. //
  75. // NOTES: The SavedStateArea address cleared here is before SMBASE
  76. // relocation. Currently, we do not clear the SavedStateArea address after
  77. // SMBASE is relocated due to the following reasons:
  78. //
  79. // 1) Guest BIOS never access the relocated SavedStateArea.
  80. //
  81. // 2) The C-bit works on page-aligned address, but the SavedStateArea
  82. // address is not a page-aligned. Theoretically, we could roundup the address
  83. // and clear the C-bit of aligned address but looking carefully we found
  84. // that some portion of the page contains code -- which will causes a bigger
  85. // issues for SEV guest. When SEV is enabled, all the code must be encrypted
  86. // otherwise hardware will cause trap.
  87. //
  88. // We restore the C-bit for this SMM Saved State Area after SMBASE relocation
  89. // is completed (See OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c).
  90. //
  91. if (FeaturePcdGet (PcdSmmSmramRequire)) {
  92. UINTN MapPagesBase;
  93. UINTN MapPagesCount;
  94. Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (
  95. &MapPagesBase,
  96. &MapPagesCount
  97. );
  98. ASSERT_EFI_ERROR (Status);
  99. //
  100. // Although these pages were set aside (i.e., allocated) by PlatformPei, we
  101. // could be after a warm reboot from the OS. Don't leak any stale OS data
  102. // to the hypervisor.
  103. //
  104. ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));
  105. Status = MemEncryptSevClearPageEncMask (
  106. 0, // Cr3BaseAddress -- use current CR3
  107. MapPagesBase, // BaseAddress
  108. MapPagesCount // NumPages
  109. );
  110. if (EFI_ERROR (Status)) {
  111. DEBUG ((
  112. DEBUG_ERROR,
  113. "%a: MemEncryptSevClearPageEncMask(): %r\n",
  114. __FUNCTION__,
  115. Status
  116. ));
  117. ASSERT (FALSE);
  118. CpuDeadLoop ();
  119. }
  120. }
  121. return EFI_SUCCESS;
  122. }