git: 92ad79ec33fb - main - kboot: Move common EFI stuff from aarch64 to libkboot
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 17 Apr 2025 21:59:17 UTC
The branch main has been updated by imp:
URL: https://cgit.FreeBSD.org/src/commit/?id=92ad79ec33fb5caf9a79c0bd8b33697b34c8e26d
commit 92ad79ec33fb5caf9a79c0bd8b33697b34c8e26d
Author: Warner Losh <imp@FreeBSD.org>
AuthorDate: 2025-04-17 04:04:31 +0000
Commit: Warner Losh <imp@FreeBSD.org>
CommitDate: 2025-04-17 21:56:46 +0000
kboot: Move common EFI stuff from aarch64 to libkboot
Move efi_read_from_pa, efi_set_systbl and efi_bi_loadsmap into efi.c
Move prototype for populate_avail_from_efi as well, though that arrived
previously.
Move efi memory map variables into efi.c.
Add efi_read_from_sysfs, but if 0 it out. We'll want to use it if we can
get the proposed /sys/firmware/efi/memmap data published in the same
format and the code works, it's just that the current
/sys/firmware/efi/runtime-memmap isn't complete enough to use.
Sponsored by: Netflix
Reviewed by: kevans, jhibbits
Differential Revision: https://reviews.freebsd.org/D49863
---
stand/kboot/include/efi.h | 11 +-
stand/kboot/kboot/arch/aarch64/exec.c | 7 +-
stand/kboot/kboot/arch/aarch64/load_addr.c | 121 ++++---------------
stand/kboot/libkboot/Makefile | 1 +
stand/kboot/libkboot/efi.c | 187 +++++++++++++++++++++++++----
5 files changed, 200 insertions(+), 127 deletions(-)
diff --git a/stand/kboot/include/efi.h b/stand/kboot/include/efi.h
index f75a9ea055d3..26a6cf8944ca 100644
--- a/stand/kboot/include/efi.h
+++ b/stand/kboot/include/efi.h
@@ -13,6 +13,15 @@
typedef void (*efi_map_entry_cb)(struct efi_md *, void *argp);
+struct preloaded_file;
+
+bool efi_read_from_pa(uint64_t pa, uint32_t map_size, uint32_t desc_size, uint32_t vers);
+void efi_read_from_sysfs(void);
+void efi_set_systbl(uint64_t tbl);
void foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp);
void print_efi_map(struct efi_map_header *efihdr);
-bool populate_avail_from_efi(struct efi_map_header *efihdr);
+void efi_bi_loadsmap(struct preloaded_file *kfp);
+
+extern uint32_t efi_map_size;
+extern vm_paddr_t efi_map_phys_src; /* From DTB */
+extern vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */
diff --git a/stand/kboot/kboot/arch/aarch64/exec.c b/stand/kboot/kboot/arch/aarch64/exec.c
index bbb97cc20979..40eb57f371a9 100644
--- a/stand/kboot/kboot/arch/aarch64/exec.c
+++ b/stand/kboot/kboot/arch/aarch64/exec.c
@@ -41,6 +41,7 @@
#include <machine/metadata.h>
#include "bootstrap.h"
+#include "efi.h"
#include "kboot.h"
#include "platform/acfreebsd.h"
@@ -65,11 +66,7 @@ static int elf64_obj_exec(struct preloaded_file *amp);
bool do_mem_map = false;
-extern uint32_t efi_map_size;
-extern vm_paddr_t efi_map_phys_src; /* From DTB */
-extern vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */
-
-/* Usually provided by loader_efi.h */
+/* Usually provided by loader_efi.h -- maybe just delete? */
#ifndef EFI
int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp,
bool exit_bs);
diff --git a/stand/kboot/kboot/arch/aarch64/load_addr.c b/stand/kboot/kboot/arch/aarch64/load_addr.c
index 8ceb21007c45..c458adc8dd05 100644
--- a/stand/kboot/kboot/arch/aarch64/load_addr.c
+++ b/stand/kboot/kboot/arch/aarch64/load_addr.c
@@ -11,30 +11,18 @@
#include <libfdt.h>
#include "kboot.h"
-#include "bootstrap.h"
#include "efi.h"
-/*
- * Info from dtb about the EFI system
- */
-vm_paddr_t efi_systbl_phys;
-struct efi_map_header *efi_map_hdr;
-uint32_t efi_map_size;
-vm_paddr_t efi_map_phys_src; /* From DTB */
-vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */
-
static bool
do_memory_from_fdt(int fd)
{
struct stat sb;
char *buf = NULL;
- int len, offset, fd2 = -1;
- uint32_t sz, ver, esz, efisz;
+ int len, offset;
+ uint32_t sz, ver, esz;
uint64_t mmap_pa;
const uint32_t *u32p;
const uint64_t *u64p;
- struct efi_map_header *efihdr;
- struct efi_md *map;
if (fstat(fd, &sb) < 0)
return false;
@@ -60,7 +48,7 @@ do_memory_from_fdt(int fd)
u64p = fdt_getprop(buf, offset, "linux,uefi-system-table", &len);
if (u64p == NULL)
goto errout;
- efi_systbl_phys = fdt64_to_cpu(*u64p);
+ efi_set_systbl(fdt64_to_cpu(*u64p));
u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-ver", &len);
if (u32p == NULL)
goto errout;
@@ -82,62 +70,8 @@ do_memory_from_fdt(int fd)
printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n",
ver, esz, sz, mmap_pa);
- /*
- * We may have no ability to read the PA that this map is in, so pass
- * the address to FreeBSD via a rather odd flag entry as the first map
- * so early boot can copy the memory map into this space and have the
- * rest of the code cope.
- */
- efisz = roundup2(sizeof(*efihdr), 16);
- buf = malloc(sz + efisz);
- if (buf == NULL)
- return false;
- efihdr = (struct efi_map_header *)buf;
- map = (struct efi_md *)((uint8_t *)efihdr + efisz);
- bzero(map, sz);
- efihdr->memory_size = sz;
- efihdr->descriptor_size = esz;
- efihdr->descriptor_version = ver;
-
- /*
- * Save EFI table. Either this will be an empty table filled in by the trampoline,
- * or we'll read it below. Either way, set these two variables so we share the best
- * UEFI memory map with the kernel.
- */
- efi_map_hdr = efihdr;
- efi_map_size = sz + efisz;
-
- /*
- * Try to read in the actual UEFI map.
- */
- fd2 = open("host:/dev/mem", O_RDONLY);
- if (fd2 < 0) {
- printf("Will read UEFI mem map in tramp: no /dev/mem, need CONFIG_DEVMEM=y\n");
- goto no_read;
- }
- if (lseek(fd2, mmap_pa, SEEK_SET) < 0) {
- printf("Will read UEFI mem map in tramp: lseek failed\n");
- goto no_read;
- }
- len = read(fd2, map, sz);
- if (len != sz) {
- if (len < 0 && errno == EPERM)
- printf("Will read UEFI mem map in tramp: kernel needs CONFIG_STRICT_DEVMEM=n\n");
- else
- printf("Will read UEFI mem map in tramp: lean = %d errno = %d\n", len, errno);
- goto no_read;
- }
- printf("Read UEFI mem map from physmem\n");
- efi_map_phys_src = 0; /* Mark MODINFOMD_EFI_MAP as valid */
- close(fd2);
- printf("UEFI MAP:\n");
- print_efi_map(efihdr);
- return true; /* OK, we really have the memory map */
-
-no_read:
- efi_map_phys_src = mmap_pa;
- close(fd2);
- return true; /* We can get it the trampoline */
+ efi_read_from_pa(mmap_pa, sz, esz, ver);
+ return true;
errout:
free(buf);
@@ -150,22 +84,32 @@ enumerate_memory_arch(void)
int fd = -1;
bool rv = false;
+ /*
+ * FDT publishes the parameters for the memory table in a series of
+ * nodes in the DTB. One of them is the physical address for the memory
+ * table. Try to open the fdt nblob to find this information if we can
+ * and try to grab things from memory. If we return rv == TRUE then
+ * we found it. The global efi_map_phys_src is set != 0 when we know
+ * the PA but can't read it.
+ */
fd = open("host:/sys/firmware/fdt", O_RDONLY);
if (fd != -1) {
rv = do_memory_from_fdt(fd);
close(fd);
- /*
- * So, we have physaddr to the memory table. However, we can't
- * open /dev/mem on some platforms to get the actual table. So
- * we have to fall through to get it from /proc/iomem.
- */
}
+
+ /*
+ * One would think that one could use the raw EFI map to find memory
+ * that's free to boot the kernel with. However, Linux reserves some
+ * areas that it needs to properly. I'm not sure if the printf should be
+ * a panic, but for now, so I can debug (maybe at the loader prompt),
+ * I'm printing and carrying on.
+ */
if (!rv) {
printf("Could not obtain UEFI memory tables, expect failure\n");
}
populate_avail_from_iomem();
-
print_avail();
return true;
@@ -181,32 +125,19 @@ kboot_get_phys_load_segment(void)
if (s != 0)
return (s);
+ print_avail();
s = first_avail(KERN_ALIGN, HOLE_SIZE, SYSTEM_RAM);
+ printf("KBOOT GET PHYS Using %#llx\n", (long long)s);
if (s != 0)
return (s);
s = 0x40000000 | 0x4200000; /* should never get here */
- printf("Falling back to crazy address %#lx\n", s);
+ /* XXX PANIC? XXX */
+ printf("Falling back to the crazy address %#lx which works in qemu\n", s);
return (s);
}
void
bi_loadsmap(struct preloaded_file *kfp)
{
-
- /*
- * Make a note of a systbl. This is nearly mandatory on AARCH64.
- */
- if (efi_systbl_phys)
- file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(efi_systbl_phys), &efi_systbl_phys);
-
- /*
- * If we have efi_map_hdr, then it's a pointer to the PA where this
- * memory map lives. The trampoline code will copy it over. If we don't
- * have it, we use whatever we found in /proc/iomap.
- */
- if (efi_map_hdr != NULL) {
- file_addmetadata(kfp, MODINFOMD_EFI_MAP, efi_map_size, efi_map_hdr);
- return;
- }
- panic("Can't get UEFI memory map, nor a pointer to it, can't proceed.\n");
+ efi_bi_loadsmap(kfp);
}
diff --git a/stand/kboot/libkboot/Makefile b/stand/kboot/libkboot/Makefile
index e23ae9bb9215..dc85ffe8afb2 100644
--- a/stand/kboot/libkboot/Makefile
+++ b/stand/kboot/libkboot/Makefile
@@ -5,6 +5,7 @@ WARNS?= 4
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}
CFLAGS+=-I${.CURDIR} -I${.CURDIR}/arch/${MACHINE_ARCH}
+CFLAGS+=-I${LDRSRC}
SRCS= crt1.c
SRCS+= host_syscall.S
diff --git a/stand/kboot/libkboot/efi.c b/stand/kboot/libkboot/efi.c
index 1c1d9a34d297..3f1055f6d538 100644
--- a/stand/kboot/libkboot/efi.c
+++ b/stand/kboot/libkboot/efi.c
@@ -5,9 +5,156 @@
*/
#include <sys/param.h>
+#include <sys/linker.h>
#include "stand.h"
+#include "bootstrap.h"
#include "efi.h"
#include "seg.h"
+#include "util.h"
+
+vm_paddr_t efi_systbl_phys;
+struct efi_map_header *efi_map_hdr;
+uint32_t efi_map_size;
+vm_paddr_t efi_map_phys_src; /* From DTB */
+vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */
+
+void
+efi_set_systbl(uint64_t tbl)
+{
+ efi_systbl_phys = tbl;
+}
+
+#if 0
+/* Note: This is useless since runtime-map is a subset */
+void
+efi_read_from_sysfs(void)
+{
+ uint32_t efisz, sz, map_size;
+ int entries = 0;
+ struct efi_md *map; /* Really an array */
+ char *buf;
+ struct stat sb;
+ char fn[100];
+
+ /*
+ * Count the number of entries we have. They are numbered from 0
+ * through entries - 1.
+ */
+ do {
+ printf("Looking at index %d\n", entries);
+ snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/phys_addr", entries++);
+ } while (stat(fn, &sb) == 0);
+
+ /*
+ * We incremented entries one past the first failure, so we need to
+ * adjust the count and the test for 'nothing found' is against 1.
+ */
+ if (entries == 1)
+ goto err;
+ entries--;
+
+ /* XXX lots of copied code, refactor? */
+ map_size = sizeof(struct efi_md) * entries;
+ efisz = roundup2(sizeof(*efi_map_hdr), 16);
+ sz = efisz + map_size;
+ buf = malloc(efisz + map_size);
+ if (buf == NULL)
+ return;
+ efi_map_hdr = (struct efi_map_header *)buf;
+ efi_map_size = sz;
+ map = (struct efi_md *)(buf + efisz);
+ bzero(map, sz);
+ efi_map_hdr->memory_size = map_size;
+ efi_map_hdr->descriptor_size = sizeof(struct efi_md);
+ efi_map_hdr->descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION;
+ for (int i = 0; i < entries; i++) {
+ struct efi_md *m;
+
+ printf("Populating index %d\n", i);
+ m = map + i;
+ snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/type", i);
+ if (!file2u32(fn, &m->md_type))
+ goto err;
+ snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/phys_addr", i);
+ if (!file2u64(fn, &m->md_phys))
+ goto err;
+ snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/virt_addr", i);
+ if (!file2u64(fn, &m->md_virt))
+ goto err;
+ snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/num_pages", i);
+ if (!file2u64(fn, &m->md_pages))
+ goto err;
+ snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/attribute", i);
+ if (!file2u64(fn, &m->md_attr))
+ goto err;
+ }
+ efi_map_phys_src = 0;
+ printf("UEFI MAP:\n");
+ print_efi_map(efi_map_hdr);
+ printf("DONE\n");
+ return;
+err:
+ printf("Parse error in reading current memory map\n");
+}
+#endif
+
+/*
+ * We may have no ability to read the PA that this map is in, so pass
+ * the address to FreeBSD via a rather odd flag entry as the first map
+ * so early boot can copy the memory map into this space and have the
+ * rest of the code cope.
+ */
+bool
+efi_read_from_pa(uint64_t pa, uint32_t map_size, uint32_t desc_size, uint32_t vers)
+{
+ uint32_t efisz, sz;
+ char *buf;
+ int fd2, len;
+ struct efi_md *map; /* Really an array */
+
+ /*
+ * We may have no ability to read the PA that this map is in, so pass
+ * the address to FreeBSD via a rather odd flag entry as the first map
+ * so early boot can copy the memory map into this space and have the
+ * rest of the code cope. We also have to round the size of the header
+ * to 16 byte boundary.
+ */
+ efisz = roundup2(sizeof(*efi_map_hdr), 16);
+ sz = efisz + map_size;
+ buf = malloc(efisz + map_size);
+ if (buf == NULL)
+ return false;
+ efi_map_hdr = (struct efi_map_header *)buf;
+ efi_map_size = sz;
+ map = (struct efi_md *)(buf + efisz);
+ bzero(map, sz);
+ efi_map_hdr->memory_size = map_size;
+ efi_map_hdr->descriptor_size = desc_size;
+ efi_map_hdr->descriptor_version = vers;
+
+ /*
+ * Try to read in the actual UEFI map. This may fail, and that's OK. We just
+ * won't print the map.
+ */
+ fd2 = open("host:/dev/mem", O_RDONLY);
+ if (fd2 < 0)
+ goto no_read;
+ if (lseek(fd2, pa, SEEK_SET) < 0)
+ goto no_read;
+ len = read(fd2, map, sz);
+ if (len != sz)
+ goto no_read;
+ efi_map_phys_src = 0; /* Mark MODINFOMD_EFI_MAP as valid */
+ close(fd2);
+ printf("UEFI MAP:\n");
+ print_efi_map(efi_map_hdr);
+ return (true);
+
+no_read: /* Just get it the trampoline */
+ efi_map_phys_src = pa;
+ close(fd2);
+ return (true);
+}
void
foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp)
@@ -98,37 +245,25 @@ print_efi_map(struct efi_map_header *efihdr)
foreach_efi_map_entry(efihdr, print_efi_map_entry, NULL);
}
-static void
-efi_map_entry_add_avail(struct efi_md *p, void *argp)
+void
+efi_bi_loadsmap(struct preloaded_file *kfp)
{
- bool *retval = argp;
-
/*
- * The kernel itself uses a lot more types as memory it can use. Be
- * conservative here so we don't overwrite anything during the reboot
- * process which copies the new kernel (so we can't use the Linux kenrel
- * space for example). Anything that's not free, we simply don't add to
- * the system ram space. We just need to find a big enough place we can
- * land the kernel, and most of the other types we might use are
- * typically too small anyway, even if we could safely use them.
+ * Make a note of a systbl. This is nearly mandatory on AARCH64.
*/
- if (p->md_type != EFI_MD_TYPE_FREE)
- return;
+ if (efi_systbl_phys)
+ file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(efi_systbl_phys), &efi_systbl_phys);
/*
- * The memory map is always disjoint, so we never have to remove avail.
+ * If we have efi_map_hdr, then it's a pointer to the PA where this
+ * memory map lives. The trampoline code will copy it over. If we don't
+ * have it, panic because /proc/iomem isn't sufficient and there's no
+ * hope.
*/
- add_avail(p->md_phys, p->md_phys + p->md_pages * EFI_PAGE_SIZE - 1,
- SYSTEM_RAM);
- *retval = true;
-}
-
-bool
-populate_avail_from_efi(struct efi_map_header *efihdr)
-{
- bool retval = false;
+ if (efi_map_hdr != NULL) {
+ file_addmetadata(kfp, MODINFOMD_EFI_MAP, efi_map_size, efi_map_hdr);
+ return;
+ }
- init_avail();
- foreach_efi_map_entry(efihdr, efi_map_entry_add_avail, &retval);
- return retval;
+ panic("Can't get UEFI memory map, nor a pointer to it, can't proceed.\n");
}