]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Library / BaseMemEncryptSevLib / X64 / VirtualMemory.c
1 /** @file
2
3 Virtual Memory Management Services to test an address range encryption state
4
5 Copyright (c) 2020, AMD Incorporated. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include <Library/CpuLib.h>
12 #include <Library/MemEncryptSevLib.h>
13
14 #include "VirtualMemory.h"
15
16 /**
17 Returns the (updated) address range state based upon the page table
18 entry.
19
20 @param[in] CurrentState The current address range state
21 @param[in] PageDirectoryEntry The page table entry to check
22 @param[in] AddressEncMask The encryption mask
23
24 @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
25 unencrypted
26 @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
27 encrypted
28 @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
29 **/
30 STATIC
31 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
32 UpdateAddressState (
33 IN MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE CurrentState,
34 IN UINT64 PageDirectoryEntry,
35 IN UINT64 AddressEncMask
36 )
37 {
38 if (CurrentState == MemEncryptSevAddressRangeEncrypted) {
39 if ((PageDirectoryEntry & AddressEncMask) == 0) {
40 CurrentState = MemEncryptSevAddressRangeMixed;
41 }
42 } else if (CurrentState == MemEncryptSevAddressRangeUnencrypted) {
43 if ((PageDirectoryEntry & AddressEncMask) != 0) {
44 CurrentState = MemEncryptSevAddressRangeMixed;
45 }
46 } else if (CurrentState == MemEncryptSevAddressRangeError) {
47 //
48 // First address check, set initial state
49 //
50 if ((PageDirectoryEntry & AddressEncMask) == 0) {
51 CurrentState = MemEncryptSevAddressRangeUnencrypted;
52 } else {
53 CurrentState = MemEncryptSevAddressRangeEncrypted;
54 }
55 }
56
57 return CurrentState;
58 }
59
60 /**
61 Returns the encryption state of the specified virtual address range.
62
63 @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
64 current CR3)
65 @param[in] BaseAddress Base address to check
66 @param[in] Length Length of virtual address range
67
68 @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
69 unencrypted
70 @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
71 encrypted
72 @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
73 @retval MemEncryptSevAddressRangeError Address range is not mapped
74 **/
75 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
76 EFIAPI
77 InternalMemEncryptSevGetAddressRangeState (
78 IN PHYSICAL_ADDRESS Cr3BaseAddress,
79 IN PHYSICAL_ADDRESS BaseAddress,
80 IN UINTN Length
81 )
82 {
83 PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
84 PAGE_MAP_AND_DIRECTORY_POINTER *PageUpperDirectoryPointerEntry;
85 PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
86 PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
87 PAGE_TABLE_ENTRY *PageDirectory2MEntry;
88 PAGE_TABLE_4K_ENTRY *PageTableEntry;
89 UINT64 AddressEncMask;
90 UINT64 PgTableMask;
91 PHYSICAL_ADDRESS Address;
92 PHYSICAL_ADDRESS AddressEnd;
93 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;
94
95 //
96 // If Cr3BaseAddress is not specified then read the current CR3
97 //
98 if (Cr3BaseAddress == 0) {
99 Cr3BaseAddress = AsmReadCr3 ();
100 }
101
102 AddressEncMask = MemEncryptSevGetEncryptionMask ();
103 AddressEncMask &= PAGING_1G_ADDRESS_MASK_64;
104
105 PgTableMask = AddressEncMask | EFI_PAGE_MASK;
106
107 State = MemEncryptSevAddressRangeError;
108
109 //
110 // Encryption is on a page basis, so start at the beginning of the
111 // virtual address page boundary and walk page-by-page.
112 //
113 Address = (PHYSICAL_ADDRESS)(UINTN)BaseAddress & ~EFI_PAGE_MASK;
114 AddressEnd = (PHYSICAL_ADDRESS)
115 (UINTN)(BaseAddress + Length);
116
117 while (Address < AddressEnd) {
118 PageMapLevel4Entry = (VOID *)(Cr3BaseAddress & ~PgTableMask);
119 PageMapLevel4Entry += PML4_OFFSET (Address);
120 if (!PageMapLevel4Entry->Bits.Present) {
121 return MemEncryptSevAddressRangeError;
122 }
123
124 PageDirectory1GEntry = (VOID *)(
125 (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
126 12) & ~PgTableMask
127 );
128 PageDirectory1GEntry += PDP_OFFSET (Address);
129 if (!PageDirectory1GEntry->Bits.Present) {
130 return MemEncryptSevAddressRangeError;
131 }
132
133 //
134 // If the MustBe1 bit is not 1, it's not actually a 1GB entry
135 //
136 if (PageDirectory1GEntry->Bits.MustBe1) {
137 //
138 // Valid 1GB page
139 //
140 State = UpdateAddressState (
141 State,
142 PageDirectory1GEntry->Uint64,
143 AddressEncMask
144 );
145
146 Address += BIT30;
147 continue;
148 }
149
150 //
151 // Actually a PDP
152 //
153 PageUpperDirectoryPointerEntry =
154 (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory1GEntry;
155 PageDirectory2MEntry =
156 (VOID *)(
157 (PageUpperDirectoryPointerEntry->Bits.PageTableBaseAddress <<
158 12) & ~PgTableMask
159 );
160 PageDirectory2MEntry += PDE_OFFSET (Address);
161 if (!PageDirectory2MEntry->Bits.Present) {
162 return MemEncryptSevAddressRangeError;
163 }
164
165 //
166 // If the MustBe1 bit is not a 1, it's not a 2MB entry
167 //
168 if (PageDirectory2MEntry->Bits.MustBe1) {
169 //
170 // Valid 2MB page
171 //
172 State = UpdateAddressState (
173 State,
174 PageDirectory2MEntry->Uint64,
175 AddressEncMask
176 );
177
178 Address += BIT21;
179 continue;
180 }
181
182 //
183 // Actually a PMD
184 //
185 PageDirectoryPointerEntry =
186 (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory2MEntry;
187 PageTableEntry =
188 (VOID *)(
189 (PageDirectoryPointerEntry->Bits.PageTableBaseAddress <<
190 12) & ~PgTableMask
191 );
192 PageTableEntry += PTE_OFFSET (Address);
193 if (!PageTableEntry->Bits.Present) {
194 return MemEncryptSevAddressRangeError;
195 }
196
197 State = UpdateAddressState (
198 State,
199 PageTableEntry->Uint64,
200 AddressEncMask
201 );
202
203 Address += EFI_PAGE_SIZE;
204 }
205
206 return State;
207 }