]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c
EmbeddedPkg: Apply uncrustify changes
[mirror_edk2.git] / EmbeddedPkg / Library / NonCoherentDmaLib / NonCoherentDmaLib.c
CommitLineData
723102c7
AB
1/** @file\r
2\r
3 Generic non-coherent implementation of DmaLib.h\r
4\r
5 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
6 Copyright (c) 2015 - 2017, Linaro, Ltd. All rights reserved.<BR>\r
7\r
878b807a 8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
723102c7
AB
9\r
10**/\r
11\r
12#include <PiDxe.h>\r
13#include <Library/BaseLib.h>\r
14#include <Library/DebugLib.h>\r
15#include <Library/DmaLib.h>\r
16#include <Library/DxeServicesTableLib.h>\r
17#include <Library/MemoryAllocationLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19#include <Library/IoLib.h>\r
20#include <Library/BaseMemoryLib.h>\r
21\r
22#include <Protocol/Cpu.h>\r
23\r
24typedef struct {\r
e7108d0e
MK
25 EFI_PHYSICAL_ADDRESS HostAddress;\r
26 VOID *BufferAddress;\r
27 UINTN NumberOfBytes;\r
28 DMA_MAP_OPERATION Operation;\r
29 BOOLEAN DoubleBuffer;\r
723102c7
AB
30} MAP_INFO_INSTANCE;\r
31\r
723102c7 32typedef struct {\r
e7108d0e
MK
33 LIST_ENTRY Link;\r
34 VOID *HostAddress;\r
35 UINTN NumPages;\r
36 UINT64 Attributes;\r
723102c7
AB
37} UNCACHED_ALLOCATION;\r
38\r
e7108d0e
MK
39STATIC EFI_CPU_ARCH_PROTOCOL *mCpu;\r
40STATIC LIST_ENTRY UncachedAllocationList;\r
723102c7 41\r
e7108d0e 42STATIC PHYSICAL_ADDRESS mDmaHostAddressLimit;\r
62a75650 43\r
723102c7
AB
44STATIC\r
45PHYSICAL_ADDRESS\r
46HostToDeviceAddress (\r
e7108d0e 47 IN VOID *Address\r
723102c7
AB
48 )\r
49{\r
50 return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset);\r
51}\r
52\r
62a75650
AB
53/**\r
54 Allocates one or more 4KB pages of a certain memory type at a specified\r
55 alignment.\r
56\r
57 Allocates the number of 4KB pages specified by Pages of a certain memory type\r
58 with an alignment specified by Alignment. The allocated buffer is returned.\r
59 If Pages is 0, then NULL is returned. If there is not enough memory at the\r
60 specified alignment remaining to satisfy the request, then NULL is returned.\r
61 If Alignment is not a power of two and Alignment is not zero, then ASSERT().\r
62 If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT().\r
63\r
64 @param MemoryType The type of memory to allocate.\r
65 @param Pages The number of 4 KB pages to allocate.\r
66 @param Alignment The requested alignment of the allocation.\r
67 Must be a power of two.\r
68 If Alignment is zero, then byte alignment is\r
69 used.\r
70\r
71 @return A pointer to the allocated buffer or NULL if allocation fails.\r
72\r
73**/\r
74STATIC\r
75VOID *\r
76InternalAllocateAlignedPages (\r
77 IN EFI_MEMORY_TYPE MemoryType,\r
78 IN UINTN Pages,\r
79 IN UINTN Alignment\r
80 )\r
81{\r
82 EFI_STATUS Status;\r
83 EFI_PHYSICAL_ADDRESS Memory;\r
84 UINTN AlignedMemory;\r
85 UINTN AlignmentMask;\r
86 UINTN UnalignedPages;\r
87 UINTN RealPages;\r
88\r
89 //\r
90 // Alignment must be a power of two or zero.\r
91 //\r
92 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
93\r
94 if (Pages == 0) {\r
95 return NULL;\r
96 }\r
e7108d0e 97\r
62a75650
AB
98 if (Alignment > EFI_PAGE_SIZE) {\r
99 //\r
100 // Calculate the total number of pages since alignment is larger than page\r
101 // size.\r
102 //\r
e7108d0e
MK
103 AlignmentMask = Alignment - 1;\r
104 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
62a75650
AB
105 //\r
106 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not\r
107 // overflow.\r
108 //\r
109 ASSERT (RealPages > Pages);\r
110\r
111 Memory = mDmaHostAddressLimit;\r
e7108d0e
MK
112 Status = gBS->AllocatePages (\r
113 AllocateMaxAddress,\r
114 MemoryType,\r
115 RealPages,\r
116 &Memory\r
117 );\r
62a75650
AB
118 if (EFI_ERROR (Status)) {\r
119 return NULL;\r
120 }\r
e7108d0e 121\r
62a75650
AB
122 AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;\r
123 UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);\r
124 if (UnalignedPages > 0) {\r
125 //\r
126 // Free first unaligned page(s).\r
127 //\r
128 Status = gBS->FreePages (Memory, UnalignedPages);\r
129 ASSERT_EFI_ERROR (Status);\r
130 }\r
e7108d0e 131\r
62a75650
AB
132 Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);\r
133 UnalignedPages = RealPages - Pages - UnalignedPages;\r
134 if (UnalignedPages > 0) {\r
135 //\r
136 // Free last unaligned page(s).\r
137 //\r
138 Status = gBS->FreePages (Memory, UnalignedPages);\r
139 ASSERT_EFI_ERROR (Status);\r
140 }\r
141 } else {\r
142 //\r
143 // Do not over-allocate pages in this case.\r
144 //\r
145 Memory = mDmaHostAddressLimit;\r
e7108d0e
MK
146 Status = gBS->AllocatePages (\r
147 AllocateMaxAddress,\r
148 MemoryType,\r
149 Pages,\r
150 &Memory\r
151 );\r
62a75650
AB
152 if (EFI_ERROR (Status)) {\r
153 return NULL;\r
154 }\r
e7108d0e 155\r
62a75650
AB
156 AlignedMemory = (UINTN)Memory;\r
157 }\r
e7108d0e 158\r
62a75650
AB
159 return (VOID *)AlignedMemory;\r
160}\r
161\r
723102c7
AB
162/**\r
163 Provides the DMA controller-specific addresses needed to access system memory.\r
164\r
165 Operation is relative to the DMA bus master.\r
166\r
167 @param Operation Indicates if the bus master is going to read or\r
168 write to system memory.\r
169 @param HostAddress The system memory address to map to the DMA\r
170 controller.\r
171 @param NumberOfBytes On input the number of bytes to map. On output\r
172 the number of bytes that were mapped.\r
173 @param DeviceAddress The resulting map address for the bus master\r
174 controller to use to access the host's\r
175 HostAddress.\r
176 @param Mapping A resulting value to pass to Unmap().\r
177\r
178 @retval EFI_SUCCESS The range was mapped for the returned\r
179 NumberOfBytes.\r
180 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common\r
181 buffer.\r
182 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
183 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
184 of resources.\r
185 @retval EFI_DEVICE_ERROR The system hardware could not map the requested\r
186 address.\r
187\r
188**/\r
189EFI_STATUS\r
190EFIAPI\r
191DmaMap (\r
e7108d0e
MK
192 IN DMA_MAP_OPERATION Operation,\r
193 IN VOID *HostAddress,\r
194 IN OUT UINTN *NumberOfBytes,\r
195 OUT PHYSICAL_ADDRESS *DeviceAddress,\r
196 OUT VOID **Mapping\r
723102c7
AB
197 )\r
198{\r
e7108d0e
MK
199 EFI_STATUS Status;\r
200 MAP_INFO_INSTANCE *Map;\r
201 VOID *Buffer;\r
202 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
203 UINTN AllocSize;\r
204\r
205 if ((HostAddress == NULL) ||\r
206 (NumberOfBytes == NULL) ||\r
207 (DeviceAddress == NULL) ||\r
208 (Mapping == NULL))\r
209 {\r
723102c7
AB
210 return EFI_INVALID_PARAMETER;\r
211 }\r
212\r
213 if (Operation >= MapOperationMaximum) {\r
214 return EFI_INVALID_PARAMETER;\r
215 }\r
216\r
217 *DeviceAddress = HostToDeviceAddress (HostAddress);\r
218\r
219 // Remember range so we can flush on the other side\r
220 Map = AllocatePool (sizeof (MAP_INFO_INSTANCE));\r
221 if (Map == NULL) {\r
e7108d0e 222 return EFI_OUT_OF_RESOURCES;\r
723102c7
AB
223 }\r
224\r
62a75650 225 if (((UINTN)HostAddress + *NumberOfBytes) > mDmaHostAddressLimit) {\r
62a75650
AB
226 if (Operation == MapOperationBusMasterCommonBuffer) {\r
227 goto CommonBufferError;\r
228 }\r
229\r
e7108d0e
MK
230 AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment);\r
231 Map->BufferAddress = InternalAllocateAlignedPages (\r
232 EfiBootServicesData,\r
62a75650 233 EFI_SIZE_TO_PAGES (AllocSize),\r
e7108d0e
MK
234 mCpu->DmaBufferAlignment\r
235 );\r
62a75650
AB
236 if (Map->BufferAddress == NULL) {\r
237 Status = EFI_OUT_OF_RESOURCES;\r
238 goto FreeMapInfo;\r
239 }\r
240\r
ef56f55d 241 if (Operation == MapOperationBusMasterRead) {\r
8f22a331 242 CopyMem (Map->BufferAddress, (VOID *)(UINTN)HostAddress, *NumberOfBytes);\r
62a75650 243 }\r
62a75650 244\r
e7108d0e
MK
245 mCpu->FlushDataCache (\r
246 mCpu,\r
247 (UINTN)Map->BufferAddress,\r
248 AllocSize,\r
249 EfiCpuFlushTypeWriteBack\r
250 );\r
723102c7 251\r
e7108d0e
MK
252 *DeviceAddress = HostToDeviceAddress (Map->BufferAddress);\r
253 } else if ((Operation != MapOperationBusMasterRead) &&\r
254 ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) ||\r
255 ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0)))\r
256 {\r
723102c7
AB
257 // Get the cacheability of the region\r
258 Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor);\r
e7108d0e 259 if (EFI_ERROR (Status)) {\r
723102c7
AB
260 goto FreeMapInfo;\r
261 }\r
262\r
263 // If the mapped buffer is not an uncached buffer\r
264 if ((GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) != 0) {\r
265 //\r
266 // Operations of type MapOperationBusMasterCommonBuffer are only allowed\r
267 // on uncached buffers.\r
268 //\r
269 if (Operation == MapOperationBusMasterCommonBuffer) {\r
62a75650 270 goto CommonBufferError;\r
723102c7
AB
271 }\r
272\r
273 //\r
274 // If the buffer does not fill entire cache lines we must double buffer\r
275 // into a suitably aligned allocation that allows us to invalidate the\r
276 // cache without running the risk of corrupting adjacent unrelated data.\r
277 // Note that pool allocations are guaranteed to be 8 byte aligned, so\r
278 // we only have to add (alignment - 8) worth of padding.\r
279 //\r
280 Map->DoubleBuffer = TRUE;\r
e7108d0e
MK
281 AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment) +\r
282 (mCpu->DmaBufferAlignment - 8);\r
723102c7
AB
283 Map->BufferAddress = AllocatePool (AllocSize);\r
284 if (Map->BufferAddress == NULL) {\r
285 Status = EFI_OUT_OF_RESOURCES;\r
286 goto FreeMapInfo;\r
287 }\r
288\r
e7108d0e 289 Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment);\r
723102c7
AB
290 *DeviceAddress = HostToDeviceAddress (Buffer);\r
291\r
292 //\r
293 // Get rid of any dirty cachelines covering the double buffer. This\r
294 // prevents them from being written back unexpectedly, potentially\r
295 // overwriting the data we receive from the device.\r
296 //\r
e7108d0e
MK
297 mCpu->FlushDataCache (\r
298 mCpu,\r
299 (UINTN)Buffer,\r
300 *NumberOfBytes,\r
301 EfiCpuFlushTypeWriteBack\r
302 );\r
723102c7 303 } else {\r
e7108d0e 304 Map->DoubleBuffer = FALSE;\r
723102c7
AB
305 }\r
306 } else {\r
e7108d0e 307 Map->DoubleBuffer = FALSE;\r
723102c7
AB
308\r
309 DEBUG_CODE_BEGIN ();\r
310\r
311 //\r
312 // The operation type check above only executes if the buffer happens to be\r
313 // misaligned with respect to CWG, but even if it is aligned, we should not\r
314 // allow arbitrary buffers to be used for creating consistent mappings.\r
315 // So duplicate the check here when running in DEBUG mode, just to assert\r
316 // that we are not trying to create a consistent mapping for cached memory.\r
317 //\r
318 Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor);\r
e7108d0e 319 ASSERT_EFI_ERROR (Status);\r
723102c7 320\r
e7108d0e
MK
321 ASSERT (\r
322 Operation != MapOperationBusMasterCommonBuffer ||\r
323 (GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0\r
324 );\r
723102c7
AB
325\r
326 DEBUG_CODE_END ();\r
327\r
328 // Flush the Data Cache (should not have any effect if the memory region is\r
329 // uncached)\r
e7108d0e
MK
330 mCpu->FlushDataCache (\r
331 mCpu,\r
332 (UINTN)HostAddress,\r
333 *NumberOfBytes,\r
334 EfiCpuFlushTypeWriteBackInvalidate\r
335 );\r
723102c7
AB
336 }\r
337\r
338 Map->HostAddress = (UINTN)HostAddress;\r
339 Map->NumberOfBytes = *NumberOfBytes;\r
340 Map->Operation = Operation;\r
341\r
342 *Mapping = Map;\r
343\r
344 return EFI_SUCCESS;\r
345\r
62a75650 346CommonBufferError:\r
e7108d0e
MK
347 DEBUG ((\r
348 DEBUG_ERROR,\r
62a75650
AB
349 "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only "\r
350 "supported\non memory regions that were allocated using "\r
e7108d0e
MK
351 "DmaAllocateBuffer ()\n",\r
352 __FUNCTION__\r
353 ));\r
62a75650 354 Status = EFI_UNSUPPORTED;\r
723102c7
AB
355FreeMapInfo:\r
356 FreePool (Map);\r
357\r
358 return Status;\r
359}\r
360\r
723102c7
AB
361/**\r
362 Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or\r
363 DmaMapBusMasterCommonBuffer() operation and releases any corresponding\r
364 resources.\r
365\r
366 @param Mapping The mapping value returned from DmaMap*().\r
367\r
368 @retval EFI_SUCCESS The range was unmapped.\r
369 @retval EFI_DEVICE_ERROR The data was not committed to the target system\r
370 memory.\r
371 @retval EFI_INVALID_PARAMETER An inconsistency was detected between the\r
372 mapping type and the DoubleBuffer field\r
373\r
374**/\r
375EFI_STATUS\r
376EFIAPI\r
377DmaUnmap (\r
e7108d0e 378 IN VOID *Mapping\r
723102c7
AB
379 )\r
380{\r
e7108d0e
MK
381 MAP_INFO_INSTANCE *Map;\r
382 EFI_STATUS Status;\r
383 VOID *Buffer;\r
384 UINTN AllocSize;\r
723102c7
AB
385\r
386 if (Mapping == NULL) {\r
387 ASSERT (FALSE);\r
388 return EFI_INVALID_PARAMETER;\r
389 }\r
390\r
391 Map = (MAP_INFO_INSTANCE *)Mapping;\r
392\r
393 Status = EFI_SUCCESS;\r
62a75650
AB
394 if (((UINTN)Map->HostAddress + Map->NumberOfBytes) > mDmaHostAddressLimit) {\r
395 AllocSize = ALIGN_VALUE (Map->NumberOfBytes, mCpu->DmaBufferAlignment);\r
396 if (Map->Operation == MapOperationBusMasterWrite) {\r
e7108d0e
MK
397 mCpu->FlushDataCache (\r
398 mCpu,\r
399 (UINTN)Map->BufferAddress,\r
400 AllocSize,\r
401 EfiCpuFlushTypeInvalidate\r
402 );\r
403 CopyMem (\r
404 (VOID *)(UINTN)Map->HostAddress,\r
405 Map->BufferAddress,\r
406 Map->NumberOfBytes\r
407 );\r
62a75650 408 }\r
e7108d0e 409\r
62a75650
AB
410 FreePages (Map->BufferAddress, EFI_SIZE_TO_PAGES (AllocSize));\r
411 } else if (Map->DoubleBuffer) {\r
723102c7
AB
412 ASSERT (Map->Operation == MapOperationBusMasterWrite);\r
413\r
414 if (Map->Operation != MapOperationBusMasterWrite) {\r
415 Status = EFI_INVALID_PARAMETER;\r
416 } else {\r
417 Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment);\r
418\r
e7108d0e
MK
419 mCpu->FlushDataCache (\r
420 mCpu,\r
421 (UINTN)Buffer,\r
422 Map->NumberOfBytes,\r
423 EfiCpuFlushTypeInvalidate\r
424 );\r
723102c7
AB
425\r
426 CopyMem ((VOID *)(UINTN)Map->HostAddress, Buffer, Map->NumberOfBytes);\r
427\r
428 FreePool (Map->BufferAddress);\r
429 }\r
430 } else {\r
431 if (Map->Operation == MapOperationBusMasterWrite) {\r
432 //\r
433 // Make sure we read buffer from uncached memory and not the cache\r
434 //\r
e7108d0e
MK
435 mCpu->FlushDataCache (\r
436 mCpu,\r
437 Map->HostAddress,\r
438 Map->NumberOfBytes,\r
439 EfiCpuFlushTypeInvalidate\r
440 );\r
723102c7
AB
441 }\r
442 }\r
443\r
444 FreePool (Map);\r
445\r
446 return Status;\r
447}\r
448\r
449/**\r
450 Allocates pages that are suitable for an DmaMap() of type\r
451 MapOperationBusMasterCommonBuffer mapping.\r
452\r
453 @param MemoryType The type of memory to allocate,\r
454 EfiBootServicesData or EfiRuntimeServicesData.\r
455 @param Pages The number of pages to allocate.\r
456 @param HostAddress A pointer to store the base system memory\r
457 address of the allocated range.\r
458\r
459 @retval EFI_SUCCESS The requested memory pages were allocated.\r
460 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
461 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
462\r
463**/\r
464EFI_STATUS\r
465EFIAPI\r
466DmaAllocateBuffer (\r
e7108d0e
MK
467 IN EFI_MEMORY_TYPE MemoryType,\r
468 IN UINTN Pages,\r
469 OUT VOID **HostAddress\r
723102c7
AB
470 )\r
471{\r
472 return DmaAllocateAlignedBuffer (MemoryType, Pages, 0, HostAddress);\r
473}\r
474\r
475/**\r
476 Allocates pages that are suitable for an DmaMap() of type\r
477 MapOperationBusMasterCommonBuffer mapping, at the requested alignment.\r
478\r
479 @param MemoryType The type of memory to allocate,\r
480 EfiBootServicesData or EfiRuntimeServicesData.\r
481 @param Pages The number of pages to allocate.\r
482 @param Alignment Alignment in bytes of the base of the returned\r
483 buffer (must be a power of 2)\r
484 @param HostAddress A pointer to store the base system memory\r
485 address of the allocated range.\r
486\r
487 @retval EFI_SUCCESS The requested memory pages were allocated.\r
488 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
489 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
490\r
491**/\r
492EFI_STATUS\r
493EFIAPI\r
494DmaAllocateAlignedBuffer (\r
e7108d0e
MK
495 IN EFI_MEMORY_TYPE MemoryType,\r
496 IN UINTN Pages,\r
497 IN UINTN Alignment,\r
498 OUT VOID **HostAddress\r
723102c7
AB
499 )\r
500{\r
e7108d0e
MK
501 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
502 VOID *Allocation;\r
503 UINT64 MemType;\r
504 UNCACHED_ALLOCATION *Alloc;\r
505 EFI_STATUS Status;\r
723102c7
AB
506\r
507 if (Alignment == 0) {\r
508 Alignment = EFI_PAGE_SIZE;\r
509 }\r
510\r
e7108d0e
MK
511 if ((HostAddress == NULL) ||\r
512 ((Alignment & (Alignment - 1)) != 0))\r
513 {\r
723102c7
AB
514 return EFI_INVALID_PARAMETER;\r
515 }\r
516\r
e7108d0e
MK
517 if ((MemoryType == EfiBootServicesData) ||\r
518 (MemoryType == EfiRuntimeServicesData))\r
519 {\r
62a75650 520 Allocation = InternalAllocateAlignedPages (MemoryType, Pages, Alignment);\r
723102c7
AB
521 } else {\r
522 return EFI_INVALID_PARAMETER;\r
523 }\r
524\r
525 if (Allocation == NULL) {\r
526 return EFI_OUT_OF_RESOURCES;\r
527 }\r
528\r
529 // Get the cacheability of the region\r
530 Status = gDS->GetMemorySpaceDescriptor ((UINTN)Allocation, &GcdDescriptor);\r
e7108d0e 531 if (EFI_ERROR (Status)) {\r
723102c7
AB
532 goto FreeBuffer;\r
533 }\r
534\r
535 // Choose a suitable uncached memory type that is supported by the region\r
536 if (GcdDescriptor.Capabilities & EFI_MEMORY_WC) {\r
537 MemType = EFI_MEMORY_WC;\r
538 } else if (GcdDescriptor.Capabilities & EFI_MEMORY_UC) {\r
539 MemType = EFI_MEMORY_UC;\r
540 } else {\r
541 Status = EFI_UNSUPPORTED;\r
542 goto FreeBuffer;\r
543 }\r
544\r
545 Alloc = AllocatePool (sizeof *Alloc);\r
546 if (Alloc == NULL) {\r
547 goto FreeBuffer;\r
548 }\r
549\r
550 Alloc->HostAddress = Allocation;\r
e7108d0e
MK
551 Alloc->NumPages = Pages;\r
552 Alloc->Attributes = GcdDescriptor.Attributes;\r
723102c7
AB
553\r
554 InsertHeadList (&UncachedAllocationList, &Alloc->Link);\r
555\r
556 // Remap the region with the new attributes\r
e7108d0e
MK
557 Status = gDS->SetMemorySpaceAttributes (\r
558 (PHYSICAL_ADDRESS)(UINTN)Allocation,\r
559 EFI_PAGES_TO_SIZE (Pages),\r
560 MemType\r
561 );\r
723102c7
AB
562 if (EFI_ERROR (Status)) {\r
563 goto FreeAlloc;\r
564 }\r
565\r
e7108d0e
MK
566 Status = mCpu->FlushDataCache (\r
567 mCpu,\r
568 (PHYSICAL_ADDRESS)(UINTN)Allocation,\r
569 EFI_PAGES_TO_SIZE (Pages),\r
570 EfiCpuFlushTypeInvalidate\r
571 );\r
723102c7
AB
572 if (EFI_ERROR (Status)) {\r
573 goto FreeAlloc;\r
574 }\r
575\r
576 *HostAddress = Allocation;\r
577\r
578 return EFI_SUCCESS;\r
579\r
580FreeAlloc:\r
581 RemoveEntryList (&Alloc->Link);\r
582 FreePool (Alloc);\r
583\r
584FreeBuffer:\r
585 FreePages (Allocation, Pages);\r
586 return Status;\r
587}\r
588\r
723102c7
AB
589/**\r
590 Frees memory that was allocated with DmaAllocateBuffer().\r
591\r
592 @param Pages The number of pages to free.\r
593 @param HostAddress The base system memory address of the allocated\r
594 range.\r
595\r
596 @retval EFI_SUCCESS The requested memory pages were freed.\r
597 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and\r
598 Pages was not allocated with\r
599 DmaAllocateBuffer().\r
600\r
601**/\r
602EFI_STATUS\r
603EFIAPI\r
604DmaFreeBuffer (\r
e7108d0e
MK
605 IN UINTN Pages,\r
606 IN VOID *HostAddress\r
723102c7
AB
607 )\r
608{\r
e7108d0e
MK
609 LIST_ENTRY *Link;\r
610 UNCACHED_ALLOCATION *Alloc;\r
611 BOOLEAN Found;\r
612 EFI_STATUS Status;\r
723102c7
AB
613\r
614 if (HostAddress == NULL) {\r
e7108d0e 615 return EFI_INVALID_PARAMETER;\r
723102c7
AB
616 }\r
617\r
618 for (Link = GetFirstNode (&UncachedAllocationList), Found = FALSE;\r
619 !IsNull (&UncachedAllocationList, Link);\r
e7108d0e
MK
620 Link = GetNextNode (&UncachedAllocationList, Link))\r
621 {\r
723102c7 622 Alloc = BASE_CR (Link, UNCACHED_ALLOCATION, Link);\r
e7108d0e 623 if ((Alloc->HostAddress == HostAddress) && (Alloc->NumPages == Pages)) {\r
723102c7
AB
624 Found = TRUE;\r
625 break;\r
626 }\r
627 }\r
628\r
629 if (!Found) {\r
630 ASSERT (FALSE);\r
631 return EFI_INVALID_PARAMETER;\r
632 }\r
633\r
634 RemoveEntryList (&Alloc->Link);\r
635\r
e7108d0e
MK
636 Status = gDS->SetMemorySpaceAttributes (\r
637 (PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
638 EFI_PAGES_TO_SIZE (Pages),\r
639 Alloc->Attributes\r
640 );\r
723102c7
AB
641 if (EFI_ERROR (Status)) {\r
642 goto FreeAlloc;\r
643 }\r
644\r
645 //\r
646 // If we fail to restore the original attributes, it is better to leak the\r
647 // memory than to return it to the heap\r
648 //\r
649 FreePages (HostAddress, Pages);\r
650\r
651FreeAlloc:\r
652 FreePool (Alloc);\r
653 return Status;\r
654}\r
655\r
723102c7
AB
656EFI_STATUS\r
657EFIAPI\r
658NonCoherentDmaLibConstructor (\r
e7108d0e
MK
659 IN EFI_HANDLE ImageHandle,\r
660 IN EFI_SYSTEM_TABLE *SystemTable\r
723102c7
AB
661 )\r
662{\r
663 InitializeListHead (&UncachedAllocationList);\r
664\r
62a75650
AB
665 //\r
666 // Ensure that the combination of DMA addressing offset and limit produces\r
667 // a sane value.\r
668 //\r
669 ASSERT (PcdGet64 (PcdDmaDeviceLimit) > PcdGet64 (PcdDmaDeviceOffset));\r
670\r
671 mDmaHostAddressLimit = PcdGet64 (PcdDmaDeviceLimit) -\r
672 PcdGet64 (PcdDmaDeviceOffset);\r
673\r
723102c7
AB
674 // Get the Cpu protocol for later use\r
675 return gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);\r
676}\r