Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:10

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsX8664AMD64EFI
0007  *
0008  * @brief EFI memory
0009  */
0010 
0011 /*
0012  * Copyright (C) 2023 Karel Gardas
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <bsp.h>
0037 #include <bsp/bootcard.h>
0038 
0039 #include <efi.h>
0040 #include <efilib.h>
0041 
0042 #include <stdio.h>
0043 
0044 extern Heap_Control *RTEMS_Malloc_Heap;
0045 
0046 void bsp_memory_heap_extend(void);
0047 
0048 extern EFI_BOOT_SERVICES        *BS;
0049 
0050 static UINT32 total_pages = 0;
0051 static UINT32 allocated_pages = 0;
0052 static UINT32 usable_pages = 0;
0053 static EFI_PHYSICAL_ADDRESS physBuf;
0054 
0055 static int error = 0;
0056 static int extension_steps = 0;
0057 
0058 #ifdef BSP_EFI_MMAP_PRINTOUT
0059 static const char*
0060 efi_memory_type(EFI_MEMORY_TYPE type);
0061 #endif
0062 
0063 void
0064 efi_memory_heap_extend( void );
0065 
0066 static UINT64
0067 heap_size(void)
0068 {
0069     return RTEMS_Malloc_Heap->stats.size;
0070 }
0071 
0072 static UINT64
0073 allocate_biggest_block( void )
0074 {
0075     UINT64 sz = 0;
0076     EFI_MEMORY_DESCRIPTOR *map = 0, *p = 0;
0077     UINTN key = 0, dsz = 0;
0078     UINT32 dver = 0;
0079     EFI_STATUS status = 0;
0080     int i, ndesc = 0;
0081 
0082     UINT64 to_alloc_pages = 0;
0083     bool first_run = false;
0084     if (total_pages == 0)
0085         first_run = true;
0086     // let's see available RAM
0087     status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
0088     if (status != EFI_BUFFER_TOO_SMALL) {
0089         printf("EFI: Can't determine memory map size\n");
0090         return 0;
0091     }
0092     map = malloc(sz);
0093     if (map == NULL) {
0094         printf("EFI: Can't allocate memory map backing\n");
0095         return 0;
0096     }
0097     status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
0098     if (EFI_ERROR(status)) {
0099         printf("EFI: Can't read memory map\n");
0100         free(map);
0101         return 0;
0102     }
0103     ndesc = sz / dsz;
0104 #ifdef BSP_EFI_MMAP_PRINTOUT
0105     if (first_run)
0106         printf("%23s %12s %8s\n", "Type", "Physical", "#Pages");
0107 #endif
0108     for (i = 0, p = map; i < ndesc;
0109          i++, p = NextMemoryDescriptor(p, dsz)) {
0110         if (first_run) {
0111 #ifdef BSP_EFI_MMAP_PRINTOUT
0112             printf("%23s %012jx %08jx\n", efi_memory_type(p->Type),
0113                    (uintmax_t)p->PhysicalStart, (uintmax_t)p->NumberOfPages);
0114 #endif
0115             if (p->Type != EfiReservedMemoryType)
0116                 total_pages = total_pages + p->NumberOfPages;
0117             if (p->Type == EfiConventionalMemory) {
0118                 usable_pages = usable_pages + p->NumberOfPages;
0119             }
0120         }
0121         if (p->Type == EfiConventionalMemory) {
0122             if (to_alloc_pages < p->NumberOfPages)
0123                 to_alloc_pages = p->NumberOfPages;
0124         }
0125     }
0126     status = ST->BootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, to_alloc_pages, &physBuf );
0127     if (EFI_ERROR(status)) {
0128         /* on some UEFI implementations it is not possible to allocate biggest available block
0129            for whatever reasons. In that case, let's go wild and attempt to allocate
0130            half of it */
0131         error++;
0132         status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, (to_alloc_pages / 2), &physBuf );
0133         if (EFI_ERROR(status)) {
0134             printf("EFI can't allocate: %lu pages nor half of the amount.\n", to_alloc_pages);
0135             free(map);
0136             return 0;
0137         }
0138         else {
0139             to_alloc_pages = to_alloc_pages / 2;
0140         }
0141     }
0142     allocated_pages = allocated_pages + to_alloc_pages;
0143     sz = to_alloc_pages * 4096;
0144     uintptr_t es = 0;
0145     es = _Heap_Extend( RTEMS_Malloc_Heap, (void *)physBuf, sz, 0 );
0146     free(map);
0147     return es;
0148 }
0149 
0150 void efi_memory_heap_extend( void )
0151 {
0152     int i;
0153     UINT64 asz = 0;
0154     UINT64 oldsz, newsz = 0;
0155     oldsz = heap_size();
0156     for (i = 0; i < 1024; i++) {
0157         /* let's try 1k alloc attempts */
0158         asz = allocate_biggest_block();
0159         if (asz == 0)
0160             break;
0161         extension_steps++;
0162     }
0163     newsz = heap_size();
0164     printf("EFI: Total memory: %u pages, %u megabytes\n", total_pages, (total_pages * 4 / 1024));
0165     printf("EFI: Usable memory: %u pages, %u megabytes\n", usable_pages, (usable_pages * 4 / 1024));
0166     printf("EFI: Allocated memory: %u pages, %u megabytes\n", allocated_pages, (allocated_pages * 4 / 1024));
0167     printf("RTEMS: Heap extended in %u steps with %u steps failed.\n", extension_steps, error);
0168     uint64_t s = newsz - oldsz;
0169     printf("RTEMS: Heap extended by %lu pages, %lu megabytes\n", (s / 4096), ((s / 1024) / 1024));
0170 }
0171 
0172 #ifdef BSP_EFI_MMAP_PRINTOUT
0173 static const char*
0174 efi_memory_type(EFI_MEMORY_TYPE type)
0175 {
0176     switch (type) {
0177     case EfiReservedMemoryType:
0178         return "Reserved";
0179     case EfiLoaderCode:
0180         return "LoaderCode";
0181     case EfiLoaderData:
0182         return "LoaderData";
0183     case EfiBootServicesCode:
0184         return "BootServicesCode";
0185     case EfiBootServicesData:
0186         return "BootServicesData";
0187     case EfiRuntimeServicesCode:
0188         return "RuntimeServicesCode";
0189     case EfiRuntimeServicesData:
0190         return "RuntimeServicesData";
0191     case EfiConventionalMemory:
0192         return "ConventionalMemory";
0193     case EfiUnusableMemory:
0194         return "UnusableMemory";
0195     case EfiACPIReclaimMemory:
0196         return "ACPIReclaimMemory";
0197     case EfiACPIMemoryNVS:
0198         return "ACPIMemoryNVS";
0199     case EfiMemoryMappedIO:
0200         return "MemoryMappedIO";
0201     case EfiMemoryMappedIOPortSpace:
0202         return "MemoryMappedIOPortSpace";
0203     case EfiPalCode:
0204         return "PalCode";
0205     case EfiPersistentMemory:
0206         return "PersistentMemory";
0207     default:
0208         return "Unknown Type";
0209     }
0210 }
0211 #endif