aboutsummaryrefslogtreecommitdiff
path: root/stand/kboot/kboot/arch/amd64/load_addr.c
diff options
context:
space:
mode:
Diffstat (limited to 'stand/kboot/kboot/arch/amd64/load_addr.c')
-rw-r--r--stand/kboot/kboot/arch/amd64/load_addr.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/stand/kboot/kboot/arch/amd64/load_addr.c b/stand/kboot/kboot/arch/amd64/load_addr.c
new file mode 100644
index 000000000000..4bd2a19dab48
--- /dev/null
+++ b/stand/kboot/kboot/arch/amd64/load_addr.c
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 2022 Netflix, Inc
+ *
+ * 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 AUTHOR 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 AUTHOR 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 <sys/param.h>
+#include <machine/pc/bios.h>
+#include <machine/metadata.h>
+
+#include "stand.h"
+#include "host_syscall.h"
+#include "kboot.h"
+#include "bootstrap.h"
+
+/* Refactor when we do arm64 */
+
+enum types {
+ system_ram = 1,
+ acpi_tables,
+ acpi_nv_storage,
+ unusable,
+ persistent_old,
+ persistent,
+ soft_reserved,
+ reserved,
+};
+
+struct kv
+{
+ uint64_t type;
+ char * name;
+} str2type_kv[] = {
+ { system_ram, "System RAM" },
+ { acpi_tables, "ACPI Tables" },
+ { acpi_nv_storage, "ACPI Non-volatile Storage" },
+ { unusable, "Unusable memory" },
+ { persistent_old, "Persistent Memory (legacy)" },
+ { persistent, "Persistent Memory" },
+ { soft_reserved, "Soft Reserved" },
+ { reserved, "reserved" },
+ { 0, NULL },
+};
+
+#define MEMMAP "/sys/firmware/memmap"
+
+static struct memory_segments segs[64]; /* make dynamic later */
+static int nr_seg;
+
+static bool
+str2type(struct kv *kv, const char *buf, uint64_t *value)
+{
+ while (kv->name != NULL) {
+ if (strcmp(kv->name, buf) == 0) {
+ *value = kv->type;
+ return true;
+ }
+ kv++;
+ }
+
+ return false;
+}
+
+bool
+enumerate_memory_arch(void)
+{
+ int n;
+ char name[MAXPATHLEN];
+ char buf[80];
+
+ for (n = 0; n < nitems(segs); n++) {
+ snprintf(name, sizeof(name), "%s/%d/start", MEMMAP, n);
+ if (!file2u64(name, &segs[n].start))
+ break;
+ snprintf(name, sizeof(name), "%s/%d/end", MEMMAP, n);
+ if (!file2u64(name, &segs[n].end))
+ break;
+ snprintf(name, sizeof(name), "%s/%d/type", MEMMAP, n);
+ if (!file2str(name, buf, sizeof(buf)))
+ break;
+ if (!str2type(str2type_kv, buf, &segs[n].type))
+ break;
+ }
+
+ nr_seg = n;
+
+ return true;
+}
+
+#define BAD_SEG ~0ULL
+
+#define SZ(s) (((s).end - (s).start) + 1)
+
+static uint64_t
+find_ram(struct memory_segments *segs, int nr_seg, uint64_t minpa, uint64_t align,
+ uint64_t sz, uint64_t maxpa)
+{
+ uint64_t start;
+
+ printf("minpa %#jx align %#jx sz %#jx maxpa %#jx\n",
+ (uintmax_t)minpa,
+ (uintmax_t)align,
+ (uintmax_t)sz,
+ (uintmax_t)maxpa);
+ /* XXX assume segs are sorted in numeric order -- assumed not ensured */
+ for (int i = 0; i < nr_seg; i++) {
+ if (segs[i].type != system_ram ||
+ SZ(segs[i]) < sz ||
+ minpa + sz > segs[i].end ||
+ maxpa < segs[i].start)
+ continue;
+ start = roundup(segs[i].start, align);
+ if (start < minpa) /* Too small, round up and try again */
+ start = (roundup(minpa, align));
+ if (start + sz > segs[i].end) /* doesn't fit in seg */
+ continue;
+ if (start > maxpa || /* Over the edge */
+ start + sz > maxpa) /* on the edge */
+ break; /* No hope to continue */
+ return start;
+ }
+
+ return BAD_SEG;
+}
+
+uint64_t
+kboot_get_phys_load_segment(void)
+{
+ static uint64_t base_seg = BAD_SEG;
+
+ if (base_seg != BAD_SEG)
+ return (base_seg);
+
+ if (nr_seg > 0)
+ base_seg = find_ram(segs, nr_seg, 2ULL << 20, 2ULL << 20,
+ 64ULL << 20, 4ULL << 30);
+ if (base_seg == BAD_SEG) {
+ /* XXX Should fall back to using /proc/iomem maybe? */
+ /* XXX PUNT UNTIL I NEED SOMETHING BETTER */
+ base_seg = 300ULL * (1 << 20);
+ }
+ return (base_seg);
+}
+
+void
+bi_loadsmap(struct preloaded_file *kfp)
+{
+ struct bios_smap smap[32], *sm;
+ struct memory_segments *s;
+ int smapnum, len;
+
+ for (smapnum = 0; smapnum < min(32, nr_seg); smapnum++) {
+ sm = &smap[smapnum];
+ s = &segs[smapnum];
+ sm->base = s->start;
+ sm->length = s->end - s->start + 1;
+ sm->type = SMAP_TYPE_MEMORY;
+ }
+
+ len = smapnum * sizeof(struct bios_smap);
+ file_addmetadata(kfp, MODINFOMD_SMAP, len, &smap[0]);
+}