Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108217530
D38249.id116007.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D38249.id116007.diff
View Options
diff --git a/stand/kboot/arch/aarch64/load_addr.c b/stand/kboot/arch/aarch64/load_addr.c
--- a/stand/kboot/arch/aarch64/load_addr.c
+++ b/stand/kboot/arch/aarch64/load_addr.c
@@ -0,0 +1,451 @@
+/*-
+ * Copyright (c) 2022 Netflix, Inc
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/efi.h>
+#include <machine/metadata.h>
+#include <sys/linker.h>
+#include <fdt_platform.h>
+#include <libfdt.h>
+
+#include "kboot.h"
+#include "bootstrap.h"
+
+static struct memory_segments *segs;
+static int nr_seg = 0;
+static int segalloc = 0;
+
+/*
+ * 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 */
+
+enum types {
+ system_ram = 1,
+ firmware_reserved,
+ linux_code,
+ linux_data,
+ unknown,
+};
+
+struct kv
+{
+ uint64_t type;
+ char * name;
+ int flags;
+#define KV_KEEPER 1
+} str2type_kv[] = {
+ { linux_code, "Kernel code", KV_KEEPER },
+ { linux_data, "Kernel data", KV_KEEPER },
+ { firmware_reserved, "reserved" },
+ { 0, NULL },
+};
+
+static void
+init_avail(void)
+{
+ if (segs)
+ free(segs);
+ nr_seg = 0;
+ segalloc = 16;
+ segs = malloc(sizeof(*segs) * segalloc);
+}
+
+/*
+ * Make sure at least n items can be accessed in the segs array. Note the
+ * realloc here will invalidate cached pointers (potentially), so addresses
+ * into the segs array must be recomputed after this call.
+ */
+static void
+need_avail(int n)
+{
+ if (n <= segalloc)
+ return;
+
+ while (n > segalloc)
+ segalloc *= 2;
+ segs = realloc(segs, segalloc * sizeof(*segs));
+}
+
+/*
+ * Always called for a new range, so always just append a range,
+ * unless it's continuous with the prior range.
+ */
+static void
+add_avail(uint64_t start, uint64_t end, enum types type)
+{
+ /*
+ * This range is contiguous with the previous range, and is
+ * the same type: we can collapse the two.
+ */
+ if (nr_seg >= 1 &&
+ segs[nr_seg - 1].end + 1 == start &&
+ segs[nr_seg - 1].type == type) {
+ segs[nr_seg - 1].end = end;
+ return;
+ }
+
+ /*
+ * Otherwise we need to add a new range at the end, but don't need to
+ * adjust the current end.
+ */
+ need_avail(nr_seg + 1);
+ segs[nr_seg].start = start;
+ segs[nr_seg].end = end;
+ segs[nr_seg].type = type;
+ nr_seg++;
+}
+
+/*
+ * All or part of a prior entry needs to be modified. Given the structure of the
+ * code, we know that it will always be modifying the last time and/or extending
+ * the one before it if its contiguous.
+ */
+static void
+remove_avail(uint64_t start, uint64_t end, enum types type)
+{
+ struct memory_segments *s;
+
+ /*
+ * simple case: we are extending a previously removed item.
+ */
+ if (nr_seg >= 2) {
+ s = &segs[nr_seg - 2];
+ if (s->end + 1 == start &&
+ s->type == type) {
+ s->end = end;
+ /* Now adjust the ending element */
+ s++;
+ if (s->end == end) {
+ /* we've used up the 'free' space */
+ nr_seg--;
+ return;
+ }
+ /* Otherwise adjust the 'free' space */
+ s->start = end + 1;
+ return;
+ }
+ }
+
+ /*
+ * OK, we have four cases:
+ * (1) The new chunk is at the start of the free space, but didn't catch the above
+ * folding for whatever reason (different type, start of space). In this case,
+ * we allocate 1 additional item. The current end is copied to the new end. The
+ * current end is set to <start, end, type> and the new end's start is set to end + 1.
+ * (2) The new chunk is in the middle of the free space. In this case we allocate 2
+ * additional items. We copy the current end to the new end, set the new end's start
+ * to end + 1, the old end's end to start - 1 and the new item is <start, end, type>
+ * (3) The new chunk is at the end of the current end. In this case we allocate 1 more
+ * and adjust the current end's end to start - 1 and set the new end to <start, end, type>.
+ * (4) The new chunk is exactly the current end, except for type. In this case, we just adjust
+ * the type.
+ * We can assume we always have at least one chunk since that's created with new_avail() above
+ * necessarily before we are called to subset it.
+ */
+ s = &segs[nr_seg - 1];
+ if (s->start == start) {
+ if (s->end == end) { /* (4) */
+ s->type = type;
+ return;
+ }
+ /* chunk at start of old chunk -> (1) */
+ need_avail(nr_seg + 1);
+ s = &segs[nr_seg - 1]; /* Realloc may change pointers */
+ s[1] = s[0];
+ s->start = start;
+ s->end = end;
+ s->type = type;
+ s[1].start = end + 1;
+ nr_seg++;
+ return;
+ }
+ if (s->end == end) { /* At end of old chunk (3) */
+ need_avail(nr_seg + 1);
+ s = &segs[nr_seg - 1]; /* Realloc may change pointers */
+ s[1] = s[0];
+ s->end = start - 1;
+ s[1].start = start;
+ s[1].type = type;
+ nr_seg++;
+ return;
+ }
+ /* In the middle, need to split things up (2) */
+ need_avail(nr_seg + 2);
+ s = &segs[nr_seg - 1]; /* Realloc may change pointers */
+ s[2] = s[1] = s[0];
+ s->end = start - 1;
+ s[1].start = start;
+ s[1].end = end;
+ s[1].type = type;
+ s[2].start = end + 1;
+ nr_seg += 2;
+}
+
+static const char *
+parse_line(const char *line, uint64_t *startp, uint64_t *endp)
+{
+ const char *walker;
+ char *next;
+ uint64_t start, end;
+
+ /*
+ * Each line is a range followed by a descriptoin of the form:
+ * <hex-number><dash><hex-number><space><colon><space><string>
+ * Bail if we have any parsing errors.
+ */
+ walker = line;
+ start = strtoull(walker, &next, 16);
+ if (start == ULLONG_MAX || walker == next)
+ return (NULL);
+ walker = next;
+ if (*walker != '-')
+ return (NULL);
+ walker++;
+ end = strtoull(walker, &next, 16);
+ if (end == ULLONG_MAX || walker == next)
+ return (NULL);
+ walker = next;
+ /* Now eat the ' : ' in front of the string we want to return */
+ if (strncmp(walker, " : ", 3) != 0)
+ return (NULL);
+ *startp = start;
+ *endp = end;
+ return (walker + 3);
+}
+
+static struct kv *
+kvlookup(const char *str, struct kv *kvs, size_t nkv)
+{
+ for (int i = 0; i < nkv; i++)
+ if (strcmp(kvs[i].name, str) == 0)
+ return (&kvs[i]);
+
+ return (NULL);
+}
+
+/* Trim trailing whitespace */
+static void
+chop(char *line)
+{
+ char *ep = line + strlen(line) - 1;
+
+ while (ep >= line && isspace(*ep))
+ *ep-- = '\0';
+}
+
+#define SYSTEM_RAM "System RAM"
+#define RESERVED "reserved"
+
+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;
+ 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;
+ buf = malloc(sb.st_size);
+ if (buf == NULL)
+ return false;
+ len = read(fd, buf, sb.st_size);
+ /* NB: we're reading this from sysfs, so mismatch OK */
+ if (len <= 0)
+ goto errout;
+
+ /*
+ * Look for /chosen to find these values:
+ * linux,uefi-system-table PA of the UEFI System Table.
+ * linux,uefi-mmap-start PA of the UEFI memory map
+ * linux,uefi-mmap-size Size of mmap
+ * linux,uefi-mmap-desc-size Size of each entry of mmap
+ * linux,uefi-mmap-desc-ver Format version, should be 1
+ */
+ offset = fdt_path_offset(buf, "/chosen");
+ if (offset <= 0)
+ goto errout;
+ u64p = fdt_getprop(buf, offset, "linux,uefi-system-table", &len);
+ if (u64p == NULL)
+ goto errout;
+ efi_systbl_phys = fdt64_to_cpu(*u64p);
+ u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-ver", &len);
+ if (u32p == NULL)
+ goto errout;
+ ver = fdt32_to_cpu(*u32p);
+ u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-size", &len);
+ if (u32p == NULL)
+ goto errout;
+ esz = fdt32_to_cpu(*u32p);
+ u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-size", &len);
+ if (u32p == NULL)
+ goto errout;
+ sz = fdt32_to_cpu(*u32p);
+ u64p = fdt_getprop(buf, offset, "linux,uefi-mmap-start", &len);
+ if (u64p == NULL)
+ goto errout;
+ mmap_pa = fdt64_to_cpu(*u64p);
+ free(buf);
+
+ printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n",
+ ver, esz, sz, mmap_pa);
+
+ /*
+ * We 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 = (sizeof(*efihdr) + 0xf) & ~0xf;
+ 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;
+ efi_map_phys_src = mmap_pa;
+ efi_map_hdr = efihdr;
+ efi_map_size = sz + efisz;
+
+ return true;
+errout:
+ close(fd2);
+ free(buf);
+ return false;
+}
+
+bool
+enumerate_memory_arch(void)
+{
+ int fd = -1;
+ char buf[128];
+ const char *str;
+ uint64_t start, end;
+ struct kv *kv;
+ bool rv;
+
+ fd = open("/sys/firmware/fdt", O_RDONLY);
+ if (fd != -1) {
+ printf("Doing trying to get UEFI from FDT -- fake\n");
+ rv = do_memory_from_fdt(fd);
+ close(fd);
+ if (rv) {
+ printf("Got it from /sys/firmware/fdt\n");
+ }
+ /*
+ * 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.
+ */
+ }
+
+ printf("Falling back to iomem to find where to load\n");
+ fd = open("/proc/iomem", O_RDONLY);
+ if (fd == -1) {
+ printf("Can't get memory map\n");
+ return false;
+ }
+
+ if (fgetstr(buf, sizeof(buf), fd) < 0)
+ goto out; /* Nothing to do ???? */
+ init_avail();
+ chop(buf);
+ while (true) {
+ /*
+ * Look for top level items we understand. Skip anything that's
+ * a continuation, since we don't care here. If we care, we'll
+ * consume them all when we recognize that top level item.
+ */
+ if (buf[0] == ' ') /* Continuation lines? Ignore */
+ goto next_line;
+ str = parse_line(buf, &start, &end);
+ if (str == NULL) /* Malformed -> ignore */
+ goto next_line;
+ /*
+ * All we care about is System RAM
+ */
+ if (strncmp(str, SYSTEM_RAM, sizeof(SYSTEM_RAM) - 1) == 0)
+ add_avail(start, end, system_ram);
+ else if (strncmp(str, RESERVED, sizeof(RESERVED) - 1) == 0)
+ add_avail(start, end, firmware_reserved);
+ else
+ goto next_line; /* Ignore hardware */
+ while (fgetstr(buf, sizeof(buf), fd) >= 0 && buf[0] == ' ') {
+ chop(buf);
+ str = parse_line(buf, &start, &end);
+ if (str == NULL)
+ break;
+ kv = kvlookup(str, str2type_kv, nitems(str2type_kv));
+ if (kv == NULL) /* failsafe for new types: igonre */
+ remove_avail(start, end, unknown);
+ else if ((kv->flags & KV_KEEPER) == 0)
+ remove_avail(start, end, kv->type);
+ /* Else no need to adjust since it's a keeper */
+ }
+
+ /*
+ * if buf[0] == ' ' then we know that the fgetstr failed and we
+ * should break. Otherwise fgetstr succeeded and we have a
+ * buffer we need to examine for being a top level item.
+ */
+ if (buf[0] == ' ')
+ break;
+ chop(buf);
+ continue; /* buf has next top level line to parse */
+next_line:
+ if (fgetstr(buf, sizeof(buf), fd) < 0)
+ break;
+ }
+
+out:
+ close(fd);
+
+ printf("Found %d RAM segments:\n", nr_seg);
+ for (int i = 0; i < nr_seg; i++) {
+ printf("%#lx-%#lx type %lu\n", segs[i].start, segs[i].end, segs[i].type);
+ }
+
+ return true;
+}
+
+uint64_t
+kboot_get_phys_load_segment(void)
+{
+#define HOLE_SIZE (64ul << 20)
+#define KERN_ALIGN (2ul << 20)
+ uint64_t s;
+ uint64_t len;
+
+ for (int i = 0; i < nr_seg; i++) {
+ if (segs[i].type != system_ram) /* Not candiate */
+ continue;
+ s = roundup(segs[i].start, KERN_ALIGN);
+ if (s >= segs[i].end) /* roundup past end */
+ continue;
+ len = segs[i].end - s + 1;
+ if (len >= HOLE_SIZE) {
+ printf("Found a big enough hole at in seg %d at %#lx (%#lx-%#lx)\n",
+ i, s, segs[i].start, segs[i].end);
+ return (s);
+ }
+ }
+ s = 0x40000000 | 0x4200000; /* should never get here */
+ printf("Falling back to crazy address %#lx\n", s);
+ return (s);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 23, 6:49 PM (15 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16061165
Default Alt Text
D38249.id116007.diff (11 KB)
Attached To
Mode
D38249: kboot: aarch64 memory enumeration enumerate_memory_arch()
Attached
Detach File
Event Timeline
Log In to Comment