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