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