1 /*- 2 * Copyright (c) 2022 Netflix, Inc 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/param.h> 27 #include <machine/pc/bios.h> 28 #include <machine/metadata.h> 29 30 #include "stand.h" 31 #include "host_syscall.h" 32 #include "kboot.h" 33 #include "bootstrap.h" 34 35 /* Refactor when we do arm64 */ 36 37 enum types { 38 system_ram = 1, 39 acpi_tables, 40 acpi_nv_storage, 41 unusable, 42 persistent_old, 43 persistent, 44 soft_reserved, 45 reserved, 46 }; 47 48 struct kv 49 { 50 uint64_t type; 51 char * name; 52 } str2type_kv[] = { 53 { system_ram, "System RAM" }, 54 { acpi_tables, "ACPI Tables" }, 55 { acpi_nv_storage, "ACPI Non-volatile Storage" }, 56 { unusable, "Unusable memory" }, 57 { persistent_old, "Persistent Memory (legacy)" }, 58 { persistent, "Persistent Memory" }, 59 { soft_reserved, "Soft Reserved" }, 60 { reserved, "reserved" }, 61 { 0, NULL }, 62 }; 63 64 #define MEMMAP "/sys/firmware/memmap" 65 66 static struct memory_segments segs[64]; /* make dynamic later */ 67 static int nr_seg; 68 69 static bool 70 str2type(struct kv *kv, const char *buf, uint64_t *value) 71 { 72 while (kv->name != NULL) { 73 if (strcmp(kv->name, buf) == 0) { 74 *value = kv->type; 75 return true; 76 } 77 kv++; 78 } 79 80 return false; 81 } 82 83 bool 84 enumerate_memory_arch(void) 85 { 86 int n; 87 char name[MAXPATHLEN]; 88 char buf[80]; 89 90 for (n = 0; n < nitems(segs); n++) { 91 snprintf(name, sizeof(name), "%s/%d/start", MEMMAP, n); 92 if (!file2u64(name, &segs[n].start)) 93 break; 94 snprintf(name, sizeof(name), "%s/%d/end", MEMMAP, n); 95 if (!file2u64(name, &segs[n].end)) 96 break; 97 snprintf(name, sizeof(name), "%s/%d/type", MEMMAP, n); 98 if (!file2str(name, buf, sizeof(buf))) 99 break; 100 if (!str2type(str2type_kv, buf, &segs[n].type)) 101 break; 102 } 103 104 nr_seg = n; 105 106 return true; 107 } 108 109 #define BAD_SEG ~0ULL 110 111 #define SZ(s) (((s).end - (s).start) + 1) 112 113 static uint64_t 114 find_ram(struct memory_segments *segs, int nr_seg, uint64_t minpa, uint64_t align, 115 uint64_t sz, uint64_t maxpa) 116 { 117 uint64_t start; 118 119 printf("minpa %#jx align %#jx sz %#jx maxpa %#jx\n", 120 (uintmax_t)minpa, 121 (uintmax_t)align, 122 (uintmax_t)sz, 123 (uintmax_t)maxpa); 124 /* XXX assume segs are sorted in numeric order -- assumed not ensured */ 125 for (int i = 0; i < nr_seg; i++) { 126 if (segs[i].type != system_ram || 127 SZ(segs[i]) < sz || 128 minpa + sz > segs[i].end || 129 maxpa < segs[i].start) 130 continue; 131 start = roundup(segs[i].start, align); 132 if (start < minpa) /* Too small, round up and try again */ 133 start = (roundup(minpa, align)); 134 if (start + sz > segs[i].end) /* doesn't fit in seg */ 135 continue; 136 if (start > maxpa || /* Over the edge */ 137 start + sz > maxpa) /* on the edge */ 138 break; /* No hope to continue */ 139 return start; 140 } 141 142 return BAD_SEG; 143 } 144 145 uint64_t 146 kboot_get_phys_load_segment(void) 147 { 148 static uint64_t base_seg = BAD_SEG; 149 150 if (base_seg != BAD_SEG) 151 return (base_seg); 152 153 if (nr_seg > 0) 154 base_seg = find_ram(segs, nr_seg, 2ULL << 20, 2ULL << 20, 155 64ULL << 20, 4ULL << 30); 156 if (base_seg == BAD_SEG) { 157 /* XXX Should fall back to using /proc/iomem maybe? */ 158 /* XXX PUNT UNTIL I NEED SOMETHING BETTER */ 159 base_seg = 300ULL * (1 << 20); 160 } 161 return (base_seg); 162 } 163 164 void 165 bi_loadsmap(struct preloaded_file *kfp) 166 { 167 struct bios_smap smap[32], *sm; 168 struct memory_segments *s; 169 int smapnum, len; 170 171 for (smapnum = 0; smapnum < min(32, nr_seg); smapnum++) { 172 sm = &smap[smapnum]; 173 s = &segs[smapnum]; 174 sm->base = s->start; 175 sm->length = s->end - s->start + 1; 176 sm->type = SMAP_TYPE_MEMORY; 177 } 178 179 len = smapnum * sizeof(struct bios_smap); 180 file_addmetadata(kfp, MODINFOMD_SMAP, len, &smap[0]); 181 } 182