summaryrefslogtreecommitdiffstats
path: root/bsps/x86_64/amd64/start/efimem.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/x86_64/amd64/start/efimem.c')
-rw-r--r--bsps/x86_64/amd64/start/efimem.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/bsps/x86_64/amd64/start/efimem.c b/bsps/x86_64/amd64/start/efimem.c
new file mode 100644
index 0000000000..a6ec076a63
--- /dev/null
+++ b/bsps/x86_64/amd64/start/efimem.c
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2023 Karel Gardas
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bsp.h>
+#include <bsp/bootcard.h>
+
+#include <efi.h>
+#include <efilib.h>
+
+#include <stdio.h>
+
+extern Heap_Control *RTEMS_Malloc_Heap;
+
+void bsp_memory_heap_extend(void);
+
+extern EFI_BOOT_SERVICES *BS;
+
+static UINT32 total_pages = 0;
+static UINT32 allocated_pages = 0;
+static UINT32 usable_pages = 0;
+static EFI_PHYSICAL_ADDRESS physBuf;
+
+static int error = 0;
+static int extension_steps = 0;
+
+#ifdef BSP_EFI_MMAP_PRINTOUT
+static const char*
+efi_memory_type(EFI_MEMORY_TYPE type);
+#endif
+
+void
+efi_memory_heap_extend( void );
+
+static UINT64
+heap_size(void)
+{
+ return RTEMS_Malloc_Heap->stats.size;
+}
+
+static UINT64
+allocate_biggest_block( void )
+{
+ UINT64 sz = 0;
+ EFI_MEMORY_DESCRIPTOR *map = 0, *p = 0;
+ UINTN key = 0, dsz = 0;
+ UINT32 dver = 0;
+ EFI_STATUS status = 0;
+ int i, ndesc = 0;
+
+ UINT64 to_alloc_pages = 0;
+ bool first_run = false;
+ if (total_pages == 0)
+ first_run = true;
+ // let's see available RAM
+ status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ printf("EFI: Can't determine memory map size\n");
+ return 0;
+ }
+ map = malloc(sz);
+ if (map == NULL) {
+ printf("EFI: Can't allocate memory map backing\n");
+ return 0;
+ }
+ status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
+ if (EFI_ERROR(status)) {
+ printf("EFI: Can't read memory map\n");
+ free(map);
+ return 0;
+ }
+ ndesc = sz / dsz;
+#ifdef BSP_EFI_MMAP_PRINTOUT
+ if (first_run)
+ printf("%23s %12s %8s\n", "Type", "Physical", "#Pages");
+#endif
+ for (i = 0, p = map; i < ndesc;
+ i++, p = NextMemoryDescriptor(p, dsz)) {
+ if (first_run) {
+#ifdef BSP_EFI_MMAP_PRINTOUT
+ printf("%23s %012jx %08jx\n", efi_memory_type(p->Type),
+ (uintmax_t)p->PhysicalStart, (uintmax_t)p->NumberOfPages);
+#endif
+ if (p->Type != EfiReservedMemoryType)
+ total_pages = total_pages + p->NumberOfPages;
+ if (p->Type == EfiConventionalMemory) {
+ usable_pages = usable_pages + p->NumberOfPages;
+ }
+ }
+ if (p->Type == EfiConventionalMemory) {
+ if (to_alloc_pages < p->NumberOfPages)
+ to_alloc_pages = p->NumberOfPages;
+ }
+ }
+ status = ST->BootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, to_alloc_pages, &physBuf );
+ if (EFI_ERROR(status)) {
+ /* on some UEFI implementations it is not possible to allocate biggest available block
+ for whatever reasons. In that case, let's go wild and attempt to allocate
+ half of it */
+ error++;
+ status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, (to_alloc_pages / 2), &physBuf );
+ if (EFI_ERROR(status)) {
+ printf("EFI can't allocate: %lu pages nor half of the amount.\n", to_alloc_pages);
+ free(map);
+ return 0;
+ }
+ else {
+ to_alloc_pages = to_alloc_pages / 2;
+ }
+ }
+ allocated_pages = allocated_pages + to_alloc_pages;
+ sz = to_alloc_pages * 4096;
+ uintptr_t es = 0;
+ es = _Heap_Extend( RTEMS_Malloc_Heap, (void *)physBuf, sz, 0 );
+ free(map);
+ return es;
+}
+
+void efi_memory_heap_extend( void )
+{
+ int i;
+ UINT64 asz = 0;
+ UINT64 oldsz, newsz = 0;
+ oldsz = heap_size();
+ for (i = 0; i < 1024; i++) {
+ /* let's try 1k alloc attempts */
+ asz = allocate_biggest_block();
+ if (asz == 0)
+ break;
+ extension_steps++;
+ }
+ newsz = heap_size();
+ printf("EFI: Total memory: %u pages, %u megabytes\n", total_pages, (total_pages * 4 / 1024));
+ printf("EFI: Usable memory: %u pages, %u megabytes\n", usable_pages, (usable_pages * 4 / 1024));
+ printf("EFI: Allocated memory: %u pages, %u megabytes\n", allocated_pages, (allocated_pages * 4 / 1024));
+ printf("RTEMS: Heap extended in %u steps with %u steps failed.\n", extension_steps, error);
+ uint64_t s = newsz - oldsz;
+ printf("RTEMS: Heap extended by %lu pages, %lu megabytes\n", (s / 4096), ((s / 1024) / 1024));
+}
+
+#ifdef BSP_EFI_MMAP_PRINTOUT
+static const char*
+efi_memory_type(EFI_MEMORY_TYPE type)
+{
+ switch (type) {
+ case EfiReservedMemoryType:
+ return "Reserved";
+ case EfiLoaderCode:
+ return "LoaderCode";
+ case EfiLoaderData:
+ return "LoaderData";
+ case EfiBootServicesCode:
+ return "BootServicesCode";
+ case EfiBootServicesData:
+ return "BootServicesData";
+ case EfiRuntimeServicesCode:
+ return "RuntimeServicesCode";
+ case EfiRuntimeServicesData:
+ return "RuntimeServicesData";
+ case EfiConventionalMemory:
+ return "ConventionalMemory";
+ case EfiUnusableMemory:
+ return "UnusableMemory";
+ case EfiACPIReclaimMemory:
+ return "ACPIReclaimMemory";
+ case EfiACPIMemoryNVS:
+ return "ACPIMemoryNVS";
+ case EfiMemoryMappedIO:
+ return "MemoryMappedIO";
+ case EfiMemoryMappedIOPortSpace:
+ return "MemoryMappedIOPortSpace";
+ case EfiPalCode:
+ return "PalCode";
+ case EfiPersistentMemory:
+ return "PersistentMemory";
+ default:
+ return "Unknown Type";
+ }
+}
+#endif