]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.c
Seems the BiosVideo thunk does not work recently, temporary disable it.
[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
13 Copyright (c) 2008-2010, Apple Inc. All rights reserved.\r
14 \r
15 All rights reserved. This program and the accompanying materials\r
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
86 \r
87 InsertTailList (&mPageList, &NewNode->Link);\r
88}\r
89\r
90\r
91VOID\r
92RemovePagesFromList (\r
93 IN VOID *Buffer,\r
94 OUT VOID **Allocation,\r
95 OUT UINTN *Pages\r
96 )\r
97{\r
98 LIST_ENTRY *Link;\r
99 FREE_PAGE_NODE *OldNode;\r
100\r
101 *Allocation = NULL;\r
102 *Pages = 0;\r
103 \r
104 for (Link = mPageList.ForwardLink; Link != &mPageList; Link = Link->ForwardLink) {\r
105 OldNode = BASE_CR (Link, FREE_PAGE_NODE, Link);\r
106 if (OldNode->Buffer == Buffer) {\r
107 *Allocation = OldNode->Allocation;\r
108 *Pages = OldNode->Pages;\r
109 \r
110 RemoveEntryList (&OldNode->Link);\r
111 FreePool (OldNode);\r
112 return;\r
113 }\r
114 }\r
115\r
116 return;\r
117}\r
118\r
119\r
120\r
121EFI_PHYSICAL_ADDRESS\r
122ConvertToPhysicalAddress (\r
123 IN VOID *VirtualAddress\r
124 )\r
125{\r
126 UINTN UncachedMemoryMask = (UINTN)PcdGet64 (PcdArmUncachedMemoryMask);\r
127 UINTN PhysicalAddress;\r
128 \r
129 PhysicalAddress = (UINTN)VirtualAddress & ~UncachedMemoryMask;\r
130 \r
131 return (EFI_PHYSICAL_ADDRESS)PhysicalAddress;\r
132}\r
133\r
134\r
135VOID *\r
136ConvertToUncachedAddress (\r
137 IN VOID *Address\r
138 )\r
139{\r
140 UINTN UncachedMemoryMask = (UINTN)PcdGet64 (PcdArmUncachedMemoryMask);\r
141 UINTN UncachedAddress;\r
142 \r
143 UncachedAddress = (UINTN)Address | UncachedMemoryMask;\r
144 \r
145 return (VOID *)UncachedAddress;\r
146}\r
147\r
148\r
149\r
150VOID *\r
151UncachedInternalAllocatePages (\r
152 IN EFI_MEMORY_TYPE MemoryType, \r
153 IN UINTN Pages\r
154 )\r
155{\r
156 return UncachedInternalAllocateAlignedPages (MemoryType, Pages, EFI_PAGE_SIZE);\r
157}\r
158\r
159\r
160VOID *\r
161EFIAPI\r
162UncachedAllocatePages (\r
163 IN UINTN Pages\r
164 )\r
165{\r
166 return UncachedInternalAllocatePages (EfiBootServicesData, Pages);\r
167}\r
168\r
169VOID *\r
170EFIAPI\r
171UncachedAllocateRuntimePages (\r
172 IN UINTN Pages\r
173 )\r
174{\r
175 return UncachedInternalAllocatePages (EfiRuntimeServicesData, Pages);\r
176}\r
177\r
178VOID *\r
179EFIAPI\r
180UncachedAllocateReservedPages (\r
181 IN UINTN Pages\r
182 )\r
183{\r
184 return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
185}\r
186\r
187\r
188\r
189VOID\r
190EFIAPI\r
191UncachedFreePages (\r
192 IN VOID *Buffer,\r
193 IN UINTN Pages\r
194 )\r
195{\r
196 UncachedFreeAlignedPages (Buffer, Pages);\r
197 return;\r
198}\r
199\r
200\r
201VOID *\r
202UncachedInternalAllocateAlignedPages (\r
203 IN EFI_MEMORY_TYPE MemoryType, \r
204 IN UINTN Pages,\r
205 IN UINTN Alignment\r
206 )\r
207{\r
208 EFI_STATUS Status;\r
209 EFI_PHYSICAL_ADDRESS Memory;\r
210 EFI_PHYSICAL_ADDRESS AlignedMemory;\r
211 UINTN AlignmentMask;\r
212 UINTN UnalignedPages;\r
213 UINTN RealPages;\r
214\r
215 //\r
216 // Alignment must be a power of two or zero.\r
217 //\r
218 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
219 \r
220 if (Pages == 0) {\r
221 return NULL;\r
222 }\r
223 if (Alignment > EFI_PAGE_SIZE) {\r
224 //\r
225 // Caculate the total number of pages since alignment is larger than page size.\r
226 //\r
227 AlignmentMask = Alignment - 1;\r
228 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
229 //\r
230 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
231 //\r
232 ASSERT (RealPages > Pages);\r
233 \r
234 Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);\r
235 if (EFI_ERROR (Status)) {\r
236 return NULL;\r
237 }\r
238 AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
239 UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
240 if (UnalignedPages > 0) {\r
241 //\r
242 // Free first unaligned page(s).\r
243 //\r
244 Status = gBS->FreePages (Memory, UnalignedPages);\r
245 ASSERT_EFI_ERROR (Status);\r
246 }\r
247 Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
248 UnalignedPages = RealPages - Pages - UnalignedPages;\r
249 if (UnalignedPages > 0) {\r
250 //\r
251 // Free last unaligned page(s).\r
252 //\r
253 Status = gBS->FreePages (Memory, UnalignedPages);\r
254 ASSERT_EFI_ERROR (Status);\r
255 }\r
256 } else {\r
257 //\r
258 // Do not over-allocate pages in this case.\r
259 //\r
260 Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);\r
261 if (EFI_ERROR (Status)) {\r
262 return NULL;\r
263 }\r
264 AlignedMemory = (UINTN) Memory;\r
265 }\r
266 \r
267 Status = gVirtualUncachedPages->ConvertPages (gVirtualUncachedPages, AlignedMemory, Pages * EFI_PAGE_SIZE, PcdGet64 (PcdArmUncachedMemoryMask), &gAttributes);\r
268 if (EFI_ERROR (Status)) {\r
269 return NULL;\r
270 }\r
271 \r
272 AlignedMemory = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertToUncachedAddress ((VOID *)(UINTN)AlignedMemory);\r
273 \r
274 return (VOID *)(UINTN)AlignedMemory;\r
275}\r
276\r
277\r
278VOID\r
279EFIAPI\r
280UncachedFreeAlignedPages (\r
281 IN VOID *Buffer,\r
282 IN UINTN Pages\r
283 )\r
284{\r
285 EFI_STATUS Status;\r
286 EFI_PHYSICAL_ADDRESS Memory; \r
287\r
288 ASSERT (Pages != 0);\r
289 \r
290 Memory = ConvertToPhysicalAddress (Buffer);\r
291 \r
292 Status = gVirtualUncachedPages->RevertPages (gVirtualUncachedPages, Memory, Pages * EFI_PAGE_SIZE, PcdGet64 (PcdArmUncachedMemoryMask), gAttributes);\r
293\r
294 \r
295 Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
296 ASSERT_EFI_ERROR (Status);\r
297}\r
298\r
299\r
300\r
301\r
302VOID *\r
303UncachedInternalAllocateAlignedPool (\r
304 IN EFI_MEMORY_TYPE PoolType,\r
305 IN UINTN AllocationSize,\r
306 IN UINTN Alignment\r
307 )\r
308{\r
309 VOID *AlignedAddress;\r
310 \r
311 //\r
312 // Alignment must be a power of two or zero.\r
313 //\r
314 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
315\r
316 if (Alignment < EFI_PAGE_SIZE) {\r
317 Alignment = EFI_PAGE_SIZE;\r
318 }\r
319 \r
320 AlignedAddress = UncachedInternalAllocateAlignedPages (PoolType, EFI_SIZE_TO_PAGES (AllocationSize), Alignment);\r
321 if (AlignedAddress == NULL) {\r
322 return NULL;\r
323 }\r
324\r
325 AddPagesToList ((VOID *)(UINTN)ConvertToPhysicalAddress (AlignedAddress), (VOID *)(UINTN)AlignedAddress, EFI_SIZE_TO_PAGES (AllocationSize));\r
326\r
327 return (VOID *) AlignedAddress;\r
328}\r
329\r
330VOID *\r
331EFIAPI\r
332UncachedAllocateAlignedPool (\r
333 IN UINTN AllocationSize,\r
334 IN UINTN Alignment\r
335 )\r
336{\r
337 return UncachedInternalAllocateAlignedPool (EfiBootServicesData, AllocationSize, Alignment);\r
338}\r
339\r
340VOID *\r
341EFIAPI\r
342UncachedAllocateAlignedRuntimePool (\r
343 IN UINTN AllocationSize,\r
344 IN UINTN Alignment\r
345 )\r
346{\r
347 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData, AllocationSize, Alignment);\r
348}\r
349\r
350VOID *\r
351EFIAPI\r
352UncachedAllocateAlignedReservedPool (\r
353 IN UINTN AllocationSize,\r
354 IN UINTN Alignment\r
355 )\r
356{\r
357 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType, AllocationSize, Alignment);\r
358}\r
359\r
360VOID *\r
361UncachedInternalAllocateAlignedZeroPool (\r
362 IN EFI_MEMORY_TYPE PoolType,\r
363 IN UINTN AllocationSize,\r
364 IN UINTN Alignment\r
365 )\r
366{\r
367 VOID *Memory;\r
368 Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
369 if (Memory != NULL) {\r
370 Memory = ZeroMem (Memory, AllocationSize);\r
371 }\r
372 return Memory;\r
373}\r
374\r
375VOID *\r
376EFIAPI\r
377UncachedAllocateAlignedZeroPool (\r
378 IN UINTN AllocationSize,\r
379 IN UINTN Alignment\r
380 )\r
381{\r
382 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData, AllocationSize, Alignment);\r
383}\r
384\r
385VOID *\r
386EFIAPI\r
387UncachedAllocateAlignedRuntimeZeroPool (\r
388 IN UINTN AllocationSize,\r
389 IN UINTN Alignment\r
390 )\r
391{\r
392 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData, AllocationSize, Alignment);\r
393}\r
394\r
395VOID *\r
396EFIAPI\r
397UncachedAllocateAlignedReservedZeroPool (\r
398 IN UINTN AllocationSize,\r
399 IN UINTN Alignment\r
400 )\r
401{\r
402 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType, AllocationSize, Alignment);\r
403}\r
404\r
405VOID *\r
406UncachedInternalAllocateAlignedCopyPool (\r
407 IN EFI_MEMORY_TYPE PoolType,\r
408 IN UINTN AllocationSize,\r
409 IN CONST VOID *Buffer,\r
410 IN UINTN Alignment\r
411 )\r
412{\r
413 VOID *Memory;\r
414 \r
415 ASSERT (Buffer != NULL);\r
416 ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));\r
417\r
418 Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
419 if (Memory != NULL) {\r
420 Memory = CopyMem (Memory, Buffer, AllocationSize);\r
421 }\r
422 return Memory;\r
423}\r
424\r
425VOID *\r
426EFIAPI\r
427UncachedAllocateAlignedCopyPool (\r
428 IN UINTN AllocationSize,\r
429 IN CONST VOID *Buffer,\r
430 IN UINTN Alignment\r
431 )\r
432{\r
433 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData, AllocationSize, Buffer, Alignment);\r
434}\r
435\r
436VOID *\r
437EFIAPI\r
438UncachedAllocateAlignedRuntimeCopyPool (\r
439 IN UINTN AllocationSize,\r
440 IN CONST VOID *Buffer,\r
441 IN UINTN Alignment\r
442 )\r
443{\r
444 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer, Alignment);\r
445}\r
446\r
447VOID *\r
448EFIAPI\r
449UncachedAllocateAlignedReservedCopyPool (\r
450 IN UINTN AllocationSize,\r
451 IN CONST VOID *Buffer,\r
452 IN UINTN Alignment\r
453 )\r
454{\r
455 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType, AllocationSize, Buffer, Alignment);\r
456}\r
457\r
458VOID\r
459EFIAPI\r
460UncachedFreeAlignedPool (\r
461 IN VOID *Buffer\r
462 )\r
463{\r
464 VOID *Allocation;\r
465 UINTN Pages;\r
466 \r
467 RemovePagesFromList (Buffer, &Allocation, &Pages);\r
468\r
469 UncachedFreePages (Allocation, Pages);\r
470}\r
471\r
472VOID *\r
473UncachedInternalAllocatePool (\r
474 IN EFI_MEMORY_TYPE MemoryType, \r
475 IN UINTN AllocationSize\r
476 )\r
477{\r
478 UINTN CacheLineLength = ArmDataCacheLineLength ();\r
479 return UncachedInternalAllocateAlignedPool (MemoryType, AllocationSize, CacheLineLength);\r
480}\r
481\r
482VOID *\r
483EFIAPI\r
484UncachedAllocatePool (\r
485 IN UINTN AllocationSize\r
486 )\r
487{\r
488 return UncachedInternalAllocatePool (EfiBootServicesData, AllocationSize);\r
489}\r
490\r
491VOID *\r
492EFIAPI\r
493UncachedAllocateRuntimePool (\r
494 IN UINTN AllocationSize\r
495 )\r
496{\r
497 return UncachedInternalAllocatePool (EfiRuntimeServicesData, AllocationSize);\r
498}\r
499\r
500VOID *\r
501EFIAPI\r
502UncachedAllocateReservedPool (\r
503 IN UINTN AllocationSize\r
504 )\r
505{\r
506 return UncachedInternalAllocatePool (EfiReservedMemoryType, AllocationSize);\r
507}\r
508\r
509VOID *\r
510UncachedInternalAllocateZeroPool (\r
511 IN EFI_MEMORY_TYPE PoolType, \r
512 IN UINTN AllocationSize\r
513 ) \r
514{\r
515 VOID *Memory;\r
516\r
517 Memory = UncachedInternalAllocatePool (PoolType, AllocationSize);\r
518 if (Memory != NULL) {\r
519 Memory = ZeroMem (Memory, AllocationSize);\r
520 }\r
521 return Memory;\r
522}\r
523\r
524VOID *\r
525EFIAPI\r
526UncachedAllocateZeroPool (\r
527 IN UINTN AllocationSize\r
528 )\r
529{\r
530 return UncachedInternalAllocateZeroPool (EfiBootServicesData, AllocationSize);\r
531}\r
532\r
533VOID *\r
534EFIAPI\r
535UncachedAllocateRuntimeZeroPool (\r
536 IN UINTN AllocationSize\r
537 )\r
538{\r
539 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);\r
540}\r
541\r
542VOID *\r
543EFIAPI\r
544UncachedAllocateReservedZeroPool (\r
545 IN UINTN AllocationSize\r
546 )\r
547{\r
548 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize);\r
549}\r
550\r
551VOID *\r
552UncachedInternalAllocateCopyPool (\r
553 IN EFI_MEMORY_TYPE PoolType, \r
554 IN UINTN AllocationSize,\r
555 IN CONST VOID *Buffer\r
556 ) \r
557{\r
558 VOID *Memory;\r
559\r
560 ASSERT (Buffer != NULL);\r
561 ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));\r
562\r
563 Memory = UncachedInternalAllocatePool (PoolType, AllocationSize);\r
564 if (Memory != NULL) {\r
565 Memory = CopyMem (Memory, Buffer, AllocationSize);\r
566 }\r
567 return Memory;\r
568} \r
569\r
570VOID *\r
571EFIAPI\r
572UncachedAllocateCopyPool (\r
573 IN UINTN AllocationSize,\r
574 IN CONST VOID *Buffer\r
575 )\r
576{\r
577 return UncachedInternalAllocateCopyPool (EfiBootServicesData, AllocationSize, Buffer);\r
578}\r
579\r
580VOID *\r
581EFIAPI\r
582UncachedAllocateRuntimeCopyPool (\r
583 IN UINTN AllocationSize,\r
584 IN CONST VOID *Buffer\r
585 )\r
586{\r
587 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);\r
588}\r
589\r
590VOID *\r
591EFIAPI\r
592UncachedAllocateReservedCopyPool (\r
593 IN UINTN AllocationSize,\r
594 IN CONST VOID *Buffer\r
595 )\r
596{\r
597 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer);\r
598}\r
599\r
600VOID\r
601EFIAPI\r
602UncachedFreePool (\r
603 IN VOID *Buffer\r
604 )\r
605{\r
606 UncachedFreeAlignedPool (Buffer);\r
607}\r
608\r
609VOID\r
610EFIAPI\r
611UncachedSafeFreePool (\r
612 IN VOID *Buffer\r
613 )\r
614{\r
615 if (Buffer != NULL) {\r
616 UncachedFreePool (Buffer);\r
617 Buffer = NULL;\r
618 }\r
619}\r
620\r
621/**\r
622 The constructor function caches the pointer of DXE Services Table.\r
623\r
624 The constructor function caches the pointer of DXE Services Table.\r
625 It will ASSERT() if that operation fails.\r
626 It will ASSERT() if the pointer of DXE Services Table is NULL.\r
627 It will always return EFI_SUCCESS.\r
628\r
629 @param ImageHandle The firmware allocated handle for the EFI image.\r
630 @param SystemTable A pointer to the EFI System Table.\r
631\r
632 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
633\r
634**/\r
635EFI_STATUS\r
636EFIAPI\r
637DebugUncachedMemoryAllocationLibConstructor (\r
638 IN EFI_HANDLE ImageHandle,\r
639 IN EFI_SYSTEM_TABLE *SystemTable\r
640 )\r
641{\r
642 EFI_STATUS Status;\r
643 \r
f659880b 644 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gDebugUncachedCpu);\r
965626c9
A
645 ASSERT_EFI_ERROR(Status);\r
646\r
647 Status = gBS->LocateProtocol (&gVirtualUncachedPagesProtocolGuid, NULL, (VOID **)&gVirtualUncachedPages);\r
648 ASSERT_EFI_ERROR(Status);\r
649\r
650 return Status;\r
651}\r
652\r
653\r
654\r