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