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