2 Support routines for memory allocation routines for use with drivers.
4 Copyright (c) 2006, Intel Corporation<BR>
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
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.
13 Module Name: MemoryAllocationLib.c
20 Allocates the number of 4KB pages specified by Pages of a certain memory type.
22 @param MemoryType The type of memory to allocate.
23 @param Pages The number of 4 KB pages to allocate.
25 @return A pointer to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
26 If Pages is 0, then NULL is returned.
27 If there is not enough memory remaining to satisfy the request, then NULL is returned.
31 InternalAllocatePages (
32 IN EFI_MEMORY_TYPE MemoryType
,
37 EFI_PHYSICAL_ADDRESS Memory
;
38 EFI_PEI_SERVICES
**PeiServices
;
44 PeiServices
= GetPeiServicesTablePointer ();
45 Status
= (*PeiServices
)->AllocatePages (PeiServices
, MemoryType
, Pages
, &Memory
);
46 if (EFI_ERROR (Status
)) {
49 return (VOID
*) (UINTN
) Memory
;
53 Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData.
55 @param Pages The number of 4 KB pages to allocate.
57 @return A pointer to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
58 If Pages is 0, then NULL is returned.
59 If there is not enough memory remaining to satisfy the request, then NULL is returned.
68 return InternalAllocatePages (EfiBootServicesData
, Pages
);
72 Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData.
74 @param Pages The number of 4 KB pages to allocate.
76 @return A pointer to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
77 If Pages is 0, then NULL is returned.
78 If there is not enough memory remaining to satisfy the request, then NULL is returned.
83 AllocateRuntimePages (
87 return InternalAllocatePages (EfiRuntimeServicesData
, Pages
);
91 Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType.
93 @param Pages The number of 4 KB pages to allocate.
95 @return A pointer to the allocated buffer. The buffer returned is aligned on a 4KB boundary.
96 If Pages is 0, then NULL is returned.
97 If there is not enough memory remaining to satisfy the request, then NULL is returned.
102 AllocateReservedPages (
106 return InternalAllocatePages (EfiReservedMemoryType
, Pages
);
110 Frees one or more 4KB pages that were previously allocated with
111 one of the page allocation functions in the Memory Allocation Library.
113 @param Buffer Pointer to the buffer of pages to free.
114 @param Pages The number of 4 KB pages to free.
125 // PEI phase does not support to free pages, so leave it as NOP.
130 Allocates the number of 4KB pages specified by Pages of a certian memory type
131 with an alignment specified by Alignment.
133 @param MemoryType The type of memory to allocate.
134 @param Pages The number of 4 KB pages to allocate.
135 @param Alignment The requested alignment of the allocation. Must be a power of two.
136 If Alignment is zero, then byte alignment is used.
138 @return The allocated buffer is returned. If Pages is 0, then NULL is returned.
139 If there is not enough memory at the specified alignment remaining to satisfy the request, then NULL is returned.
143 InternalAllocateAlignedPages (
144 IN EFI_MEMORY_TYPE MemoryType
,
153 // Alignment must be a power of two or zero.
155 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
161 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
163 ASSERT (Pages
<= (MAX_ADDRESS
- EFI_SIZE_TO_PAGES (Alignment
)));
165 // We would rather waste some memory to save PEI code size.
167 Memory
= InternalAllocatePages (MemoryType
, Pages
+ EFI_SIZE_TO_PAGES (Alignment
));
168 if (Alignment
== 0) {
169 AlignmentMask
= Alignment
;
171 AlignmentMask
= Alignment
- 1;
173 return (VOID
*) (UINTN
) (((UINTN
) Memory
+ AlignmentMask
) & ~AlignmentMask
);
177 Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData
178 with an alignment specified by Alignment.
180 @param Pages The number of 4 KB pages to allocate.
181 @param Alignment The requested alignment of the allocation. Must be a power of two.
182 If Alignment is zero, then byte alignment is used.
184 @return The allocated buffer is returned. If Pages is 0, then NULL is returned.
185 If there is not enough memory at the specified alignment remaining to satisfy the request, then NULL is returned.
190 AllocateAlignedPages (
195 return InternalAllocateAlignedPages (EfiBootServicesData
, Pages
, Alignment
);
199 Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData
200 with an alignment specified by Alignment.
202 @param Pages The number of 4 KB pages to allocate.
203 @param Alignment The requested alignment of the allocation. Must be a power of two.
204 If Alignment is zero, then byte alignment is used.
206 @return The allocated buffer is returned. If Pages is 0, then NULL is returned.
207 If there is not enough memory at the specified alignment remaining to satisfy the request, then NULL is returned.
212 AllocateAlignedRuntimePages (
217 return InternalAllocateAlignedPages (EfiRuntimeServicesData
, Pages
, Alignment
);
221 Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment.
223 @param Pages The number of 4 KB pages to allocate.
224 @param Alignment The requested alignment of the allocation. Must be a power of two.
225 If Alignment is zero, then byte alignment is used.
227 @return The allocated buffer is returned. If Pages is 0, then NULL is returned.
228 If there is not enough memory at the specified alignment remaining to satisfy the request, then NULL is returned.
233 AllocateAlignedReservedPages (
238 return InternalAllocateAlignedPages (EfiReservedMemoryType
, Pages
, Alignment
);
242 Frees one or more 4KB pages that were previously allocated with
243 one of the aligned page allocation functions in the Memory Allocation Library.
245 @param Buffer Pointer to the buffer of pages to free.
246 @param Pages The number of 4 KB pages to free.
257 // PEI phase does not support to free pages, so leave it as NOP.
262 Allocates a buffer of a certain memory type.
264 @param MemoryType The type of memory to allocate.
265 @param AllocationSize The number of bytes to allocate.
267 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
268 If there is not enough memory remaining to satisfy the request, then NULL is returned.
272 InternalAllocatePool (
273 IN EFI_MEMORY_TYPE MemoryType
,
274 IN UINTN AllocationSize
278 // If we need lots of small runtime/reserved memory type from PEI in the future,
279 // we can consider providing a more complex algorithm that allocates runtime pages and
280 // provide pool allocations from those pages.
282 return InternalAllocatePages (MemoryType
, EFI_SIZE_TO_PAGES (AllocationSize
));
286 Allocates a buffer of type EfiBootServicesData.
288 @param AllocationSize The number of bytes to allocate.
290 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
291 If there is not enough memory remaining to satisfy the request, then NULL is returned.
297 IN UINTN AllocationSize
301 EFI_PEI_SERVICES
**PeiServices
;
304 PeiServices
= GetPeiServicesTablePointer ();
306 Status
= (*PeiServices
)->AllocatePool (PeiServices
, AllocationSize
, &Buffer
);
307 if (EFI_ERROR (Status
)) {
314 Allocates a buffer of type EfiRuntimeServicesData.
316 @param AllocationSize The number of bytes to allocate.
318 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
319 If there is not enough memory remaining to satisfy the request, then NULL is returned.
324 AllocateRuntimePool (
325 IN UINTN AllocationSize
328 return InternalAllocatePool (EfiRuntimeServicesData
, AllocationSize
);
332 Allocates a buffer of type EfiReservedMemoryType.
334 @param AllocationSize The number of bytes to allocate.
336 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
337 If there is not enough memory remaining to satisfy the request, then NULL is returned.
342 AllocateReservedPool (
343 IN UINTN AllocationSize
346 return InternalAllocatePool (EfiReservedMemoryType
, AllocationSize
);
350 Allocates and zeros a buffer of a certian pool type.
352 @param PoolType The type of memory to allocate.
353 @param AllocationSize The number of bytes to allocate and zero.
355 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
356 If there is not enough memory remaining to satisfy the request, then NULL is returned.
360 InternalAllocateZeroPool (
361 IN EFI_MEMORY_TYPE PoolType
,
362 IN UINTN AllocationSize
367 Memory
= InternalAllocatePool (PoolType
, AllocationSize
);
368 if (Memory
!= NULL
) {
369 Memory
= ZeroMem (Memory
, AllocationSize
);
375 Allocates and zeros a buffer of type EfiBootServicesData.
377 @param AllocationSize The number of bytes to allocate and zero.
379 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
380 If there is not enough memory remaining to satisfy the request, then NULL is returned.
386 IN UINTN AllocationSize
391 Memory
= AllocatePool (AllocationSize
);
392 if (Memory
!= NULL
) {
393 Memory
= ZeroMem (Memory
, AllocationSize
);
399 Allocates and zeros a buffer of type EfiRuntimeServicesData.
401 @param AllocationSize The number of bytes to allocate and zero.
403 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
404 If there is not enough memory remaining to satisfy the request, then NULL is returned.
409 AllocateRuntimeZeroPool (
410 IN UINTN AllocationSize
413 return InternalAllocateZeroPool (EfiRuntimeServicesData
, AllocationSize
);
417 Allocates and zeros a buffer of type EfiReservedMemoryType.
419 @param AllocationSize The number of bytes to allocate and zero.
421 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
422 If there is not enough memory remaining to satisfy the request, then NULL is returned.
427 AllocateReservedZeroPool (
428 IN UINTN AllocationSize
431 return InternalAllocateZeroPool (EfiReservedMemoryType
, AllocationSize
);
435 Copies a buffer to an allocated buffer of a certian memory type.
437 @param MemoryType The type of pool to allocate.
438 @param AllocationSize The number of bytes to allocate and zero.
439 @param Buffer The buffer to copy to the allocated buffer.
441 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
442 If there is not enough memory remaining to satisfy the request, then NULL is returned.
446 InternalAllocateCopyPool (
447 IN EFI_MEMORY_TYPE PoolType
,
448 IN UINTN AllocationSize
,
449 IN CONST VOID
*Buffer
454 ASSERT (Buffer
!= NULL
);
455 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
457 Memory
= InternalAllocatePool (PoolType
, AllocationSize
);
458 if (Memory
!= NULL
) {
459 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
465 Copies a buffer to an allocated buffer of type EfiBootServicesData.
467 @param AllocationSize The number of bytes to allocate.
468 @param Buffer The buffer to copy to the allocated buffer.
470 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
471 If there is not enough memory remaining to satisfy the request, then NULL is returned.
477 IN UINTN AllocationSize
,
478 IN CONST VOID
*Buffer
483 ASSERT (Buffer
!= NULL
);
484 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
486 Memory
= AllocatePool (AllocationSize
);
487 if (Memory
!= NULL
) {
488 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
494 Copies a buffer to an allocated buffer of type EfiRuntimeServicesData.
496 @param AllocationSize The number of bytes to allocate.
497 @param Buffer The buffer to copy to the allocated buffer.
499 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
500 If there is not enough memory remaining to satisfy the request, then NULL is returned.
505 AllocateRuntimeCopyPool (
506 IN UINTN AllocationSize
,
507 IN CONST VOID
*Buffer
510 return InternalAllocateCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
);
514 Copies a buffer to an allocated buffer of type EfiReservedMemoryType.
516 @param AllocationSize The number of bytes to allocate.
517 @param Buffer The buffer to copy to the allocated buffer.
519 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
520 If there is not enough memory remaining to satisfy the request, then NULL is returned.
525 AllocateReservedCopyPool (
526 IN UINTN AllocationSize
,
527 IN CONST VOID
*Buffer
530 return InternalAllocateCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
);
534 Copies a buffer to an allocated buffer of type EfiReservedMemoryType at a specified alignment.
536 @param Buffer Pointer to the buffer to free.
546 // PEI phase does not support to free pool, so leave it as NOP.
551 Allocates a buffer of a certain pool type at a specified alignment.
553 @param PoolType The type of pool to allocate.
554 @param AllocationSize The number of bytes to allocate.
555 @param Alignment The requested alignment of the allocation. Must be a power of two. If Alignment is zero, then byte alignment is used.
557 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
558 If there is not enough memory remaining to satisfy the request, then NULL is returned.
562 InternalAllocateAlignedPool (
563 IN EFI_MEMORY_TYPE PoolType
,
564 IN UINTN AllocationSize
,
569 UINTN AlignedAddress
;
573 // Alignment must be a power of two or zero.
575 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
577 if (Alignment
== 0) {
578 AlignmentMask
= Alignment
;
580 AlignmentMask
= Alignment
- 1;
583 // Make sure that AllocationSize plus AlignmentMask does not overflow.
585 ASSERT (AllocationSize
<= (MAX_ADDRESS
- AlignmentMask
));
587 RawAddress
= InternalAllocatePool (PoolType
, AllocationSize
+ AlignmentMask
);
589 AlignedAddress
= ((UINTN
) RawAddress
+ AlignmentMask
) & ~AlignmentMask
;
591 return (VOID
*) AlignedAddress
;
595 Allocates a buffer of type EfiBootServicesData at a specified alignment.
597 @param AllocationSize The number of bytes to allocate.
598 @param Alignment The requested alignment of the allocation. Must be a power of two. If Alignment is zero, then byte alignment is used.
600 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
601 If there is not enough memory remaining to satisfy the request, then NULL is returned.
606 AllocateAlignedPool (
607 IN UINTN AllocationSize
,
612 UINTN AlignedAddress
;
616 // Alignment must be a power of two or zero.
618 ASSERT ((Alignment
& (Alignment
- 1)) == 0);
620 if (Alignment
== 0) {
621 AlignmentMask
= Alignment
;
623 AlignmentMask
= Alignment
- 1;
627 // Make sure that AllocationSize plus AlignmentMask does not overflow.
629 ASSERT (AllocationSize
<= (MAX_ADDRESS
- AlignmentMask
));
631 RawAddress
= AllocatePool (AllocationSize
+ AlignmentMask
);
633 AlignedAddress
= ((UINTN
) RawAddress
+ AlignmentMask
) & ~AlignmentMask
;
635 return (VOID
*) AlignedAddress
;
639 Allocates a buffer of type EfiRuntimeServicesData at a specified alignment.
641 @param AllocationSize The number of bytes to allocate.
642 @param Alignment The requested alignment of the allocation. Must be a power of two.
643 If Alignment is zero, then byte alignment is used.
645 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
646 If there is not enough memory remaining to satisfy the request, then NULL is returned.
651 AllocateAlignedRuntimePool (
652 IN UINTN AllocationSize
,
656 return InternalAllocateAlignedPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
660 Allocates a buffer of type EfiReservedMemoryType at a specified alignment.
662 @param AllocationSize The number of bytes to allocate.
663 @param Alignment The requested alignment of the allocation. Must be a power of two.
664 If Alignment is zero, then byte alignment is used.
666 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
667 If there is not enough memory remaining to satisfy the request, then NULL is returned.
672 AllocateAlignedReservedPool (
673 IN UINTN AllocationSize
,
677 return InternalAllocateAlignedPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
681 Allocates and zeros a buffer of type EfiBootServicesData at a specified alignment.
683 @param PoolType The type of pool to allocate.
684 @param AllocationSize The number of bytes to allocate.
685 @param Alignment The requested alignment of the allocation. Must be a power of two.
686 If Alignment is zero, then byte alignment is used.
688 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
689 If there is not enough memory remaining to satisfy the request, then NULL is returned.
693 InternalAllocateAlignedZeroPool (
694 IN EFI_MEMORY_TYPE PoolType
,
695 IN UINTN AllocationSize
,
701 Memory
= InternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
702 if (Memory
!= NULL
) {
703 Memory
= ZeroMem (Memory
, AllocationSize
);
709 Allocates and zeros a buffer of type EfiBootServicesData at a specified alignment.
711 @param AllocationSize The number of bytes to allocate.
712 @param Alignment The requested alignment of the allocation. Must be a power of two.
713 If Alignment is zero, then byte alignment is used.
715 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
716 If there is not enough memory remaining to satisfy the request, then NULL is returned.
721 AllocateAlignedZeroPool (
722 IN UINTN AllocationSize
,
728 Memory
= AllocateAlignedPool (AllocationSize
, Alignment
);
729 if (Memory
!= NULL
) {
730 Memory
= ZeroMem (Memory
, AllocationSize
);
736 Allocates and zeros a buffer of type EfiRuntimeServicesData at a specified alignment.
738 @param AllocationSize The number of bytes to allocate.
739 @param Alignment The requested alignment of the allocation. Must be a power of two.
740 If Alignment is zero, then byte alignment is used.
742 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
743 If there is not enough memory remaining to satisfy the request, then NULL is returned.
748 AllocateAlignedRuntimeZeroPool (
749 IN UINTN AllocationSize
,
753 return InternalAllocateAlignedZeroPool (EfiRuntimeServicesData
, AllocationSize
, Alignment
);
757 Allocates and zeros a buffer of type EfiReservedMemoryType at a specified alignment.
759 @param AllocationSize The number of bytes to allocate.
760 @param Alignment The requested alignment of the allocation. Must be a power of two.
761 If Alignment is zero, then byte alignment is used.
763 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
764 If there is not enough memory remaining to satisfy the request, then NULL is returned.
769 AllocateAlignedReservedZeroPool (
770 IN UINTN AllocationSize
,
774 return InternalAllocateAlignedZeroPool (EfiReservedMemoryType
, AllocationSize
, Alignment
);
778 Copies a buffer to an allocated buffer of type EfiBootServicesData at a specified alignment.
780 @param PoolType The type of pool to allocate.
781 @param AllocationSize The number of bytes to allocate.
782 @param Buffer The buffer to copy to the allocated buffer.
783 @param Alignment The requested alignment of the allocation. Must be a power of two.
784 If Alignment is zero, then byte alignment is used.
786 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
787 If there is not enough memory remaining to satisfy the request, then NULL is returned.
791 InternalAllocateAlignedCopyPool (
792 IN EFI_MEMORY_TYPE PoolType
,
793 IN UINTN AllocationSize
,
794 IN CONST VOID
*Buffer
,
800 ASSERT (Buffer
!= NULL
);
801 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
803 Memory
= InternalAllocateAlignedPool (PoolType
, AllocationSize
, Alignment
);
804 if (Memory
!= NULL
) {
805 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
811 Copies a buffer to an allocated buffer of type EfiBootServicesData at a specified alignment.
813 @param AllocationSize The number of bytes to allocate.
814 @param Buffer The buffer to copy to the allocated buffer.
815 @param Alignment The requested alignment of the allocation. Must be a power of two.
816 If Alignment is zero, then byte alignment is used.
818 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
819 If there is not enough memory remaining to satisfy the request, then NULL is returned.
824 AllocateAlignedCopyPool (
825 IN UINTN AllocationSize
,
826 IN CONST VOID
*Buffer
,
832 ASSERT (Buffer
!= NULL
);
833 ASSERT (AllocationSize
<= (MAX_ADDRESS
- (UINTN
) Buffer
+ 1));
835 Memory
= AllocateAlignedPool (AllocationSize
, Alignment
);
836 if (Memory
!= NULL
) {
837 Memory
= CopyMem (Memory
, Buffer
, AllocationSize
);
843 Copies a buffer to an allocated buffer of type EfiRuntimeServicesData at a specified alignment.
845 @param AllocationSize The number of bytes to allocate.
846 @param Buffer The buffer to copy to the allocated buffer.
847 @param Alignment The requested alignment of the allocation. Must be a power of two.
848 If Alignment is zero, then byte alignment is used.
850 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
851 If there is not enough memory remaining to satisfy the request, then NULL is returned.
856 AllocateAlignedRuntimeCopyPool (
857 IN UINTN AllocationSize
,
858 IN CONST VOID
*Buffer
,
862 return InternalAllocateAlignedCopyPool (EfiRuntimeServicesData
, AllocationSize
, Buffer
, Alignment
);
866 Copies a buffer to an allocated buffer of type EfiReservedMemoryType at a specified alignment.
868 @param AllocationSize The number of bytes to allocate.
869 @param Buffer The buffer to copy to the allocated buffer.
870 @param Alignment The requested alignment of the allocation. Must be a power of two.
871 If Alignment is zero, then byte alignment is used.
873 @return A pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned.
874 If there is not enough memory remaining to satisfy the request, then NULL is returned.
879 AllocateAlignedReservedCopyPool (
880 IN UINTN AllocationSize
,
881 IN CONST VOID
*Buffer
,
885 return InternalAllocateAlignedCopyPool (EfiReservedMemoryType
, AllocationSize
, Buffer
, Alignment
);
889 Frees a buffer that was previously allocated with one of the aligned pool allocation functions
890 in the Memory Allocation Library.
892 @param Buffer Pointer to the buffer to free.
902 // PEI phase does not support to free pool, so leave it as NOP.