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