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