VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/IoMmuDxe/IoMmuBuffer.c@ 99404

Last change on this file since 99404 was 99404, checked in by vboxsync, 23 months ago

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 15.1 KB
Line 
1/** @file
2
3 Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8#include <Library/BaseLib.h>
9#include <Library/BaseMemoryLib.h>
10#include <Library/DebugLib.h>
11#include <Library/MemoryAllocationLib.h>
12#include <Library/MemEncryptSevLib.h>
13#include <Library/MemEncryptTdxLib.h>
14#include <Library/PcdLib.h>
15#include <Library/UefiBootServicesTableLib.h>
16#include "IoMmuInternal.h"
17
18extern BOOLEAN mReservedSharedMemSupported;
19
20#define SIZE_OF_MEM_RANGE(MemRange) (MemRange->HeaderSize + MemRange->DataSize)
21
22#define RESERVED_MEM_BITMAP_4K_MASK 0xf
23#define RESERVED_MEM_BITMAP_32K_MASK 0xff0
24#define RESERVED_MEM_BITMAP_128K_MASK 0x3000
25#define RESERVED_MEM_BITMAP_1M_MASK 0x40000
26#define RESERVED_MEM_BITMAP_2M_MASK 0x180000
27#define RESERVED_MEM_BITMAP_MASK 0x1fffff
28
29/**
30 * mReservedMemRanges describes the layout of the reserved memory.
31 * The reserved memory consists of disfferent size of memory region.
32 * The pieces of memory with the same size are managed by one entry
33 * in the mReservedMemRanges. All the pieces of memories are managed by
34 * mReservedMemBitmap which is a UINT32. It means it can manage at most
35 * 32 pieces of memory. Because of the layout of CommonBuffer
36 * (1-page header + n-page data), a piece of reserved memory consists of
37 * 2 parts: Header + Data.
38 *
39 * So put all these together, mReservedMemRanges and mReservedMemBitmap
40 * are designed to manage the reserved memory.
41 *
42 * Use the second entry of mReservedMemRanges as an example.
43 * { RESERVED_MEM_BITMAP_32K_MASK, 4, 8, SIZE_32KB, SIZE_4KB, 0 },
44 * - RESERVED_MEM_BITMAP_32K_MASK is 0xff0. It means bit4-11 in mReservedMemBitmap
45 * is reserved for 32K size memory.
46 * - 4 is the shift of mReservedMemBitmap.
47 * - 8 means there are 8 pieces of 32K size memory.
48 * - SIZE_32KB indicates the size of Data part.
49 * - SIZE_4KB is the size of Header part.
50 * - 0 is the start address of this memory range which will be populated when
51 * the reserved memory is initialized.
52 *
53 * The size and count of the memory region are derived from the experience. For
54 * a typical grub boot, there are about 5100 IoMmu/DMA operation. Most of these
55 * DMA operation require the memory with size less than 32K (~5080). But we find
56 * in grub boot there may be 2 DMA operation which require for the memory larger
57 * than 1M. And these 2 DMA operation occur concurrently. So we reserve 2 pieces
58 * of memory with size of SIZE_2MB. This is for the best boot performance.
59 *
60 * If all the reserved memory are exausted, then it will fall back to the legacy
61 * memory allocation as before.
62 */
63STATIC IOMMU_RESERVED_MEM_RANGE mReservedMemRanges[] = {
64 { RESERVED_MEM_BITMAP_4K_MASK, 0, 4, SIZE_4KB, SIZE_4KB, 0 },
65 { RESERVED_MEM_BITMAP_32K_MASK, 4, 8, SIZE_32KB, SIZE_4KB, 0 },
66 { RESERVED_MEM_BITMAP_128K_MASK, 12, 2, SIZE_128KB, SIZE_4KB, 0 },
67 { RESERVED_MEM_BITMAP_1M_MASK, 14, 1, SIZE_1MB, SIZE_4KB, 0 },
68 { RESERVED_MEM_BITMAP_2M_MASK, 15, 2, SIZE_2MB, SIZE_4KB, 0 },
69};
70
71//
72// Bitmap of the allocation of reserved memory.
73//
74STATIC UINT32 mReservedMemBitmap = 0;
75
76//
77// Start address of the reserved memory region.
78//
79STATIC EFI_PHYSICAL_ADDRESS mReservedSharedMemAddress = 0;
80
81//
82// Total size of the reserved memory region.
83//
84STATIC UINT32 mReservedSharedMemSize = 0;
85
86/**
87 * Calculate the size of reserved memory.
88 *
89 * @retval UINT32 Size of the reserved memory
90 */
91STATIC
92UINT32
93CalcuateReservedMemSize (
94 VOID
95 )
96{
97 UINT32 Index;
98 IOMMU_RESERVED_MEM_RANGE *MemRange;
99
100 if (mReservedSharedMemSize != 0) {
101 return mReservedSharedMemSize;
102 }
103
104 for (Index = 0; Index < ARRAY_SIZE (mReservedMemRanges); Index++) {
105 MemRange = &mReservedMemRanges[Index];
106 mReservedSharedMemSize += (SIZE_OF_MEM_RANGE (MemRange) * MemRange->Slots);
107 }
108
109 return mReservedSharedMemSize;
110}
111
112/**
113 * Allocate a memory region and convert it to be shared. This memory region will be
114 * used in the DMA operation.
115 *
116 * The pre-alloc memory contains pieces of memory regions with different size. The
117 * allocation of the shared memory regions are indicated by a 32-bit bitmap (mReservedMemBitmap).
118 *
119 * The memory regions are consumed by IoMmuAllocateBuffer (in which CommonBuffer is allocated) and
120 * IoMmuMap (in which bounce buffer is allocated).
121 *
122 * The CommonBuffer contains 2 parts, one page for CommonBufferHeader which is private memory,
123 * the other part is shared memory. So the layout of a piece of memory region after initialization
124 * looks like:
125 *
126 * |------------|----------------------------|
127 * | Header | Data | <-- a piece of pre-alloc memory region
128 * | 4k, private| 4k/32k/128k/etc, shared |
129 * |-----------------------------------------|
130 *
131 * @retval EFI_SUCCESS Successfully initialize the reserved memory.
132 * @retval EFI_UNSUPPORTED This feature is not supported.
133 */
134EFI_STATUS
135IoMmuInitReservedSharedMem (
136 VOID
137 )
138{
139 EFI_STATUS Status;
140 UINT32 Index1, Index2;
141 UINTN TotalPages;
142 IOMMU_RESERVED_MEM_RANGE *MemRange;
143 EFI_PHYSICAL_ADDRESS PhysicalAddress;
144 UINT64 SharedAddress;
145
146 if (!mReservedSharedMemSupported) {
147 return EFI_UNSUPPORTED;
148 }
149
150 TotalPages = EFI_SIZE_TO_PAGES (CalcuateReservedMemSize ());
151
152 PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (TotalPages);
153 DEBUG ((
154 DEBUG_VERBOSE,
155 "%a: ReservedMem (%d pages) address = 0x%llx\n",
156 __FUNCTION__,
157 TotalPages,
158 PhysicalAddress
159 ));
160
161 mReservedMemBitmap = 0;
162 mReservedSharedMemAddress = PhysicalAddress;
163
164 for (Index1 = 0; Index1 < ARRAY_SIZE (mReservedMemRanges); Index1++) {
165 MemRange = &mReservedMemRanges[Index1];
166 MemRange->StartAddressOfMemRange = PhysicalAddress;
167
168 for (Index2 = 0; Index2 < MemRange->Slots; Index2++) {
169 SharedAddress = (UINT64)(UINTN)(MemRange->StartAddressOfMemRange + Index2 * SIZE_OF_MEM_RANGE (MemRange) + MemRange->HeaderSize);
170
171 if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
172 Status = MemEncryptSevClearPageEncMask (
173 0,
174 SharedAddress,
175 EFI_SIZE_TO_PAGES (MemRange->DataSize)
176 );
177 ASSERT (!EFI_ERROR (Status));
178 } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
179 Status = MemEncryptTdxSetPageSharedBit (
180 0,
181 SharedAddress,
182 EFI_SIZE_TO_PAGES (MemRange->DataSize)
183 );
184 ASSERT (!EFI_ERROR (Status));
185 } else {
186 ASSERT (FALSE);
187 }
188 }
189
190 PhysicalAddress += (MemRange->Slots * SIZE_OF_MEM_RANGE (MemRange));
191 }
192
193 return EFI_SUCCESS;
194}
195
196/**
197 * Release the pre-alloc shared memory.
198 *
199 * @retval EFI_SUCCESS Successfully release the shared memory
200 */
201EFI_STATUS
202IoMmuReleaseReservedSharedMem (
203 BOOLEAN MemoryMapLocked
204 )
205{
206 EFI_STATUS Status;
207 UINT32 Index1, Index2;
208 IOMMU_RESERVED_MEM_RANGE *MemRange;
209 UINT64 SharedAddress;
210
211 if (!mReservedSharedMemSupported) {
212 return EFI_SUCCESS;
213 }
214
215 for (Index1 = 0; Index1 < ARRAY_SIZE (mReservedMemRanges); Index1++) {
216 MemRange = &mReservedMemRanges[Index1];
217 for (Index2 = 0; Index2 < MemRange->Slots; Index2++) {
218 SharedAddress = (UINT64)(UINTN)(MemRange->StartAddressOfMemRange + Index2 * SIZE_OF_MEM_RANGE (MemRange) + MemRange->HeaderSize);
219
220 if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
221 Status = MemEncryptSevSetPageEncMask (
222 0,
223 SharedAddress,
224 EFI_SIZE_TO_PAGES (MemRange->DataSize)
225 );
226 ASSERT (!EFI_ERROR (Status));
227 } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
228 Status = MemEncryptTdxClearPageSharedBit (
229 0,
230 SharedAddress,
231 EFI_SIZE_TO_PAGES (MemRange->DataSize)
232 );
233 ASSERT (!EFI_ERROR (Status));
234 } else {
235 ASSERT (FALSE);
236 }
237 }
238 }
239
240 if (!MemoryMapLocked) {
241 FreePages ((VOID *)(UINTN)mReservedSharedMemAddress, EFI_SIZE_TO_PAGES (CalcuateReservedMemSize ()));
242 mReservedSharedMemAddress = 0;
243 mReservedMemBitmap = 0;
244 }
245
246 mReservedSharedMemSupported = FALSE;
247
248 return EFI_SUCCESS;
249}
250
251/**
252 * Allocate from the reserved memory pool.
253 * If the reserved shared memory is exausted or there is no suitalbe size, it turns
254 * to the LegacyAllocateBuffer.
255 *
256 * @param Type Allocate type
257 * @param MemoryType The memory type to be allocated
258 * @param Pages Pages to be allocated.
259 * @param ReservedMemBitmap Bitmap of the allocated memory region
260 * @param PhysicalAddress Pointer to the data part of allocated memory region
261 *
262 * @retval EFI_SUCCESS Successfully allocate the buffer
263 * @retval Other As the error code indicates
264 */
265STATIC
266EFI_STATUS
267InternalAllocateBuffer (
268 IN EFI_ALLOCATE_TYPE Type,
269 IN EFI_MEMORY_TYPE MemoryType,
270 IN UINTN Pages,
271 IN OUT UINT32 *ReservedMemBitmap,
272 IN OUT EFI_PHYSICAL_ADDRESS *PhysicalAddress
273 )
274{
275 UINT32 MemBitmap;
276 UINT8 Index;
277 IOMMU_RESERVED_MEM_RANGE *MemRange;
278 UINTN PagesOfLastMemRange;
279
280 *ReservedMemBitmap = 0;
281
282 if (Pages == 0) {
283 ASSERT (FALSE);
284 return EFI_INVALID_PARAMETER;
285 }
286
287 if (!mReservedSharedMemSupported) {
288 goto LegacyAllocateBuffer;
289 }
290
291 if (mReservedSharedMemAddress == 0) {
292 goto LegacyAllocateBuffer;
293 }
294
295 PagesOfLastMemRange = 0;
296
297 for (Index = 0; Index < ARRAY_SIZE (mReservedMemRanges); Index++) {
298 if ((Pages > PagesOfLastMemRange) && (Pages <= EFI_SIZE_TO_PAGES (mReservedMemRanges[Index].DataSize))) {
299 break;
300 }
301
302 PagesOfLastMemRange = EFI_SIZE_TO_PAGES (mReservedMemRanges[Index].DataSize);
303 }
304
305 if (Index == ARRAY_SIZE (mReservedMemRanges)) {
306 // There is no suitable size of reserved memory. Turn to legacy allocate.
307 goto LegacyAllocateBuffer;
308 }
309
310 MemRange = &mReservedMemRanges[Index];
311
312 if ((mReservedMemBitmap & MemRange->BitmapMask) == MemRange->BitmapMask) {
313 // The reserved memory is exausted. Turn to legacy allocate.
314 goto LegacyAllocateBuffer;
315 }
316
317 MemBitmap = (mReservedMemBitmap & MemRange->BitmapMask) >> MemRange->Shift;
318
319 for (Index = 0; Index < MemRange->Slots; Index++) {
320 if ((MemBitmap & (UINT8)(1<<Index)) == 0) {
321 break;
322 }
323 }
324
325 ASSERT (Index != MemRange->Slots);
326
327 *PhysicalAddress = MemRange->StartAddressOfMemRange + Index * SIZE_OF_MEM_RANGE (MemRange) + MemRange->HeaderSize;
328 *ReservedMemBitmap = (UINT32)(1 << (Index + MemRange->Shift));
329
330 DEBUG ((
331 DEBUG_VERBOSE,
332 "%a: range-size: %lx, start-address=0x%llx, pages=0x%llx, bits=0x%lx, bitmap: %lx => %lx\n",
333 __FUNCTION__,
334 MemRange->DataSize,
335 *PhysicalAddress,
336 Pages,
337 *ReservedMemBitmap,
338 mReservedMemBitmap,
339 mReservedMemBitmap | *ReservedMemBitmap
340 ));
341
342 return EFI_SUCCESS;
343
344LegacyAllocateBuffer:
345
346 *ReservedMemBitmap = 0;
347 return gBS->AllocatePages (Type, MemoryType, Pages, PhysicalAddress);
348}
349
350/**
351 * Allocate reserved shared memory for bounce buffer.
352 *
353 * @param Type Allocate type
354 * @param MemoryType The memory type to be allocated
355 * @param MapInfo Pointer to the MAP_INFO
356 *
357 * @retval EFI_SUCCESS Successfully allocate the bounce buffer
358 * @retval Other As the error code indicates
359
360 */
361EFI_STATUS
362IoMmuAllocateBounceBuffer (
363 IN EFI_ALLOCATE_TYPE Type,
364 IN EFI_MEMORY_TYPE MemoryType,
365 IN OUT MAP_INFO *MapInfo
366 )
367{
368 EFI_STATUS Status;
369 UINT32 ReservedMemBitmap;
370
371 ReservedMemBitmap = 0;
372 Status = InternalAllocateBuffer (
373 Type,
374 MemoryType,
375 MapInfo->NumberOfPages,
376 &ReservedMemBitmap,
377 &MapInfo->PlainTextAddress
378 );
379 MapInfo->ReservedMemBitmap = ReservedMemBitmap;
380 mReservedMemBitmap |= ReservedMemBitmap;
381
382 ASSERT (Status == EFI_SUCCESS);
383
384 return Status;
385}
386
387/**
388 * Free the bounce buffer allocated in IoMmuAllocateBounceBuffer.
389 *
390 * @param MapInfo Pointer to the MAP_INFO
391 * @return EFI_SUCCESS Successfully free the bounce buffer.
392 */
393EFI_STATUS
394IoMmuFreeBounceBuffer (
395 IN OUT MAP_INFO *MapInfo
396 )
397{
398 if (MapInfo->ReservedMemBitmap == 0) {
399 gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages);
400 } else {
401 DEBUG ((
402 DEBUG_VERBOSE,
403 "%a: PlainTextAddress=0x%Lx, bits=0x%Lx, bitmap: %Lx => %Lx\n",
404 __FUNCTION__,
405 MapInfo->PlainTextAddress,
406 MapInfo->ReservedMemBitmap,
407 mReservedMemBitmap,
408 mReservedMemBitmap & ((UINT32)(~MapInfo->ReservedMemBitmap))
409 ));
410 MapInfo->PlainTextAddress = 0;
411 mReservedMemBitmap &= (UINT32)(~MapInfo->ReservedMemBitmap);
412 MapInfo->ReservedMemBitmap = 0;
413 }
414
415 return EFI_SUCCESS;
416}
417
418/**
419 * Allocate CommonBuffer from pre-allocated shared memory.
420 *
421 * @param MemoryType Memory type
422 * @param CommonBufferPages Pages of CommonBuffer
423 * @param PhysicalAddress Allocated physical address
424 * @param ReservedMemBitmap Bitmap which indicates the allocation of reserved memory
425 *
426 * @retval EFI_SUCCESS Successfully allocate the common buffer
427 * @retval Other As the error code indicates
428 */
429EFI_STATUS
430IoMmuAllocateCommonBuffer (
431 IN EFI_MEMORY_TYPE MemoryType,
432 IN UINTN CommonBufferPages,
433 OUT EFI_PHYSICAL_ADDRESS *PhysicalAddress,
434 OUT UINT32 *ReservedMemBitmap
435 )
436{
437 EFI_STATUS Status;
438
439 Status = InternalAllocateBuffer (
440 AllocateMaxAddress,
441 MemoryType,
442 CommonBufferPages,
443 ReservedMemBitmap,
444 PhysicalAddress
445 );
446 ASSERT (Status == EFI_SUCCESS);
447
448 mReservedMemBitmap |= *ReservedMemBitmap;
449
450 if (*ReservedMemBitmap != 0) {
451 *PhysicalAddress -= SIZE_4KB;
452 }
453
454 return Status;
455}
456
457/**
458 * Free CommonBuffer which is allocated by IoMmuAllocateCommonBuffer().
459 *
460 * @param CommonBufferHeader Pointer to the CommonBufferHeader
461 * @param CommonBufferPages Pages of CommonBuffer
462 *
463 * @retval EFI_SUCCESS Successfully free the common buffer
464 * @retval Other As the error code indicates
465 */
466EFI_STATUS
467IoMmuFreeCommonBuffer (
468 IN COMMON_BUFFER_HEADER *CommonBufferHeader,
469 IN UINTN CommonBufferPages
470 )
471{
472 if (!mReservedSharedMemSupported) {
473 goto LegacyFreeCommonBuffer;
474 }
475
476 if (CommonBufferHeader->ReservedMemBitmap == 0) {
477 goto LegacyFreeCommonBuffer;
478 }
479
480 DEBUG ((
481 DEBUG_VERBOSE,
482 "%a: CommonBuffer=0x%Lx, bits=0x%Lx, bitmap: %Lx => %Lx\n",
483 __FUNCTION__,
484 (UINT64)(UINTN)CommonBufferHeader + SIZE_4KB,
485 CommonBufferHeader->ReservedMemBitmap,
486 mReservedMemBitmap,
487 mReservedMemBitmap & ((UINT32)(~CommonBufferHeader->ReservedMemBitmap))
488 ));
489
490 mReservedMemBitmap &= (UINT32)(~CommonBufferHeader->ReservedMemBitmap);
491 return EFI_SUCCESS;
492
493LegacyFreeCommonBuffer:
494 return gBS->FreePages ((UINTN)CommonBufferHeader, CommonBufferPages);
495}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette