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