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