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