]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
0a85ee6559e799a1b8cb1a4c235f86239da7a281
[mirror_edk2.git] / OvmfPkg / IoMmuDxe / AmdSevIoMmu.c
1 /** @file
2
3 The protocol provides support to allocate, free, map and umap a DMA buffer
4 for bus master (e.g PciHostBridge). When SEV is enabled, the DMA operations
5 must be performed on unencrypted buffer hence we use a bounce buffer to map
6 the guest buffer into an unencrypted DMA buffer.
7
8 Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
9 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
10
11 This program and the accompanying materials are licensed and made available
12 under the terms and conditions of the BSD License which accompanies this
13 distribution. The full text of the license may be found at
14 http://opensource.org/licenses/bsd-license.php
15
16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18
19 **/
20
21 #include "AmdSevIoMmu.h"
22
23 typedef struct {
24 EDKII_IOMMU_OPERATION Operation;
25 UINTN NumberOfBytes;
26 UINTN NumberOfPages;
27 EFI_PHYSICAL_ADDRESS CryptedAddress;
28 EFI_PHYSICAL_ADDRESS PlainTextAddress;
29 } MAP_INFO;
30
31 #define NO_MAPPING (VOID *) (UINTN) -1
32
33 /**
34 Provides the controller-specific addresses required to access system memory
35 from a DMA bus master. On SEV guest, the DMA operations must be performed on
36 shared buffer hence we allocate a bounce buffer to map the HostAddress to a
37 DeviceAddress. The Encryption attribute is removed from the DeviceAddress
38 buffer.
39
40 @param This The protocol instance pointer.
41 @param Operation Indicates if the bus master is going to read or
42 write to system memory.
43 @param HostAddress The system memory address to map to the PCI
44 controller.
45 @param NumberOfBytes On input the number of bytes to map. On output
46 the number of bytes that were mapped.
47 @param DeviceAddress The resulting map address for the bus master
48 PCI controller to use to access the hosts
49 HostAddress.
50 @param Mapping A resulting value to pass to Unmap().
51
52 @retval EFI_SUCCESS The range was mapped for the returned
53 NumberOfBytes.
54 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common
55 buffer.
56 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
57 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
58 lack of resources.
59 @retval EFI_DEVICE_ERROR The system hardware could not map the requested
60 address.
61
62 **/
63 EFI_STATUS
64 EFIAPI
65 IoMmuMap (
66 IN EDKII_IOMMU_PROTOCOL *This,
67 IN EDKII_IOMMU_OPERATION Operation,
68 IN VOID *HostAddress,
69 IN OUT UINTN *NumberOfBytes,
70 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
71 OUT VOID **Mapping
72 )
73 {
74 EFI_STATUS Status;
75 MAP_INFO *MapInfo;
76 EFI_ALLOCATE_TYPE AllocateType;
77
78 if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||
79 Mapping == NULL) {
80 return EFI_INVALID_PARAMETER;
81 }
82
83 //
84 // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
85 // called later.
86 //
87 MapInfo = AllocatePool (sizeof (MAP_INFO));
88 if (MapInfo == NULL) {
89 Status = EFI_OUT_OF_RESOURCES;
90 goto Failed;
91 }
92
93 //
94 // Initialize the MAP_INFO structure, except the PlainTextAddress field
95 //
96 MapInfo->Operation = Operation;
97 MapInfo->NumberOfBytes = *NumberOfBytes;
98 MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);
99 MapInfo->CryptedAddress = (UINTN)HostAddress;
100
101 //
102 // In the switch statement below, we point "MapInfo->PlainTextAddress" to the
103 // plaintext buffer, according to Operation.
104 //
105 MapInfo->PlainTextAddress = MAX_ADDRESS;
106 AllocateType = AllocateAnyPages;
107 switch (Operation) {
108 //
109 // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer
110 // is necessary regardless of whether the original (crypted) buffer crosses
111 // the 4GB limit or not -- we have to allocate a separate plaintext buffer.
112 // The only variable is whether the plaintext buffer should be under 4GB.
113 //
114 case EdkiiIoMmuOperationBusMasterRead:
115 case EdkiiIoMmuOperationBusMasterWrite:
116 MapInfo->PlainTextAddress = BASE_4GB - 1;
117 AllocateType = AllocateMaxAddress;
118 //
119 // fall through
120 //
121 case EdkiiIoMmuOperationBusMasterRead64:
122 case EdkiiIoMmuOperationBusMasterWrite64:
123 //
124 // Allocate the implicit plaintext bounce buffer.
125 //
126 Status = gBS->AllocatePages (
127 AllocateType,
128 EfiBootServicesData,
129 MapInfo->NumberOfPages,
130 &MapInfo->PlainTextAddress
131 );
132 if (EFI_ERROR (Status)) {
133 goto FreeMapInfo;
134 }
135 break;
136
137 //
138 // For BusMasterCommonBuffer[64] operations, a plaintext buffer has been
139 // allocated already, with AllocateBuffer(). We only check whether the
140 // address is low enough for the requested operation.
141 //
142 case EdkiiIoMmuOperationBusMasterCommonBuffer:
143 if ((MapInfo->CryptedAddress > BASE_4GB) ||
144 (EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) >
145 BASE_4GB - MapInfo->CryptedAddress)) {
146 //
147 // CommonBuffer operations cannot be remapped. If the common buffer is
148 // above 4GB, then it is not possible to generate a mapping, so return an
149 // error.
150 //
151 Status = EFI_UNSUPPORTED;
152 goto FreeMapInfo;
153 }
154 //
155 // fall through
156 //
157 case EdkiiIoMmuOperationBusMasterCommonBuffer64:
158 //
159 // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer(),
160 // and it is already decrypted.
161 //
162 MapInfo->PlainTextAddress = MapInfo->CryptedAddress;
163
164 //
165 // Therefore no mapping is necessary.
166 //
167 *DeviceAddress = MapInfo->PlainTextAddress;
168 *Mapping = NO_MAPPING;
169 FreePool (MapInfo);
170 return EFI_SUCCESS;
171
172 default:
173 //
174 // Operation is invalid
175 //
176 Status = EFI_INVALID_PARAMETER;
177 goto FreeMapInfo;
178 }
179
180 //
181 // Clear the memory encryption mask on the plaintext buffer.
182 //
183 Status = MemEncryptSevClearPageEncMask (
184 0,
185 MapInfo->PlainTextAddress,
186 MapInfo->NumberOfPages,
187 TRUE
188 );
189 ASSERT_EFI_ERROR(Status);
190
191 //
192 // If this is a read operation from the Bus Master's point of view,
193 // then copy the contents of the real buffer into the mapped buffer
194 // so the Bus Master can read the contents of the real buffer.
195 //
196 if (Operation == EdkiiIoMmuOperationBusMasterRead ||
197 Operation == EdkiiIoMmuOperationBusMasterRead64) {
198 CopyMem (
199 (VOID *) (UINTN) MapInfo->PlainTextAddress,
200 (VOID *) (UINTN) MapInfo->CryptedAddress,
201 MapInfo->NumberOfBytes
202 );
203 }
204
205 //
206 // Populate output parameters.
207 //
208 *DeviceAddress = MapInfo->PlainTextAddress;
209 *Mapping = MapInfo;
210
211 DEBUG ((
212 DEBUG_VERBOSE,
213 "%a PlainText 0x%Lx Crypted 0x%Lx Pages 0x%Lx Bytes 0x%Lx\n",
214 __FUNCTION__,
215 MapInfo->PlainTextAddress,
216 MapInfo->CryptedAddress,
217 (UINT64)MapInfo->NumberOfPages,
218 (UINT64)MapInfo->NumberOfBytes
219 ));
220
221 return EFI_SUCCESS;
222
223 FreeMapInfo:
224 FreePool (MapInfo);
225
226 Failed:
227 *NumberOfBytes = 0;
228 return Status;
229 }
230
231 /**
232 Completes the Map() operation and releases any corresponding resources.
233
234 @param This The protocol instance pointer.
235 @param Mapping The mapping value returned from Map().
236
237 @retval EFI_SUCCESS The range was unmapped.
238 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
239 Map().
240 @retval EFI_DEVICE_ERROR The data was not committed to the target system
241 memory.
242 **/
243 EFI_STATUS
244 EFIAPI
245 IoMmuUnmap (
246 IN EDKII_IOMMU_PROTOCOL *This,
247 IN VOID *Mapping
248 )
249 {
250 MAP_INFO *MapInfo;
251 EFI_STATUS Status;
252
253 if (Mapping == NULL) {
254 return EFI_INVALID_PARAMETER;
255 }
256
257 //
258 // See if the Map() operation associated with this Unmap() required a mapping
259 // buffer. If a mapping buffer was not required, then this function simply
260 // buffer. If a mapping buffer was not required, then this function simply
261 //
262 if (Mapping == NO_MAPPING) {
263 return EFI_SUCCESS;
264 }
265
266 MapInfo = (MAP_INFO *)Mapping;
267
268 //
269 // If this is a write operation from the Bus Master's point of view,
270 // then copy the contents of the mapped buffer into the real buffer
271 // so the processor can read the contents of the real buffer.
272 //
273 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||
274 MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {
275 CopyMem (
276 (VOID *) (UINTN) MapInfo->CryptedAddress,
277 (VOID *) (UINTN) MapInfo->PlainTextAddress,
278 MapInfo->NumberOfBytes
279 );
280 }
281
282 DEBUG ((
283 DEBUG_VERBOSE,
284 "%a PlainText 0x%Lx Crypted 0x%Lx Pages 0x%Lx Bytes 0x%Lx\n",
285 __FUNCTION__,
286 MapInfo->PlainTextAddress,
287 MapInfo->CryptedAddress,
288 (UINT64)MapInfo->NumberOfPages,
289 (UINT64)MapInfo->NumberOfBytes
290 ));
291 //
292 // Restore the memory encryption mask
293 //
294 Status = MemEncryptSevSetPageEncMask (
295 0,
296 MapInfo->PlainTextAddress,
297 MapInfo->NumberOfPages,
298 TRUE
299 );
300 ASSERT_EFI_ERROR(Status);
301 ZeroMem (
302 (VOID*)(UINTN)MapInfo->PlainTextAddress,
303 EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages)
304 );
305
306 //
307 // Free the mapped buffer and the MAP_INFO structure.
308 //
309 gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages);
310 FreePool (Mapping);
311 return EFI_SUCCESS;
312 }
313
314 /**
315 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
316 OperationBusMasterCommonBuffer64 mapping.
317
318 @param This The protocol instance pointer.
319 @param Type This parameter is not used and must be ignored.
320 @param MemoryType The type of memory to allocate,
321 EfiBootServicesData or EfiRuntimeServicesData.
322 @param Pages The number of pages to allocate.
323 @param HostAddress A pointer to store the base system memory
324 address of the allocated range.
325 @param Attributes The requested bit mask of attributes for the
326 allocated range.
327
328 @retval EFI_SUCCESS The requested memory pages were allocated.
329 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
330 attribute bits are MEMORY_WRITE_COMBINE and
331 MEMORY_CACHED.
332 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
333 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
334
335 **/
336 EFI_STATUS
337 EFIAPI
338 IoMmuAllocateBuffer (
339 IN EDKII_IOMMU_PROTOCOL *This,
340 IN EFI_ALLOCATE_TYPE Type,
341 IN EFI_MEMORY_TYPE MemoryType,
342 IN UINTN Pages,
343 IN OUT VOID **HostAddress,
344 IN UINT64 Attributes
345 )
346 {
347 EFI_STATUS Status;
348 EFI_PHYSICAL_ADDRESS PhysicalAddress;
349
350 //
351 // Validate Attributes
352 //
353 if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
354 return EFI_UNSUPPORTED;
355 }
356
357 //
358 // Check for invalid inputs
359 //
360 if (HostAddress == NULL) {
361 return EFI_INVALID_PARAMETER;
362 }
363
364 //
365 // The only valid memory types are EfiBootServicesData and
366 // EfiRuntimeServicesData
367 //
368 if (MemoryType != EfiBootServicesData &&
369 MemoryType != EfiRuntimeServicesData) {
370 return EFI_INVALID_PARAMETER;
371 }
372
373 PhysicalAddress = (UINTN)-1;
374 if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
375 //
376 // Limit allocations to memory below 4GB
377 //
378 PhysicalAddress = SIZE_4GB - 1;
379 }
380 Status = gBS->AllocatePages (
381 AllocateMaxAddress,
382 MemoryType,
383 Pages,
384 &PhysicalAddress
385 );
386 if (!EFI_ERROR (Status)) {
387 *HostAddress = (VOID *) (UINTN) PhysicalAddress;
388
389 //
390 // Clear memory encryption mask
391 //
392 Status = MemEncryptSevClearPageEncMask (0, PhysicalAddress, Pages, TRUE);
393 ASSERT_EFI_ERROR(Status);
394 }
395
396 DEBUG ((
397 DEBUG_VERBOSE,
398 "%a Address 0x%Lx Pages 0x%Lx\n",
399 __FUNCTION__,
400 PhysicalAddress,
401 (UINT64)Pages
402 ));
403 return Status;
404 }
405
406 /**
407 Frees memory that was allocated with AllocateBuffer().
408
409 @param This The protocol instance pointer.
410 @param Pages The number of pages to free.
411 @param HostAddress The base system memory address of the allocated
412 range.
413
414 @retval EFI_SUCCESS The requested memory pages were freed.
415 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
416 Pages was not allocated with AllocateBuffer().
417
418 **/
419 EFI_STATUS
420 EFIAPI
421 IoMmuFreeBuffer (
422 IN EDKII_IOMMU_PROTOCOL *This,
423 IN UINTN Pages,
424 IN VOID *HostAddress
425 )
426 {
427 EFI_STATUS Status;
428
429 //
430 // Set memory encryption mask
431 //
432 Status = MemEncryptSevSetPageEncMask (
433 0,
434 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
435 Pages,
436 TRUE
437 );
438 ASSERT_EFI_ERROR(Status);
439 ZeroMem (HostAddress, EFI_PAGES_TO_SIZE (Pages));
440
441 DEBUG ((
442 DEBUG_VERBOSE,
443 "%a Address 0x%Lx Pages 0x%Lx\n",
444 __FUNCTION__,
445 (UINT64)(UINTN)HostAddress,
446 (UINT64)Pages
447 ));
448 return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);
449 }
450
451
452 /**
453 Set IOMMU attribute for a system memory.
454
455 If the IOMMU protocol exists, the system memory cannot be used
456 for DMA by default.
457
458 When a device requests a DMA access for a system memory,
459 the device driver need use SetAttribute() to update the IOMMU
460 attribute to request DMA access (read and/or write).
461
462 The DeviceHandle is used to identify which device submits the request.
463 The IOMMU implementation need translate the device path to an IOMMU device
464 ID, and set IOMMU hardware register accordingly.
465 1) DeviceHandle can be a standard PCI device.
466 The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
467 The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
468 The memory for BusMasterCommonBuffer need set
469 EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
470 After the memory is used, the memory need set 0 to keep it being
471 protected.
472 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
473 The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or
474 EDKII_IOMMU_ACCESS_WRITE.
475
476 @param[in] This The protocol instance pointer.
477 @param[in] DeviceHandle The device who initiates the DMA access
478 request.
479 @param[in] Mapping The mapping value returned from Map().
480 @param[in] IoMmuAccess The IOMMU access.
481
482 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range
483 specified by DeviceAddress and Length.
484 @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.
485 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
486 Map().
487 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination
488 of access.
489 @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.
490 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported
491 by the IOMMU.
492 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range
493 specified by Mapping.
494 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
495 modify the IOMMU access.
496 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while
497 attempting the operation.
498
499 **/
500 EFI_STATUS
501 EFIAPI
502 IoMmuSetAttribute (
503 IN EDKII_IOMMU_PROTOCOL *This,
504 IN EFI_HANDLE DeviceHandle,
505 IN VOID *Mapping,
506 IN UINT64 IoMmuAccess
507 )
508 {
509 return EFI_UNSUPPORTED;
510 }
511
512 EDKII_IOMMU_PROTOCOL mAmdSev = {
513 EDKII_IOMMU_PROTOCOL_REVISION,
514 IoMmuSetAttribute,
515 IoMmuMap,
516 IoMmuUnmap,
517 IoMmuAllocateBuffer,
518 IoMmuFreeBuffer,
519 };
520
521 /**
522 Initialize Iommu Protocol.
523
524 **/
525 EFI_STATUS
526 EFIAPI
527 AmdSevInstallIoMmuProtocol (
528 VOID
529 )
530 {
531 EFI_STATUS Status;
532 EFI_HANDLE Handle;
533
534 Handle = NULL;
535 Status = gBS->InstallMultipleProtocolInterfaces (
536 &Handle,
537 &gEdkiiIoMmuProtocolGuid, &mAmdSev,
538 NULL
539 );
540 return Status;
541 }