PeiSnpSystemRamValidate.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /** @file
  2. SEV-SNP Page Validation functions.
  3. Copyright (c) 2021 AMD Incorporated. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Uefi/UefiBaseType.h>
  7. #include <Library/BaseLib.h>
  8. #include <Library/PcdLib.h>
  9. #include <Library/DebugLib.h>
  10. #include <Library/MemEncryptSevLib.h>
  11. #include "SnpPageStateChange.h"
  12. #include "VirtualMemory.h"
  13. typedef struct {
  14. UINT64 StartAddress;
  15. UINT64 EndAddress;
  16. } SNP_PRE_VALIDATED_RANGE;
  17. STATIC SNP_PRE_VALIDATED_RANGE mPreValidatedRange[] = {
  18. // The below address range was part of the SEV OVMF metadata, and range
  19. // should be pre-validated by the Hypervisor.
  20. {
  21. FixedPcdGet32 (PcdOvmfSecPageTablesBase),
  22. FixedPcdGet32 (PcdOvmfPeiMemFvBase),
  23. },
  24. // The below range is pre-validated by the Sec/SecMain.c
  25. {
  26. FixedPcdGet32 (PcdOvmfSecValidatedStart),
  27. FixedPcdGet32 (PcdOvmfSecValidatedEnd)
  28. },
  29. };
  30. STATIC
  31. BOOLEAN
  32. DetectPreValidatedOverLap (
  33. IN PHYSICAL_ADDRESS StartAddress,
  34. IN PHYSICAL_ADDRESS EndAddress,
  35. OUT SNP_PRE_VALIDATED_RANGE *OverlapRange
  36. )
  37. {
  38. UINTN i;
  39. //
  40. // Check if the specified address range exist in pre-validated array.
  41. //
  42. for (i = 0; i < ARRAY_SIZE (mPreValidatedRange); i++) {
  43. if ((mPreValidatedRange[i].StartAddress < EndAddress) &&
  44. (StartAddress < mPreValidatedRange[i].EndAddress))
  45. {
  46. OverlapRange->StartAddress = mPreValidatedRange[i].StartAddress;
  47. OverlapRange->EndAddress = mPreValidatedRange[i].EndAddress;
  48. return TRUE;
  49. }
  50. }
  51. return FALSE;
  52. }
  53. /**
  54. Pre-validate the system RAM when SEV-SNP is enabled in the guest VM.
  55. @param[in] BaseAddress Base address
  56. @param[in] NumPages Number of pages starting from the base address
  57. **/
  58. VOID
  59. EFIAPI
  60. MemEncryptSevSnpPreValidateSystemRam (
  61. IN PHYSICAL_ADDRESS BaseAddress,
  62. IN UINTN NumPages
  63. )
  64. {
  65. PHYSICAL_ADDRESS EndAddress;
  66. SNP_PRE_VALIDATED_RANGE OverlapRange;
  67. EFI_STATUS Status;
  68. if (!MemEncryptSevSnpIsEnabled ()) {
  69. return;
  70. }
  71. EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
  72. //
  73. // The page table used in PEI can address up to 4GB memory. If we are asked to
  74. // validate a range above the 4GB, then create an identity mapping so that the
  75. // PVALIDATE instruction can execute correctly. If the page table entry is not
  76. // present then PVALIDATE will #GP.
  77. //
  78. if (BaseAddress >= SIZE_4GB) {
  79. Status = InternalMemEncryptSevCreateIdentityMap1G (
  80. 0,
  81. BaseAddress,
  82. EFI_PAGES_TO_SIZE (NumPages)
  83. );
  84. if (EFI_ERROR (Status)) {
  85. ASSERT (FALSE);
  86. CpuDeadLoop ();
  87. }
  88. }
  89. while (BaseAddress < EndAddress) {
  90. //
  91. // Check if the range overlaps with the pre-validated ranges.
  92. //
  93. if (DetectPreValidatedOverLap (BaseAddress, EndAddress, &OverlapRange)) {
  94. // Validate the non-overlap regions.
  95. if (BaseAddress < OverlapRange.StartAddress) {
  96. NumPages = EFI_SIZE_TO_PAGES (OverlapRange.StartAddress - BaseAddress);
  97. InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
  98. }
  99. BaseAddress = OverlapRange.EndAddress;
  100. continue;
  101. }
  102. // Validate the remaining pages.
  103. NumPages = EFI_SIZE_TO_PAGES (EndAddress - BaseAddress);
  104. InternalSetPageState (BaseAddress, NumPages, SevSnpPagePrivate, TRUE);
  105. BaseAddress = EndAddress;
  106. }
  107. }