Sync up ArmPkg with patch from mailing list. Changed name of BdsLib.h to BdsUnixLib...
[mirror_edk2.git] / ArmPkg / Library / DebugUncachedMemoryAllocationLib / DebugUncachedMemoryAllocationLib.c
CommitLineData
965626c9
A
1/** @file\r
2 Debug version of the UncachedMemoryAllocation lib that uses the VirtualUncachedPages\r
3 protocol, produced by the DXE CPU driver, to produce debuggable uncached memory buffers.\r
4 \r
5 The DMA rules for EFI contain the concept of a PCI (DMA master) address for memory and\r
6 a CPU (C code) address for the memory buffer that don't have to be the same. There seem to\r
7 be common errors out there with folks mixing up the two addresses. This library causes\r
8 the PCI (DMA master) address to not be mapped into system memory so if the CPU (C code)\r
9 uses the wrong pointer it will generate a page fault. The CPU (C code) version of the buffer\r
10 has a virtual address that does not match the physical address. The virtual address has\r
11 PcdArmUncachedMemoryMask ored into the physical address.\r
12\r
d6ebcab7 13 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
965626c9 14 \r
d6ebcab7 15 This program and the accompanying materials\r
965626c9
A
16 are licensed and made available under the terms and conditions of the BSD License\r
17 which accompanies this distribution. The full text of the license may be found at\r
18 http://opensource.org/licenses/bsd-license.php\r
19\r
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
22\r
23**/\r
24\r
25#include <Library/BaseLib.h>\r
26#include <Library/BaseMemoryLib.h>\r
27#include <Library/MemoryAllocationLib.h>\r
28#include <Library/DebugLib.h>\r
29#include <Library/UefiBootServicesTableLib.h>\r
30#include <Library/UncachedMemoryAllocationLib.h>\r
31#include <Library/PcdLib.h>\r
32#include <Library/ArmLib.h>\r
33\r
34#include <Protocol/Cpu.h>\r
35#include <Protocol/VirtualUncachedPages.h>\r
36\r
37VOID *\r
38UncachedInternalAllocatePages (\r
39 IN EFI_MEMORY_TYPE MemoryType, \r
40 IN UINTN Pages\r
41 );\r
42\r
43VOID *\r
44UncachedInternalAllocateAlignedPages (\r
45 IN EFI_MEMORY_TYPE MemoryType, \r
46 IN UINTN Pages,\r
47 IN UINTN Alignment\r
48 );\r
49 \r
50 \r
51\r
f659880b 52EFI_CPU_ARCH_PROTOCOL *gDebugUncachedCpu;\r
965626c9
A
53VIRTUAL_UNCACHED_PAGES_PROTOCOL *gVirtualUncachedPages;\r
54\r
55//\r
56// Assume all of memory has the same cache attributes, unless we do our magic\r
57//\r
58UINT64 gAttributes;\r
59\r
60typedef struct {\r
61 VOID *Buffer;\r
62 VOID *Allocation;\r
63 UINTN Pages;\r
64 LIST_ENTRY Link;\r
65} FREE_PAGE_NODE;\r
66\r
67LIST_ENTRY mPageList = INITIALIZE_LIST_HEAD_VARIABLE (mPageList);\r
68\r
69VOID\r
70AddPagesToList (\r
71 IN VOID *Buffer,\r
72 IN VOID *Allocation,\r
73 UINTN Pages\r
74 )\r
75{\r
76 FREE_PAGE_NODE *NewNode;\r
77 \r
78 NewNode = AllocatePool (sizeof (LIST_ENTRY));\r
79 if (NewNode == NULL) {\r
80 ASSERT (FALSE);\r
81 return;\r
82 }\r
83 \r
84 NewNode->Buffer = Buffer;\r
85 NewNode->Allocation = Allocation;\r
883b666e 86 NewNode->Pages = Pages;\r
87\r
965626c9
A
88 InsertTailList (&mPageList, &NewNode->Link);\r
89}\r
90\r
91\r
92VOID\r
93RemovePagesFromList (\r
94 IN VOID *Buffer,\r
95 OUT VOID **Allocation,\r
96 OUT UINTN *Pages\r
97 )\r
98{\r
99 LIST_ENTRY *Link;\r
100 FREE_PAGE_NODE *OldNode;\r
101\r
102 *Allocation = NULL;\r
103 *Pages = 0;\r
104 \r
105 for (Link = mPageList.ForwardLink; Link != &mPageList; Link = Link->ForwardLink) {\r
106 OldNode = BASE_CR (Link, FREE_PAGE_NODE, Link);\r
107 if (OldNode->Buffer == Buffer) {\r
108 *Allocation = OldNode->Allocation;\r
109 *Pages = OldNode->Pages;\r
110 \r
111 RemoveEntryList (&OldNode->Link);\r
112 FreePool (OldNode);\r
113 return;\r
114 }\r
115 }\r
116\r
117 return;\r
118}\r
119\r
120\r
121\r
122EFI_PHYSICAL_ADDRESS\r
123ConvertToPhysicalAddress (\r
124 IN VOID *VirtualAddress\r
125 )\r
126{\r
127 UINTN UncachedMemoryMask = (UINTN)PcdGet64 (PcdArmUncachedMemoryMask);\r
128 UINTN PhysicalAddress;\r
129 \r
130 PhysicalAddress = (UINTN)VirtualAddress & ~UncachedMemoryMask;\r
131 \r
132 return (EFI_PHYSICAL_ADDRESS)PhysicalAddress;\r
133}\r
134\r
135\r
136VOID *\r
137ConvertToUncachedAddress (\r
138 IN VOID *Address\r
139 )\r
140{\r
141 UINTN UncachedMemoryMask = (UINTN)PcdGet64 (PcdArmUncachedMemoryMask);\r
142 UINTN UncachedAddress;\r
143 \r
144 UncachedAddress = (UINTN)Address | UncachedMemoryMask;\r
145 \r
146 return (VOID *)UncachedAddress;\r
147}\r
148\r
149\r
150\r
151VOID *\r
152UncachedInternalAllocatePages (\r
153 IN EFI_MEMORY_TYPE MemoryType, \r
154 IN UINTN Pages\r
155 )\r
156{\r
157 return UncachedInternalAllocateAlignedPages (MemoryType, Pages, EFI_PAGE_SIZE);\r
158}\r
159\r
160\r
161VOID *\r
162EFIAPI\r
163UncachedAllocatePages (\r
164 IN UINTN Pages\r
165 )\r
166{\r
167 return UncachedInternalAllocatePages (EfiBootServicesData, Pages);\r
168}\r
169\r
170VOID *\r
171EFIAPI\r
172UncachedAllocateRuntimePages (\r
173 IN UINTN Pages\r
174 )\r
175{\r
176 return UncachedInternalAllocatePages (EfiRuntimeServicesData, Pages);\r
177}\r
178\r
179VOID *\r
180EFIAPI\r
181UncachedAllocateReservedPages (\r
182 IN UINTN Pages\r
183 )\r
184{\r
185 return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
186}\r
187\r
188\r
189\r
190VOID\r
191EFIAPI\r
192UncachedFreePages (\r
193 IN VOID *Buffer,\r
194 IN UINTN Pages\r
195 )\r
196{\r
197 UncachedFreeAlignedPages (Buffer, Pages);\r
198 return;\r
199}\r
200\r
201\r
202VOID *\r
203UncachedInternalAllocateAlignedPages (\r
204 IN EFI_MEMORY_TYPE MemoryType, \r
205 IN UINTN Pages,\r
206 IN UINTN Alignment\r
207 )\r
208{\r
209 EFI_STATUS Status;\r
210 EFI_PHYSICAL_ADDRESS Memory;\r
211 EFI_PHYSICAL_ADDRESS AlignedMemory;\r
212 UINTN AlignmentMask;\r
213 UINTN UnalignedPages;\r
214 UINTN RealPages;\r
215\r
216 //\r
217 // Alignment must be a power of two or zero.\r
218 //\r
219 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
220 \r
221 if (Pages == 0) {\r
222 return NULL;\r
223 }\r
224 if (Alignment > EFI_PAGE_SIZE) {\r
225 //\r
226 // Caculate the total number of pages since alignment is larger than page size.\r
227 //\r
228 AlignmentMask = Alignment - 1;\r
229 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
230 //\r
231 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
232 //\r
233 ASSERT (RealPages > Pages);\r
234 \r
235 Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);\r
236 if (EFI_ERROR (Status)) {\r
237 return NULL;\r
238 }\r
239 AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
240 UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
241 if (UnalignedPages > 0) {\r
242 //\r
243 // Free first unaligned page(s).\r
244 //\r
245 Status = gBS->FreePages (Memory, UnalignedPages);\r
246 ASSERT_EFI_ERROR (Status);\r
247 }\r
248 Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
249 UnalignedPages = RealPages - Pages - UnalignedPages;\r
250 if (UnalignedPages > 0) {\r
251 //\r
252 // Free last unaligned page(s).\r
253 //\r
254 Status = gBS->FreePages (Memory, UnalignedPages);\r
255 ASSERT_EFI_ERROR (Status);\r
256 }\r
257 } else {\r
258 //\r
259 // Do not over-allocate pages in this case.\r
260 //\r
261 Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);\r
262 if (EFI_ERROR (Status)) {\r
263 return NULL;\r
264 }\r
265 AlignedMemory = (UINTN) Memory;\r
266 }\r
267 \r
268 Status = gVirtualUncachedPages->ConvertPages (gVirtualUncachedPages, AlignedMemory, Pages * EFI_PAGE_SIZE, PcdGet64 (PcdArmUncachedMemoryMask), &gAttributes);\r
269 if (EFI_ERROR (Status)) {\r
270 return NULL;\r
271 }\r
272 \r
273 AlignedMemory = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertToUncachedAddress ((VOID *)(UINTN)AlignedMemory);\r
274 \r
275 return (VOID *)(UINTN)AlignedMemory;\r
276}\r
277\r
278\r
279VOID\r
280EFIAPI\r
281UncachedFreeAlignedPages (\r
282 IN VOID *Buffer,\r
283 IN UINTN Pages\r
284 )\r
285{\r
286 EFI_STATUS Status;\r
287 EFI_PHYSICAL_ADDRESS Memory; \r
288\r
289 ASSERT (Pages != 0);\r
290 \r
291 Memory = ConvertToPhysicalAddress (Buffer);\r
292 \r
293 Status = gVirtualUncachedPages->RevertPages (gVirtualUncachedPages, Memory, Pages * EFI_PAGE_SIZE, PcdGet64 (PcdArmUncachedMemoryMask), gAttributes);\r
294\r
295 \r
d4f167a9 296 Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Memory, Pages);\r
965626c9
A
297 ASSERT_EFI_ERROR (Status);\r
298}\r
299\r
300\r
301\r
302\r
303VOID *\r
304UncachedInternalAllocateAlignedPool (\r
305 IN EFI_MEMORY_TYPE PoolType,\r
306 IN UINTN AllocationSize,\r
307 IN UINTN Alignment\r
308 )\r
309{\r
310 VOID *AlignedAddress;\r
311 \r
312 //\r
313 // Alignment must be a power of two or zero.\r
314 //\r
315 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
316\r
317 if (Alignment < EFI_PAGE_SIZE) {\r
318 Alignment = EFI_PAGE_SIZE;\r
319 }\r
320 \r
321 AlignedAddress = UncachedInternalAllocateAlignedPages (PoolType, EFI_SIZE_TO_PAGES (AllocationSize), Alignment);\r
322 if (AlignedAddress == NULL) {\r
323 return NULL;\r
324 }\r
325\r
326 AddPagesToList ((VOID *)(UINTN)ConvertToPhysicalAddress (AlignedAddress), (VOID *)(UINTN)AlignedAddress, EFI_SIZE_TO_PAGES (AllocationSize));\r
327\r
328 return (VOID *) AlignedAddress;\r
329}\r
330\r
331VOID *\r
332EFIAPI\r
333UncachedAllocateAlignedPool (\r
334 IN UINTN AllocationSize,\r
335 IN UINTN Alignment\r
336 )\r
337{\r
338 return UncachedInternalAllocateAlignedPool (EfiBootServicesData, AllocationSize, Alignment);\r
339}\r
340\r
341VOID *\r
342EFIAPI\r
343UncachedAllocateAlignedRuntimePool (\r
344 IN UINTN AllocationSize,\r
345 IN UINTN Alignment\r
346 )\r
347{\r
348 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData, AllocationSize, Alignment);\r
349}\r
350\r
351VOID *\r
352EFIAPI\r
353UncachedAllocateAlignedReservedPool (\r
354 IN UINTN AllocationSize,\r
355 IN UINTN Alignment\r
356 )\r
357{\r
358 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType, AllocationSize, Alignment);\r
359}\r
360\r
361VOID *\r
362UncachedInternalAllocateAlignedZeroPool (\r
363 IN EFI_MEMORY_TYPE PoolType,\r
364 IN UINTN AllocationSize,\r
365 IN UINTN Alignment\r
366 )\r
367{\r
368 VOID *Memory;\r
369 Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
370 if (Memory != NULL) {\r
371 Memory = ZeroMem (Memory, AllocationSize);\r
372 }\r
373 return Memory;\r
374}\r
375\r
376VOID *\r
377EFIAPI\r
378UncachedAllocateAlignedZeroPool (\r
379 IN UINTN AllocationSize,\r
380 IN UINTN Alignment\r
381 )\r
382{\r
383 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData, AllocationSize, Alignment);\r
384}\r
385\r
386VOID *\r
387EFIAPI\r
388UncachedAllocateAlignedRuntimeZeroPool (\r
389 IN UINTN AllocationSize,\r
390 IN UINTN Alignment\r
391 )\r
392{\r
393 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData, AllocationSize, Alignment);\r
394}\r
395\r
396VOID *\r
397EFIAPI\r
398UncachedAllocateAlignedReservedZeroPool (\r
399 IN UINTN AllocationSize,\r
400 IN UINTN Alignment\r
401 )\r
402{\r
403 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType, AllocationSize, Alignment);\r
404}\r
405\r
406VOID *\r
407UncachedInternalAllocateAlignedCopyPool (\r
408 IN EFI_MEMORY_TYPE PoolType,\r
409 IN UINTN AllocationSize,\r
410 IN CONST VOID *Buffer,\r
411 IN UINTN Alignment\r
412 )\r
413{\r
414 VOID *Memory;\r
415 \r
416 ASSERT (Buffer != NULL);\r
417 ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));\r
418\r
419 Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
420 if (Memory != NULL) {\r
421 Memory = CopyMem (Memory, Buffer, AllocationSize);\r
422 }\r
423 return Memory;\r
424}\r
425\r
426VOID *\r
427EFIAPI\r
428UncachedAllocateAlignedCopyPool (\r
429 IN UINTN AllocationSize,\r
430 IN CONST VOID *Buffer,\r
431 IN UINTN Alignment\r
432 )\r
433{\r
434 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData, AllocationSize, Buffer, Alignment);\r
435}\r
436\r
437VOID *\r
438EFIAPI\r
439UncachedAllocateAlignedRuntimeCopyPool (\r
440 IN UINTN AllocationSize,\r
441 IN CONST VOID *Buffer,\r
442 IN UINTN Alignment\r
443 )\r
444{\r
445 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer, Alignment);\r
446}\r
447\r
448VOID *\r
449EFIAPI\r
450UncachedAllocateAlignedReservedCopyPool (\r
451 IN UINTN AllocationSize,\r
452 IN CONST VOID *Buffer,\r
453 IN UINTN Alignment\r
454 )\r
455{\r
456 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType, AllocationSize, Buffer, Alignment);\r
457}\r
458\r
459VOID\r
460EFIAPI\r
461UncachedFreeAlignedPool (\r
462 IN VOID *Buffer\r
463 )\r
464{\r
465 VOID *Allocation;\r
466 UINTN Pages;\r
467 \r
468 RemovePagesFromList (Buffer, &Allocation, &Pages);\r
469\r
470 UncachedFreePages (Allocation, Pages);\r
471}\r
472\r
473VOID *\r
474UncachedInternalAllocatePool (\r
475 IN EFI_MEMORY_TYPE MemoryType, \r
476 IN UINTN AllocationSize\r
477 )\r
478{\r
479 UINTN CacheLineLength = ArmDataCacheLineLength ();\r
480 return UncachedInternalAllocateAlignedPool (MemoryType, AllocationSize, CacheLineLength);\r
481}\r
482\r
483VOID *\r
484EFIAPI\r
485UncachedAllocatePool (\r
486 IN UINTN AllocationSize\r
487 )\r
488{\r
489 return UncachedInternalAllocatePool (EfiBootServicesData, AllocationSize);\r
490}\r
491\r
492VOID *\r
493EFIAPI\r
494UncachedAllocateRuntimePool (\r
495 IN UINTN AllocationSize\r
496 )\r
497{\r
498 return UncachedInternalAllocatePool (EfiRuntimeServicesData, AllocationSize);\r
499}\r
500\r
501VOID *\r
502EFIAPI\r
503UncachedAllocateReservedPool (\r
504 IN UINTN AllocationSize\r
505 )\r
506{\r
507 return UncachedInternalAllocatePool (EfiReservedMemoryType, AllocationSize);\r
508}\r
509\r
510VOID *\r
511UncachedInternalAllocateZeroPool (\r
512 IN EFI_MEMORY_TYPE PoolType, \r
513 IN UINTN AllocationSize\r
514 ) \r
515{\r
516 VOID *Memory;\r
517\r
518 Memory = UncachedInternalAllocatePool (PoolType, AllocationSize);\r
519 if (Memory != NULL) {\r
520 Memory = ZeroMem (Memory, AllocationSize);\r
521 }\r
522 return Memory;\r
523}\r
524\r
525VOID *\r
526EFIAPI\r
527UncachedAllocateZeroPool (\r
528 IN UINTN AllocationSize\r
529 )\r
530{\r
531 return UncachedInternalAllocateZeroPool (EfiBootServicesData, AllocationSize);\r
532}\r
533\r
534VOID *\r
535EFIAPI\r
536UncachedAllocateRuntimeZeroPool (\r
537 IN UINTN AllocationSize\r
538 )\r
539{\r
540 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);\r
541}\r
542\r
543VOID *\r
544EFIAPI\r
545UncachedAllocateReservedZeroPool (\r
546 IN UINTN AllocationSize\r
547 )\r
548{\r
549 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize);\r
550}\r
551\r
552VOID *\r
553UncachedInternalAllocateCopyPool (\r
554 IN EFI_MEMORY_TYPE PoolType, \r
555 IN UINTN AllocationSize,\r
556 IN CONST VOID *Buffer\r
557 ) \r
558{\r
559 VOID *Memory;\r
560\r
561 ASSERT (Buffer != NULL);\r
562 ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));\r
563\r
564 Memory = UncachedInternalAllocatePool (PoolType, AllocationSize);\r
565 if (Memory != NULL) {\r
566 Memory = CopyMem (Memory, Buffer, AllocationSize);\r
567 }\r
568 return Memory;\r
569} \r
570\r
571VOID *\r
572EFIAPI\r
573UncachedAllocateCopyPool (\r
574 IN UINTN AllocationSize,\r
575 IN CONST VOID *Buffer\r
576 )\r
577{\r
578 return UncachedInternalAllocateCopyPool (EfiBootServicesData, AllocationSize, Buffer);\r
579}\r
580\r
581VOID *\r
582EFIAPI\r
583UncachedAllocateRuntimeCopyPool (\r
584 IN UINTN AllocationSize,\r
585 IN CONST VOID *Buffer\r
586 )\r
587{\r
588 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);\r
589}\r
590\r
591VOID *\r
592EFIAPI\r
593UncachedAllocateReservedCopyPool (\r
594 IN UINTN AllocationSize,\r
595 IN CONST VOID *Buffer\r
596 )\r
597{\r
598 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer);\r
599}\r
600\r
601VOID\r
602EFIAPI\r
603UncachedFreePool (\r
604 IN VOID *Buffer\r
605 )\r
606{\r
607 UncachedFreeAlignedPool (Buffer);\r
608}\r
609\r
610VOID\r
611EFIAPI\r
612UncachedSafeFreePool (\r
613 IN VOID *Buffer\r
614 )\r
615{\r
616 if (Buffer != NULL) {\r
617 UncachedFreePool (Buffer);\r
618 Buffer = NULL;\r
619 }\r
620}\r
621\r
622/**\r
623 The constructor function caches the pointer of DXE Services Table.\r
624\r
625 The constructor function caches the pointer of DXE Services Table.\r
626 It will ASSERT() if that operation fails.\r
627 It will ASSERT() if the pointer of DXE Services Table is NULL.\r
628 It will always return EFI_SUCCESS.\r
629\r
630 @param ImageHandle The firmware allocated handle for the EFI image.\r
631 @param SystemTable A pointer to the EFI System Table.\r
632\r
633 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
634\r
635**/\r
636EFI_STATUS\r
637EFIAPI\r
638DebugUncachedMemoryAllocationLibConstructor (\r
639 IN EFI_HANDLE ImageHandle,\r
640 IN EFI_SYSTEM_TABLE *SystemTable\r
641 )\r
642{\r
643 EFI_STATUS Status;\r
644 \r
f659880b 645 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gDebugUncachedCpu);\r
965626c9
A
646 ASSERT_EFI_ERROR(Status);\r
647\r
648 Status = gBS->LocateProtocol (&gVirtualUncachedPagesProtocolGuid, NULL, (VOID **)&gVirtualUncachedPages);\r
649 ASSERT_EFI_ERROR(Status);\r
650\r
651 return Status;\r
652}\r
653\r
654\r
655\r