]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/VTd/IntelVTdDxe/BmDma.c
IntelSiliconPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / BmDma.c
CommitLineData
c049fc99
JY
1/** @file\r
2 BmDma related function\r
3\r
3a716706 4 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>\r
8f7a05e1 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
c049fc99
JY
6\r
7**/\r
8\r
3a716706 9#include "DmaProtection.h"\r
c049fc99
JY
10\r
11// TBD: May make it a policy\r
12#define DMA_MEMORY_TOP MAX_UINTN\r
13//#define DMA_MEMORY_TOP 0x0000000001FFFFFFULL\r
14\r
6d2d2e6e
JY
15#define MAP_HANDLE_INFO_SIGNATURE SIGNATURE_32 ('H', 'M', 'A', 'P')\r
16typedef struct {\r
17 UINT32 Signature;\r
18 LIST_ENTRY Link;\r
19 EFI_HANDLE DeviceHandle;\r
20 UINT64 IoMmuAccess;\r
21} MAP_HANDLE_INFO;\r
22#define MAP_HANDLE_INFO_FROM_LINK(a) CR (a, MAP_HANDLE_INFO, Link, MAP_HANDLE_INFO_SIGNATURE)\r
23\r
c049fc99
JY
24#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')\r
25typedef struct {\r
26 UINT32 Signature;\r
27 LIST_ENTRY Link;\r
28 EDKII_IOMMU_OPERATION Operation;\r
29 UINTN NumberOfBytes;\r
30 UINTN NumberOfPages;\r
31 EFI_PHYSICAL_ADDRESS HostAddress;\r
32 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
6d2d2e6e 33 LIST_ENTRY HandleList;\r
c049fc99
JY
34} MAP_INFO;\r
35#define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)\r
36\r
37LIST_ENTRY gMaps = INITIALIZE_LIST_HEAD_VARIABLE(gMaps);\r
38\r
6d2d2e6e
JY
39/**\r
40 This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,\r
41 based upon the DeviceAddress.\r
42\r
43 @param[in] DeviceHandle The device who initiates the DMA access request.\r
44 @param[in] DeviceAddress The base of device memory address to be used as the DMA memory.\r
45 @param[in] Length The length of device memory address to be used as the DMA memory.\r
46 @param[in] IoMmuAccess The IOMMU access.\r
47\r
48**/\r
49VOID\r
50SyncDeviceHandleToMapInfo (\r
51 IN EFI_HANDLE DeviceHandle,\r
52 IN EFI_PHYSICAL_ADDRESS DeviceAddress,\r
53 IN UINT64 Length,\r
54 IN UINT64 IoMmuAccess\r
55 )\r
56{\r
57 MAP_INFO *MapInfo;\r
58 MAP_HANDLE_INFO *MapHandleInfo;\r
59 LIST_ENTRY *Link;\r
60 EFI_TPL OriginalTpl;\r
61\r
62 //\r
63 // Find MapInfo according to DeviceAddress\r
64 //\r
65 OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);\r
66 MapInfo = NULL;\r
67 for (Link = GetFirstNode (&gMaps)\r
68 ; !IsNull (&gMaps, Link)\r
69 ; Link = GetNextNode (&gMaps, Link)\r
70 ) {\r
71 MapInfo = MAP_INFO_FROM_LINK (Link);\r
72 if (MapInfo->DeviceAddress == DeviceAddress) {\r
73 break;\r
74 }\r
75 }\r
76 if ((MapInfo == NULL) || (MapInfo->DeviceAddress != DeviceAddress)) {\r
77 DEBUG ((DEBUG_ERROR, "SyncDeviceHandleToMapInfo: DeviceAddress(0x%lx) - not found\n", DeviceAddress));\r
78 gBS->RestoreTPL (OriginalTpl);\r
79 return ;\r
80 }\r
81\r
82 //\r
83 // Find MapHandleInfo according to DeviceHandle\r
84 //\r
85 MapHandleInfo = NULL;\r
86 for (Link = GetFirstNode (&MapInfo->HandleList)\r
87 ; !IsNull (&MapInfo->HandleList, Link)\r
88 ; Link = GetNextNode (&MapInfo->HandleList, Link)\r
89 ) {\r
90 MapHandleInfo = MAP_HANDLE_INFO_FROM_LINK (Link);\r
91 if (MapHandleInfo->DeviceHandle == DeviceHandle) {\r
92 break;\r
93 }\r
94 }\r
95 if ((MapHandleInfo != NULL) && (MapHandleInfo->DeviceHandle == DeviceHandle)) {\r
96 MapHandleInfo->IoMmuAccess = IoMmuAccess;\r
97 gBS->RestoreTPL (OriginalTpl);\r
98 return ;\r
99 }\r
100\r
101 //\r
102 // No DeviceHandle\r
103 // Initialize and insert the MAP_HANDLE_INFO structure\r
104 //\r
105 MapHandleInfo = AllocatePool (sizeof (MAP_HANDLE_INFO));\r
106 if (MapHandleInfo == NULL) {\r
107 DEBUG ((DEBUG_ERROR, "SyncDeviceHandleToMapInfo: %r\n", EFI_OUT_OF_RESOURCES));\r
108 gBS->RestoreTPL (OriginalTpl);\r
109 return ;\r
110 }\r
111\r
112 MapHandleInfo->Signature = MAP_HANDLE_INFO_SIGNATURE;\r
113 MapHandleInfo->DeviceHandle = DeviceHandle;\r
114 MapHandleInfo->IoMmuAccess = IoMmuAccess;\r
115\r
116 InsertTailList (&MapInfo->HandleList, &MapHandleInfo->Link);\r
117 gBS->RestoreTPL (OriginalTpl);\r
118\r
119 return ;\r
120}\r
121\r
c049fc99
JY
122/**\r
123 Provides the controller-specific addresses required to access system memory from a\r
124 DMA bus master.\r
125\r
126 @param This The protocol instance pointer.\r
127 @param Operation Indicates if the bus master is going to read or write to system memory.\r
128 @param HostAddress The system memory address to map to the PCI controller.\r
129 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
130 that were mapped.\r
131 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
132 access the hosts HostAddress.\r
133 @param Mapping A resulting value to pass to Unmap().\r
134\r
135 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
136 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
137 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
138 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
139 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
140\r
141**/\r
142EFI_STATUS\r
143EFIAPI\r
144IoMmuMap (\r
145 IN EDKII_IOMMU_PROTOCOL *This,\r
146 IN EDKII_IOMMU_OPERATION Operation,\r
147 IN VOID *HostAddress,\r
148 IN OUT UINTN *NumberOfBytes,\r
149 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
150 OUT VOID **Mapping\r
151 )\r
152{\r
153 EFI_STATUS Status;\r
154 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
155 MAP_INFO *MapInfo;\r
156 EFI_PHYSICAL_ADDRESS DmaMemoryTop;\r
157 BOOLEAN NeedRemap;\r
3a716706 158 EFI_TPL OriginalTpl;\r
c049fc99 159\r
94fb621d 160 if (NumberOfBytes == NULL || DeviceAddress == NULL ||\r
c049fc99
JY
161 Mapping == NULL) {\r
162 DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));\r
163 return EFI_INVALID_PARAMETER;\r
164 }\r
165\r
94fb621d
JY
166 DEBUG ((DEBUG_VERBOSE, "IoMmuMap: ==> 0x%08x - 0x%08x (%x)\n", HostAddress, *NumberOfBytes, Operation));\r
167\r
c049fc99
JY
168 //\r
169 // Make sure that Operation is valid\r
170 //\r
171 if ((UINT32) Operation >= EdkiiIoMmuOperationMaximum) {\r
172 DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER));\r
173 return EFI_INVALID_PARAMETER;\r
174 }\r
175 NeedRemap = FALSE;\r
176 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
177\r
178 DmaMemoryTop = DMA_MEMORY_TOP;\r
179\r
180 //\r
181 // Alignment check\r
182 //\r
183 if ((*NumberOfBytes != ALIGN_VALUE(*NumberOfBytes, SIZE_4KB)) ||\r
184 (PhysicalAddress != ALIGN_VALUE(PhysicalAddress, SIZE_4KB))) {\r
185 if ((Operation == EdkiiIoMmuOperationBusMasterCommonBuffer) ||\r
186 (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64)) {\r
187 //\r
188 // The input buffer might be a subset from IoMmuAllocateBuffer.\r
189 // Skip the check.\r
190 //\r
191 } else {\r
192 NeedRemap = TRUE;\r
193 }\r
194 }\r
195\r
196 if ((PhysicalAddress + *NumberOfBytes) >= DMA_MEMORY_TOP) {\r
197 NeedRemap = TRUE;\r
198 }\r
199\r
200 if (((Operation != EdkiiIoMmuOperationBusMasterRead64 &&\r
201 Operation != EdkiiIoMmuOperationBusMasterWrite64 &&\r
202 Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) &&\r
203 ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {\r
204 //\r
205 // If the root bridge or the device cannot handle performing DMA above\r
206 // 4GB but any part of the DMA transfer being mapped is above 4GB, then\r
207 // map the DMA transfer to a buffer below 4GB.\r
208 //\r
209 NeedRemap = TRUE;\r
210 DmaMemoryTop = MIN (DmaMemoryTop, SIZE_4GB - 1);\r
211 }\r
212\r
213 if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
214 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
215 if (NeedRemap) {\r
216 //\r
217 // Common Buffer operations can not be remapped. If the common buffer\r
94fb621d 218 // is above 4GB, then it is not possible to generate a mapping, so return\r
c049fc99
JY
219 // an error.\r
220 //\r
221 DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_UNSUPPORTED));\r
222 return EFI_UNSUPPORTED;\r
223 }\r
224 }\r
225\r
226 //\r
227 // Allocate a MAP_INFO structure to remember the mapping when Unmap() is\r
228 // called later.\r
229 //\r
230 MapInfo = AllocatePool (sizeof (MAP_INFO));\r
231 if (MapInfo == NULL) {\r
232 *NumberOfBytes = 0;\r
233 DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", EFI_OUT_OF_RESOURCES));\r
234 return EFI_OUT_OF_RESOURCES;\r
235 }\r
236\r
237 //\r
238 // Initialize the MAP_INFO structure\r
239 //\r
240 MapInfo->Signature = MAP_INFO_SIGNATURE;\r
241 MapInfo->Operation = Operation;\r
242 MapInfo->NumberOfBytes = *NumberOfBytes;\r
243 MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);\r
244 MapInfo->HostAddress = PhysicalAddress;\r
245 MapInfo->DeviceAddress = DmaMemoryTop;\r
6d2d2e6e 246 InitializeListHead(&MapInfo->HandleList);\r
c049fc99
JY
247\r
248 //\r
249 // Allocate a buffer below 4GB to map the transfer to.\r
250 //\r
251 if (NeedRemap) {\r
252 Status = gBS->AllocatePages (\r
253 AllocateMaxAddress,\r
254 EfiBootServicesData,\r
255 MapInfo->NumberOfPages,\r
256 &MapInfo->DeviceAddress\r
257 );\r
258 if (EFI_ERROR (Status)) {\r
259 FreePool (MapInfo);\r
260 *NumberOfBytes = 0;\r
261 DEBUG ((DEBUG_ERROR, "IoMmuMap: %r\n", Status));\r
262 return Status;\r
263 }\r
264\r
265 //\r
266 // If this is a read operation from the Bus Master's point of view,\r
267 // then copy the contents of the real buffer into the mapped buffer\r
268 // so the Bus Master can read the contents of the real buffer.\r
269 //\r
270 if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
271 Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
272 CopyMem (\r
273 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
274 (VOID *) (UINTN) MapInfo->HostAddress,\r
275 MapInfo->NumberOfBytes\r
276 );\r
277 }\r
278 } else {\r
279 MapInfo->DeviceAddress = MapInfo->HostAddress;\r
280 }\r
281\r
3a716706 282 OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);\r
c049fc99 283 InsertTailList (&gMaps, &MapInfo->Link);\r
3a716706 284 gBS->RestoreTPL (OriginalTpl);\r
c049fc99
JY
285\r
286 //\r
287 // The DeviceAddress is the address of the maped buffer below 4GB\r
288 //\r
289 *DeviceAddress = MapInfo->DeviceAddress;\r
290 //\r
291 // Return a pointer to the MAP_INFO structure in Mapping\r
292 //\r
293 *Mapping = MapInfo;\r
294\r
295 DEBUG ((DEBUG_VERBOSE, "IoMmuMap: 0x%08x - 0x%08x <==\n", *DeviceAddress, *Mapping));\r
296\r
297 return EFI_SUCCESS;\r
298}\r
299\r
300/**\r
301 Completes the Map() operation and releases any corresponding resources.\r
302\r
303 @param This The protocol instance pointer.\r
304 @param Mapping The mapping value returned from Map().\r
305\r
306 @retval EFI_SUCCESS The range was unmapped.\r
307 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
308 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
309**/\r
310EFI_STATUS\r
311EFIAPI\r
312IoMmuUnmap (\r
313 IN EDKII_IOMMU_PROTOCOL *This,\r
314 IN VOID *Mapping\r
315 )\r
316{\r
317 MAP_INFO *MapInfo;\r
6d2d2e6e 318 MAP_HANDLE_INFO *MapHandleInfo;\r
c049fc99 319 LIST_ENTRY *Link;\r
3a716706 320 EFI_TPL OriginalTpl;\r
c049fc99
JY
321\r
322 DEBUG ((DEBUG_VERBOSE, "IoMmuUnmap: 0x%08x\n", Mapping));\r
323\r
324 if (Mapping == NULL) {\r
325 DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));\r
326 return EFI_INVALID_PARAMETER;\r
327 }\r
328\r
3a716706 329 OriginalTpl = gBS->RaiseTPL (VTD_TPL_LEVEL);\r
c049fc99
JY
330 MapInfo = NULL;\r
331 for (Link = GetFirstNode (&gMaps)\r
332 ; !IsNull (&gMaps, Link)\r
333 ; Link = GetNextNode (&gMaps, Link)\r
334 ) {\r
335 MapInfo = MAP_INFO_FROM_LINK (Link);\r
336 if (MapInfo == Mapping) {\r
337 break;\r
338 }\r
339 }\r
340 //\r
341 // Mapping is not a valid value returned by Map()\r
342 //\r
343 if (MapInfo != Mapping) {\r
3a716706 344 gBS->RestoreTPL (OriginalTpl);\r
c049fc99
JY
345 DEBUG ((DEBUG_ERROR, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER));\r
346 return EFI_INVALID_PARAMETER;\r
347 }\r
348 RemoveEntryList (&MapInfo->Link);\r
3a716706 349 gBS->RestoreTPL (OriginalTpl);\r
c049fc99 350\r
6d2d2e6e
JY
351 //\r
352 // remove all nodes in MapInfo->HandleList\r
353 //\r
354 while (!IsListEmpty (&MapInfo->HandleList)) {\r
355 MapHandleInfo = MAP_HANDLE_INFO_FROM_LINK (MapInfo->HandleList.ForwardLink);\r
356 RemoveEntryList (&MapHandleInfo->Link);\r
357 FreePool (MapHandleInfo);\r
358 }\r
359\r
c049fc99
JY
360 if (MapInfo->DeviceAddress != MapInfo->HostAddress) {\r
361 //\r
362 // If this is a write operation from the Bus Master's point of view,\r
363 // then copy the contents of the mapped buffer into the real buffer\r
364 // so the processor can read the contents of the real buffer.\r
365 //\r
366 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
367 MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
368 CopyMem (\r
369 (VOID *) (UINTN) MapInfo->HostAddress,\r
370 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
371 MapInfo->NumberOfBytes\r
372 );\r
373 }\r
374\r
375 //\r
376 // Free the mapped buffer and the MAP_INFO structure.\r
377 //\r
378 gBS->FreePages (MapInfo->DeviceAddress, MapInfo->NumberOfPages);\r
379 }\r
380\r
381 FreePool (Mapping);\r
382 return EFI_SUCCESS;\r
383}\r
384\r
385/**\r
386 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
387 OperationBusMasterCommonBuffer64 mapping.\r
388\r
389 @param This The protocol instance pointer.\r
390 @param Type This parameter is not used and must be ignored.\r
391 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
392 EfiRuntimeServicesData.\r
393 @param Pages The number of pages to allocate.\r
394 @param HostAddress A pointer to store the base system memory address of the\r
395 allocated range.\r
396 @param Attributes The requested bit mask of attributes for the allocated range.\r
397\r
398 @retval EFI_SUCCESS The requested memory pages were allocated.\r
399 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
34e18d17 400 MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.\r
c049fc99
JY
401 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
402 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
403\r
404**/\r
405EFI_STATUS\r
406EFIAPI\r
407IoMmuAllocateBuffer (\r
408 IN EDKII_IOMMU_PROTOCOL *This,\r
409 IN EFI_ALLOCATE_TYPE Type,\r
410 IN EFI_MEMORY_TYPE MemoryType,\r
411 IN UINTN Pages,\r
412 IN OUT VOID **HostAddress,\r
413 IN UINT64 Attributes\r
414 )\r
415{\r
416 EFI_STATUS Status;\r
417 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
418\r
419 DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: ==> 0x%08x\n", Pages));\r
420\r
421 //\r
422 // Validate Attributes\r
423 //\r
424 if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {\r
425 DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_UNSUPPORTED));\r
426 return EFI_UNSUPPORTED;\r
427 }\r
428\r
429 //\r
430 // Check for invalid inputs\r
431 //\r
432 if (HostAddress == NULL) {\r
433 DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));\r
434 return EFI_INVALID_PARAMETER;\r
435 }\r
436\r
437 //\r
438 // The only valid memory types are EfiBootServicesData and\r
439 // EfiRuntimeServicesData\r
440 //\r
441 if (MemoryType != EfiBootServicesData &&\r
442 MemoryType != EfiRuntimeServicesData) {\r
443 DEBUG ((DEBUG_ERROR, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER));\r
444 return EFI_INVALID_PARAMETER;\r
445 }\r
446\r
447 PhysicalAddress = DMA_MEMORY_TOP;\r
448 if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
449 //\r
450 // Limit allocations to memory below 4GB\r
451 //\r
452 PhysicalAddress = MIN (PhysicalAddress, SIZE_4GB - 1);\r
453 }\r
454 Status = gBS->AllocatePages (\r
455 AllocateMaxAddress,\r
456 MemoryType,\r
457 Pages,\r
458 &PhysicalAddress\r
459 );\r
460 if (!EFI_ERROR (Status)) {\r
461 *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
462 }\r
463\r
464 DEBUG ((DEBUG_VERBOSE, "IoMmuAllocateBuffer: 0x%08x <==\n", *HostAddress));\r
465\r
466 return Status;\r
467}\r
468\r
469/**\r
470 Frees memory that was allocated with AllocateBuffer().\r
471\r
472 @param This The protocol instance pointer.\r
473 @param Pages The number of pages to free.\r
474 @param HostAddress The base system memory address of the allocated range.\r
475\r
476 @retval EFI_SUCCESS The requested memory pages were freed.\r
477 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
478 was not allocated with AllocateBuffer().\r
479\r
480**/\r
481EFI_STATUS\r
482EFIAPI\r
483IoMmuFreeBuffer (\r
484 IN EDKII_IOMMU_PROTOCOL *This,\r
485 IN UINTN Pages,\r
486 IN VOID *HostAddress\r
487 )\r
488{\r
489 DEBUG ((DEBUG_VERBOSE, "IoMmuFreeBuffer: 0x%\n", Pages));\r
490 return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);\r
491}\r
492\r
493/**\r
494 Get device information from mapping.\r
495\r
496 @param[in] Mapping The mapping.\r
497 @param[out] DeviceAddress The device address of the mapping.\r
498 @param[out] NumberOfPages The number of pages of the mapping.\r
499\r
500 @retval EFI_SUCCESS The device information is returned.\r
501 @retval EFI_INVALID_PARAMETER The mapping is invalid.\r
502**/\r
503EFI_STATUS\r
504GetDeviceInfoFromMapping (\r
505 IN VOID *Mapping,\r
506 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
507 OUT UINTN *NumberOfPages\r
508 )\r
509{\r
510 MAP_INFO *MapInfo;\r
511 LIST_ENTRY *Link;\r
512\r
513 if (Mapping == NULL) {\r
514 return EFI_INVALID_PARAMETER;\r
515 }\r
516\r
517 MapInfo = NULL;\r
518 for (Link = GetFirstNode (&gMaps)\r
519 ; !IsNull (&gMaps, Link)\r
520 ; Link = GetNextNode (&gMaps, Link)\r
521 ) {\r
522 MapInfo = MAP_INFO_FROM_LINK (Link);\r
523 if (MapInfo == Mapping) {\r
524 break;\r
525 }\r
526 }\r
527 //\r
528 // Mapping is not a valid value returned by Map()\r
529 //\r
530 if (MapInfo != Mapping) {\r
531 return EFI_INVALID_PARAMETER;\r
532 }\r
533\r
534 *DeviceAddress = MapInfo->DeviceAddress;\r
535 *NumberOfPages = MapInfo->NumberOfPages;\r
536 return EFI_SUCCESS;\r
537}\r
538\r