]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
OvmfPkg/IoMmuDxe: IoMmuUnmap(): clean up DEBUG message
[mirror_edk2.git] / OvmfPkg / IoMmuDxe / AmdSevIoMmu.c
CommitLineData
f9d129e6
BS
1/** @file\r
2\r
812568fb
LE
3 The protocol provides support to allocate, free, map and umap a DMA buffer\r
4 for bus master (e.g PciHostBridge). When SEV is enabled, the DMA operations\r
5 must be performed on unencrypted buffer hence we use a bounce buffer to map\r
6 the guest buffer into an unencrypted DMA buffer.\r
f9d129e6
BS
7\r
8 Copyright (c) 2017, AMD Inc. All rights reserved.<BR>\r
9 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
10\r
11 This program and the accompanying materials are licensed and made available\r
12 under the terms and conditions of the BSD License which accompanies this\r
13 distribution. The full text of the license may be found at\r
14 http://opensource.org/licenses/bsd-license.php\r
15\r
16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
18\r
19**/\r
20\r
21#include "AmdSevIoMmu.h"\r
22\r
d0c9afea
LE
23#define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O')\r
24\r
f9d129e6 25typedef struct {\r
d0c9afea
LE
26 UINT64 Signature;\r
27 LIST_ENTRY Link;\r
f9d129e6
BS
28 EDKII_IOMMU_OPERATION Operation;\r
29 UINTN NumberOfBytes;\r
30 UINTN NumberOfPages;\r
c7ef2ed2 31 EFI_PHYSICAL_ADDRESS CryptedAddress;\r
dc194ce3 32 EFI_PHYSICAL_ADDRESS PlainTextAddress;\r
f9d129e6
BS
33} MAP_INFO;\r
34\r
d0c9afea
LE
35//\r
36// List of MAP_INFO structures recycled by Unmap().\r
37//\r
38// Recycled MAP_INFO structures are equally good for future recycling and\r
39// freeing.\r
40//\r
41STATIC LIST_ENTRY mRecycledMapInfos = INITIALIZE_LIST_HEAD_VARIABLE (\r
42 mRecycledMapInfos\r
43 );\r
44\r
58e68140
LE
45#define COMMON_BUFFER_SIG SIGNATURE_64 ('C', 'M', 'N', 'B', 'U', 'F', 'F', 'R')\r
46\r
2ad6ba80
LE
47//\r
48// ASCII names for EDKII_IOMMU_OPERATION constants, for debug logging.\r
49//\r
50STATIC CONST CHAR8 * CONST\r
51mBusMasterOperationName[EdkiiIoMmuOperationMaximum] = {\r
52 "Read",\r
53 "Write",\r
54 "CommonBuffer",\r
55 "Read64",\r
56 "Write64",\r
57 "CommonBuffer64"\r
58};\r
59\r
58e68140
LE
60//\r
61// The following structure enables Map() and Unmap() to perform in-place\r
62// decryption and encryption, respectively, for BusMasterCommonBuffer[64]\r
63// operations, without dynamic memory allocation or release.\r
64//\r
65// Both COMMON_BUFFER_HEADER and COMMON_BUFFER_HEADER.StashBuffer are allocated\r
66// by AllocateBuffer() and released by FreeBuffer().\r
67//\r
68#pragma pack (1)\r
69typedef struct {\r
70 UINT64 Signature;\r
71\r
72 //\r
73 // Always allocated from EfiBootServicesData type memory, and always\r
74 // encrypted.\r
75 //\r
76 VOID *StashBuffer;\r
77\r
78 //\r
79 // Followed by the actual common buffer, starting at the next page.\r
80 //\r
81} COMMON_BUFFER_HEADER;\r
82#pragma pack ()\r
f9d129e6
BS
83\r
84/**\r
812568fb
LE
85 Provides the controller-specific addresses required to access system memory\r
86 from a DMA bus master. On SEV guest, the DMA operations must be performed on\r
87 shared buffer hence we allocate a bounce buffer to map the HostAddress to a\r
88 DeviceAddress. The Encryption attribute is removed from the DeviceAddress\r
89 buffer.\r
f9d129e6
BS
90\r
91 @param This The protocol instance pointer.\r
92 @param Operation Indicates if the bus master is going to read or\r
93 write to system memory.\r
812568fb
LE
94 @param HostAddress The system memory address to map to the PCI\r
95 controller.\r
f9d129e6 96 @param NumberOfBytes On input the number of bytes to map. On output\r
812568fb
LE
97 the number of bytes that were mapped.\r
98 @param DeviceAddress The resulting map address for the bus master\r
99 PCI controller to use to access the hosts\r
100 HostAddress.\r
f9d129e6
BS
101 @param Mapping A resulting value to pass to Unmap().\r
102\r
812568fb
LE
103 @retval EFI_SUCCESS The range was mapped for the returned\r
104 NumberOfBytes.\r
105 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common\r
106 buffer.\r
f9d129e6 107 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
812568fb
LE
108 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
109 lack of resources.\r
110 @retval EFI_DEVICE_ERROR The system hardware could not map the requested\r
111 address.\r
f9d129e6
BS
112\r
113**/\r
114EFI_STATUS\r
115EFIAPI\r
116IoMmuMap (\r
117 IN EDKII_IOMMU_PROTOCOL *This,\r
118 IN EDKII_IOMMU_OPERATION Operation,\r
119 IN VOID *HostAddress,\r
120 IN OUT UINTN *NumberOfBytes,\r
121 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
122 OUT VOID **Mapping\r
123 )\r
124{\r
125 EFI_STATUS Status;\r
d0c9afea 126 LIST_ENTRY *RecycledMapInfo;\r
f9d129e6 127 MAP_INFO *MapInfo;\r
f9d129e6 128 EFI_ALLOCATE_TYPE AllocateType;\r
58e68140
LE
129 COMMON_BUFFER_HEADER *CommonBufferHeader;\r
130 VOID *DecryptionSource;\r
f9d129e6 131\r
2ad6ba80
LE
132 DEBUG ((\r
133 DEBUG_VERBOSE,\r
134 "%a: Operation=%a Host=0x%p Bytes=0x%Lx\n",\r
135 __FUNCTION__,\r
136 ((Operation >= 0 &&\r
137 Operation < ARRAY_SIZE (mBusMasterOperationName)) ?\r
138 mBusMasterOperationName[Operation] :\r
139 "Invalid"),\r
140 HostAddress,\r
141 (UINT64)((NumberOfBytes == NULL) ? 0 : *NumberOfBytes)\r
142 ));\r
143\r
f9d129e6
BS
144 if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||\r
145 Mapping == NULL) {\r
146 return EFI_INVALID_PARAMETER;\r
147 }\r
148\r
f9d129e6
BS
149 //\r
150 // Allocate a MAP_INFO structure to remember the mapping when Unmap() is\r
151 // called later.\r
152 //\r
d0c9afea
LE
153 RecycledMapInfo = GetFirstNode (&mRecycledMapInfos);\r
154 if (RecycledMapInfo == &mRecycledMapInfos) {\r
155 //\r
156 // No recycled MAP_INFO structure, allocate a new one.\r
157 //\r
158 MapInfo = AllocatePool (sizeof (MAP_INFO));\r
159 if (MapInfo == NULL) {\r
160 Status = EFI_OUT_OF_RESOURCES;\r
161 goto Failed;\r
162 }\r
163 } else {\r
164 MapInfo = CR (RecycledMapInfo, MAP_INFO, Link, MAP_INFO_SIG);\r
165 RemoveEntryList (RecycledMapInfo);\r
f9d129e6
BS
166 }\r
167\r
168 //\r
e130229c 169 // Initialize the MAP_INFO structure, except the PlainTextAddress field\r
f9d129e6 170 //\r
d0c9afea
LE
171 ZeroMem (&MapInfo->Link, sizeof MapInfo->Link);\r
172 MapInfo->Signature = MAP_INFO_SIG;\r
f9d129e6
BS
173 MapInfo->Operation = Operation;\r
174 MapInfo->NumberOfBytes = *NumberOfBytes;\r
175 MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);\r
e130229c 176 MapInfo->CryptedAddress = (UINTN)HostAddress;\r
f9d129e6
BS
177\r
178 //\r
e130229c 179 // In the switch statement below, we point "MapInfo->PlainTextAddress" to the\r
58e68140 180 // plaintext buffer, according to Operation. We also set "DecryptionSource".\r
e130229c
LE
181 //\r
182 MapInfo->PlainTextAddress = MAX_ADDRESS;\r
183 AllocateType = AllocateAnyPages;\r
58e68140 184 DecryptionSource = (VOID *)(UINTN)MapInfo->CryptedAddress;\r
e130229c
LE
185 switch (Operation) {\r
186 //\r
187 // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer\r
188 // is necessary regardless of whether the original (crypted) buffer crosses\r
189 // the 4GB limit or not -- we have to allocate a separate plaintext buffer.\r
190 // The only variable is whether the plaintext buffer should be under 4GB.\r
f9d129e6 191 //\r
e130229c
LE
192 case EdkiiIoMmuOperationBusMasterRead:\r
193 case EdkiiIoMmuOperationBusMasterWrite:\r
194 MapInfo->PlainTextAddress = BASE_4GB - 1;\r
195 AllocateType = AllocateMaxAddress;\r
196 //\r
197 // fall through\r
198 //\r
199 case EdkiiIoMmuOperationBusMasterRead64:\r
200 case EdkiiIoMmuOperationBusMasterWrite64:\r
201 //\r
202 // Allocate the implicit plaintext bounce buffer.\r
203 //\r
204 Status = gBS->AllocatePages (\r
205 AllocateType,\r
206 EfiBootServicesData,\r
207 MapInfo->NumberOfPages,\r
208 &MapInfo->PlainTextAddress\r
209 );\r
210 if (EFI_ERROR (Status)) {\r
211 goto FreeMapInfo;\r
212 }\r
213 break;\r
214\r
215 //\r
58e68140
LE
216 // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer and a\r
217 // stash buffer (for in-place decryption) have been allocated already, with\r
218 // AllocateBuffer(). We only check whether the address of the to-be-plaintext\r
219 // buffer is low enough for the requested operation.\r
e130229c
LE
220 //\r
221 case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
222 if ((MapInfo->CryptedAddress > BASE_4GB) ||\r
223 (EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) >\r
224 BASE_4GB - MapInfo->CryptedAddress)) {\r
225 //\r
226 // CommonBuffer operations cannot be remapped. If the common buffer is\r
227 // above 4GB, then it is not possible to generate a mapping, so return an\r
228 // error.\r
229 //\r
230 Status = EFI_UNSUPPORTED;\r
231 goto FreeMapInfo;\r
232 }\r
233 //\r
234 // fall through\r
235 //\r
236 case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
237 //\r
58e68140 238 // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer().\r
e130229c
LE
239 //\r
240 MapInfo->PlainTextAddress = MapInfo->CryptedAddress;\r
e130229c 241 //\r
58e68140
LE
242 // Stash the crypted data.\r
243 //\r
244 CommonBufferHeader = (COMMON_BUFFER_HEADER *)(\r
245 (UINTN)MapInfo->CryptedAddress - EFI_PAGE_SIZE\r
246 );\r
247 ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);\r
248 CopyMem (\r
249 CommonBufferHeader->StashBuffer,\r
250 (VOID *)(UINTN)MapInfo->CryptedAddress,\r
251 MapInfo->NumberOfBytes\r
252 );\r
253 //\r
254 // Point "DecryptionSource" to the stash buffer so that we decrypt\r
255 // it to the original location, after the switch statement.\r
e130229c 256 //\r
58e68140
LE
257 DecryptionSource = CommonBufferHeader->StashBuffer;\r
258 break;\r
e130229c
LE
259\r
260 default:\r
261 //\r
262 // Operation is invalid\r
263 //\r
264 Status = EFI_INVALID_PARAMETER;\r
265 goto FreeMapInfo;\r
f9d129e6
BS
266 }\r
267\r
268 //\r
e130229c 269 // Clear the memory encryption mask on the plaintext buffer.\r
f9d129e6 270 //\r
812568fb
LE
271 Status = MemEncryptSevClearPageEncMask (\r
272 0,\r
dc194ce3 273 MapInfo->PlainTextAddress,\r
812568fb
LE
274 MapInfo->NumberOfPages,\r
275 TRUE\r
276 );\r
f1658838
LE
277 ASSERT_EFI_ERROR (Status);\r
278 if (EFI_ERROR (Status)) {\r
279 CpuDeadLoop ();\r
280 }\r
f9d129e6
BS
281\r
282 //\r
283 // If this is a read operation from the Bus Master's point of view,\r
284 // then copy the contents of the real buffer into the mapped buffer\r
285 // so the Bus Master can read the contents of the real buffer.\r
286 //\r
58e68140
LE
287 // For BusMasterCommonBuffer[64] operations, the CopyMem() below will decrypt\r
288 // the original data (from the stash buffer) back to the original location.\r
289 //\r
f9d129e6 290 if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
58e68140
LE
291 Operation == EdkiiIoMmuOperationBusMasterRead64 ||\r
292 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
293 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
f9d129e6 294 CopyMem (\r
dc194ce3 295 (VOID *) (UINTN) MapInfo->PlainTextAddress,\r
58e68140 296 DecryptionSource,\r
f9d129e6
BS
297 MapInfo->NumberOfBytes\r
298 );\r
299 }\r
300\r
301 //\r
e130229c 302 // Populate output parameters.\r
f9d129e6 303 //\r
dc194ce3 304 *DeviceAddress = MapInfo->PlainTextAddress;\r
f9d129e6
BS
305 *Mapping = MapInfo;\r
306\r
812568fb
LE
307 DEBUG ((\r
308 DEBUG_VERBOSE,\r
2ad6ba80 309 "%a: Mapping=0x%p Device(PlainText)=0x%Lx Crypted=0x%Lx Pages=0x%Lx\n",\r
812568fb 310 __FUNCTION__,\r
2ad6ba80 311 MapInfo,\r
dc194ce3 312 MapInfo->PlainTextAddress,\r
c7ef2ed2 313 MapInfo->CryptedAddress,\r
2ad6ba80 314 (UINT64)MapInfo->NumberOfPages\r
812568fb 315 ));\r
f9d129e6
BS
316\r
317 return EFI_SUCCESS;\r
e130229c
LE
318\r
319FreeMapInfo:\r
320 FreePool (MapInfo);\r
321\r
322Failed:\r
323 *NumberOfBytes = 0;\r
324 return Status;\r
f9d129e6
BS
325}\r
326\r
327/**\r
328 Completes the Map() operation and releases any corresponding resources.\r
329\r
330 @param This The protocol instance pointer.\r
331 @param Mapping The mapping value returned from Map().\r
332\r
333 @retval EFI_SUCCESS The range was unmapped.\r
812568fb
LE
334 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by\r
335 Map().\r
336 @retval EFI_DEVICE_ERROR The data was not committed to the target system\r
337 memory.\r
f9d129e6
BS
338**/\r
339EFI_STATUS\r
340EFIAPI\r
341IoMmuUnmap (\r
342 IN EDKII_IOMMU_PROTOCOL *This,\r
343 IN VOID *Mapping\r
344 )\r
345{\r
346 MAP_INFO *MapInfo;\r
347 EFI_STATUS Status;\r
58e68140
LE
348 COMMON_BUFFER_HEADER *CommonBufferHeader;\r
349 VOID *EncryptionTarget;\r
f9d129e6 350\r
a1d6a9dc
LE
351 DEBUG ((DEBUG_VERBOSE, "%a: Mapping=0x%p\n", __FUNCTION__, Mapping));\r
352\r
f9d129e6
BS
353 if (Mapping == NULL) {\r
354 return EFI_INVALID_PARAMETER;\r
355 }\r
356\r
58e68140
LE
357 MapInfo = (MAP_INFO *)Mapping;\r
358\r
f9d129e6 359 //\r
58e68140 360 // set CommonBufferHeader to suppress incorrect compiler/analyzer warnings\r
f9d129e6 361 //\r
58e68140 362 CommonBufferHeader = NULL;\r
f9d129e6
BS
363\r
364 //\r
58e68140
LE
365 // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations\r
366 // we have to encrypt the results, ultimately to the original place (i.e.,\r
367 // "MapInfo->CryptedAddress").\r
f9d129e6 368 //\r
58e68140
LE
369 // For BusMasterCommonBuffer[64] operations however, this encryption has to\r
370 // land in-place, so divert the encryption to the stash buffer first.\r
371 //\r
372 EncryptionTarget = (VOID *)(UINTN)MapInfo->CryptedAddress;\r
373\r
374 switch (MapInfo->Operation) {\r
375 case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
376 case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
377 ASSERT (MapInfo->PlainTextAddress == MapInfo->CryptedAddress);\r
378\r
379 CommonBufferHeader = (COMMON_BUFFER_HEADER *)(\r
380 (UINTN)MapInfo->PlainTextAddress - EFI_PAGE_SIZE\r
381 );\r
382 ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);\r
383 EncryptionTarget = CommonBufferHeader->StashBuffer;\r
384 //\r
385 // fall through\r
386 //\r
387\r
388 case EdkiiIoMmuOperationBusMasterWrite:\r
389 case EdkiiIoMmuOperationBusMasterWrite64:\r
f9d129e6 390 CopyMem (\r
58e68140 391 EncryptionTarget,\r
dc194ce3 392 (VOID *) (UINTN) MapInfo->PlainTextAddress,\r
f9d129e6
BS
393 MapInfo->NumberOfBytes\r
394 );\r
58e68140
LE
395 break;\r
396\r
397 default:\r
398 //\r
399 // nothing to encrypt after BusMasterRead[64] operations\r
400 //\r
401 break;\r
f9d129e6
BS
402 }\r
403\r
f9d129e6 404 //\r
58e68140
LE
405 // Restore the memory encryption mask on the area we used to hold the\r
406 // plaintext.\r
f9d129e6 407 //\r
812568fb
LE
408 Status = MemEncryptSevSetPageEncMask (\r
409 0,\r
dc194ce3 410 MapInfo->PlainTextAddress,\r
812568fb
LE
411 MapInfo->NumberOfPages,\r
412 TRUE\r
413 );\r
f1658838
LE
414 ASSERT_EFI_ERROR (Status);\r
415 if (EFI_ERROR (Status)) {\r
416 CpuDeadLoop ();\r
417 }\r
f9d129e6
BS
418\r
419 //\r
58e68140
LE
420 // For BusMasterCommonBuffer[64] operations, copy the stashed data to the\r
421 // original (now encrypted) location.\r
422 //\r
423 // For all other operations, fill the late bounce buffer (which existed as\r
424 // plaintext at some point) with zeros, and then release it.\r
425 //\r
426 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
427 MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
428 CopyMem (\r
429 (VOID *)(UINTN)MapInfo->CryptedAddress,\r
430 CommonBufferHeader->StashBuffer,\r
431 MapInfo->NumberOfBytes\r
432 );\r
d0c9afea
LE
433\r
434 //\r
435 // Recycle the MAP_INFO structure.\r
436 //\r
437 InsertTailList (&mRecycledMapInfos, &MapInfo->Link);\r
58e68140
LE
438 } else {\r
439 ZeroMem (\r
440 (VOID *)(UINTN)MapInfo->PlainTextAddress,\r
441 EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages)\r
442 );\r
443 gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages);\r
d0c9afea
LE
444\r
445 //\r
446 // Free the MAP_INFO structure.\r
447 //\r
448 FreePool (MapInfo);\r
58e68140
LE
449 }\r
450\r
f9d129e6
BS
451 return EFI_SUCCESS;\r
452}\r
453\r
454/**\r
455 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
456 OperationBusMasterCommonBuffer64 mapping.\r
457\r
458 @param This The protocol instance pointer.\r
459 @param Type This parameter is not used and must be ignored.\r
812568fb
LE
460 @param MemoryType The type of memory to allocate,\r
461 EfiBootServicesData or EfiRuntimeServicesData.\r
f9d129e6 462 @param Pages The number of pages to allocate.\r
812568fb
LE
463 @param HostAddress A pointer to store the base system memory\r
464 address of the allocated range.\r
465 @param Attributes The requested bit mask of attributes for the\r
466 allocated range.\r
f9d129e6
BS
467\r
468 @retval EFI_SUCCESS The requested memory pages were allocated.\r
812568fb
LE
469 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal\r
470 attribute bits are MEMORY_WRITE_COMBINE and\r
471 MEMORY_CACHED.\r
f9d129e6
BS
472 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
473 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
474\r
475**/\r
476EFI_STATUS\r
477EFIAPI\r
478IoMmuAllocateBuffer (\r
479 IN EDKII_IOMMU_PROTOCOL *This,\r
480 IN EFI_ALLOCATE_TYPE Type,\r
481 IN EFI_MEMORY_TYPE MemoryType,\r
482 IN UINTN Pages,\r
483 IN OUT VOID **HostAddress,\r
484 IN UINT64 Attributes\r
485 )\r
486{\r
487 EFI_STATUS Status;\r
488 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
58e68140
LE
489 VOID *StashBuffer;\r
490 UINTN CommonBufferPages;\r
491 COMMON_BUFFER_HEADER *CommonBufferHeader;\r
f9d129e6
BS
492\r
493 //\r
494 // Validate Attributes\r
495 //\r
496 if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {\r
497 return EFI_UNSUPPORTED;\r
498 }\r
499\r
500 //\r
501 // Check for invalid inputs\r
502 //\r
503 if (HostAddress == NULL) {\r
504 return EFI_INVALID_PARAMETER;\r
505 }\r
506\r
507 //\r
508 // The only valid memory types are EfiBootServicesData and\r
509 // EfiRuntimeServicesData\r
510 //\r
511 if (MemoryType != EfiBootServicesData &&\r
512 MemoryType != EfiRuntimeServicesData) {\r
513 return EFI_INVALID_PARAMETER;\r
514 }\r
515\r
58e68140
LE
516 //\r
517 // We'll need a header page for the COMMON_BUFFER_HEADER structure.\r
518 //\r
519 if (Pages > MAX_UINTN - 1) {\r
520 return EFI_OUT_OF_RESOURCES;\r
521 }\r
522 CommonBufferPages = Pages + 1;\r
523\r
524 //\r
525 // Allocate the stash in EfiBootServicesData type memory.\r
526 //\r
527 // Map() will temporarily save encrypted data in the stash for\r
528 // BusMasterCommonBuffer[64] operations, so the data can be decrypted to the\r
529 // original location.\r
530 //\r
531 // Unmap() will temporarily save plaintext data in the stash for\r
532 // BusMasterCommonBuffer[64] operations, so the data can be encrypted to the\r
533 // original location.\r
534 //\r
535 // StashBuffer always resides in encrypted memory.\r
536 //\r
537 StashBuffer = AllocatePages (Pages);\r
538 if (StashBuffer == NULL) {\r
539 return EFI_OUT_OF_RESOURCES;\r
540 }\r
541\r
f9d129e6
BS
542 PhysicalAddress = (UINTN)-1;\r
543 if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
544 //\r
545 // Limit allocations to memory below 4GB\r
546 //\r
547 PhysicalAddress = SIZE_4GB - 1;\r
548 }\r
549 Status = gBS->AllocatePages (\r
550 AllocateMaxAddress,\r
551 MemoryType,\r
58e68140 552 CommonBufferPages,\r
f9d129e6
BS
553 &PhysicalAddress\r
554 );\r
58e68140
LE
555 if (EFI_ERROR (Status)) {\r
556 goto FreeStashBuffer;\r
f9d129e6
BS
557 }\r
558\r
58e68140
LE
559 CommonBufferHeader = (VOID *)(UINTN)PhysicalAddress;\r
560 PhysicalAddress += EFI_PAGE_SIZE;\r
561\r
562 CommonBufferHeader->Signature = COMMON_BUFFER_SIG;\r
563 CommonBufferHeader->StashBuffer = StashBuffer;\r
564\r
565 *HostAddress = (VOID *)(UINTN)PhysicalAddress;\r
566\r
812568fb
LE
567 DEBUG ((\r
568 DEBUG_VERBOSE,\r
569 "%a Address 0x%Lx Pages 0x%Lx\n",\r
570 __FUNCTION__,\r
571 PhysicalAddress,\r
60aa3a0e 572 (UINT64)Pages\r
812568fb 573 ));\r
58e68140
LE
574 return EFI_SUCCESS;\r
575\r
576FreeStashBuffer:\r
577 FreePages (StashBuffer, Pages);\r
f9d129e6
BS
578 return Status;\r
579}\r
580\r
581/**\r
582 Frees memory that was allocated with AllocateBuffer().\r
583\r
584 @param This The protocol instance pointer.\r
585 @param Pages The number of pages to free.\r
812568fb
LE
586 @param HostAddress The base system memory address of the allocated\r
587 range.\r
f9d129e6
BS
588\r
589 @retval EFI_SUCCESS The requested memory pages were freed.\r
812568fb
LE
590 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and\r
591 Pages was not allocated with AllocateBuffer().\r
f9d129e6
BS
592\r
593**/\r
594EFI_STATUS\r
595EFIAPI\r
596IoMmuFreeBuffer (\r
597 IN EDKII_IOMMU_PROTOCOL *This,\r
598 IN UINTN Pages,\r
599 IN VOID *HostAddress\r
600 )\r
601{\r
58e68140
LE
602 UINTN CommonBufferPages;\r
603 COMMON_BUFFER_HEADER *CommonBufferHeader;\r
604\r
605 CommonBufferPages = Pages + 1;\r
606 CommonBufferHeader = (COMMON_BUFFER_HEADER *)(\r
607 (UINTN)HostAddress - EFI_PAGE_SIZE\r
608 );\r
f9d129e6
BS
609\r
610 //\r
58e68140 611 // Check the signature.\r
f9d129e6 612 //\r
58e68140
LE
613 ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);\r
614 if (CommonBufferHeader->Signature != COMMON_BUFFER_SIG) {\r
615 return EFI_INVALID_PARAMETER;\r
616 }\r
617\r
618 //\r
619 // Free the stash buffer. This buffer was always encrypted, so no need to\r
620 // zero it.\r
621 //\r
622 FreePages (CommonBufferHeader->StashBuffer, Pages);\r
f9d129e6 623\r
812568fb
LE
624 DEBUG ((\r
625 DEBUG_VERBOSE,\r
626 "%a Address 0x%Lx Pages 0x%Lx\n",\r
627 __FUNCTION__,\r
60aa3a0e
LE
628 (UINT64)(UINTN)HostAddress,\r
629 (UINT64)Pages\r
812568fb 630 ));\r
58e68140
LE
631\r
632 //\r
633 // Release the common buffer itself. Unmap() has re-encrypted it in-place, so\r
634 // no need to zero it.\r
635 //\r
636 return gBS->FreePages ((UINTN)CommonBufferHeader, CommonBufferPages);\r
f9d129e6
BS
637}\r
638\r
639\r
640/**\r
641 Set IOMMU attribute for a system memory.\r
642\r
643 If the IOMMU protocol exists, the system memory cannot be used\r
644 for DMA by default.\r
645\r
646 When a device requests a DMA access for a system memory,\r
647 the device driver need use SetAttribute() to update the IOMMU\r
648 attribute to request DMA access (read and/or write).\r
649\r
650 The DeviceHandle is used to identify which device submits the request.\r
812568fb
LE
651 The IOMMU implementation need translate the device path to an IOMMU device\r
652 ID, and set IOMMU hardware register accordingly.\r
f9d129e6
BS
653 1) DeviceHandle can be a standard PCI device.\r
654 The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.\r
655 The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.\r
812568fb
LE
656 The memory for BusMasterCommonBuffer need set\r
657 EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.\r
658 After the memory is used, the memory need set 0 to keep it being\r
659 protected.\r
f9d129e6 660 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).\r
812568fb
LE
661 The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or\r
662 EDKII_IOMMU_ACCESS_WRITE.\r
f9d129e6
BS
663\r
664 @param[in] This The protocol instance pointer.\r
812568fb
LE
665 @param[in] DeviceHandle The device who initiates the DMA access\r
666 request.\r
f9d129e6
BS
667 @param[in] Mapping The mapping value returned from Map().\r
668 @param[in] IoMmuAccess The IOMMU access.\r
669\r
812568fb
LE
670 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range\r
671 specified by DeviceAddress and Length.\r
f9d129e6 672 @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.\r
812568fb
LE
673 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by\r
674 Map().\r
675 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination\r
676 of access.\r
f9d129e6 677 @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.\r
812568fb
LE
678 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported\r
679 by the IOMMU.\r
680 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range\r
681 specified by Mapping.\r
682 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
683 modify the IOMMU access.\r
684 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while\r
685 attempting the operation.\r
f9d129e6
BS
686\r
687**/\r
688EFI_STATUS\r
689EFIAPI\r
690IoMmuSetAttribute (\r
691 IN EDKII_IOMMU_PROTOCOL *This,\r
692 IN EFI_HANDLE DeviceHandle,\r
693 IN VOID *Mapping,\r
694 IN UINT64 IoMmuAccess\r
695 )\r
696{\r
697 return EFI_UNSUPPORTED;\r
698}\r
699\r
700EDKII_IOMMU_PROTOCOL mAmdSev = {\r
701 EDKII_IOMMU_PROTOCOL_REVISION,\r
702 IoMmuSetAttribute,\r
703 IoMmuMap,\r
704 IoMmuUnmap,\r
705 IoMmuAllocateBuffer,\r
706 IoMmuFreeBuffer,\r
707};\r
708\r
709/**\r
710 Initialize Iommu Protocol.\r
711\r
712**/\r
db125079 713EFI_STATUS\r
f9d129e6
BS
714EFIAPI\r
715AmdSevInstallIoMmuProtocol (\r
716 VOID\r
717 )\r
718{\r
719 EFI_STATUS Status;\r
720 EFI_HANDLE Handle;\r
721\r
722 Handle = NULL;\r
723 Status = gBS->InstallMultipleProtocolInterfaces (\r
724 &Handle,\r
725 &gEdkiiIoMmuProtocolGuid, &mAmdSev,\r
726 NULL\r
727 );\r
db125079 728 return Status;\r
f9d129e6 729}\r