1 /*- 2 * Copyright (c) 2022 Netflix, Inc 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <sys/param.h> 8 #include <sys/efi.h> 9 #include <machine/metadata.h> 10 #include <sys/linker.h> 11 #include <fdt_platform.h> 12 #include <libfdt.h> 13 14 #include "kboot.h" 15 #include "bootstrap.h" 16 17 /* 18 * Info from dtb about the EFI system 19 */ 20 vm_paddr_t efi_systbl_phys; 21 struct efi_map_header *efi_map_hdr; 22 uint32_t efi_map_size; 23 vm_paddr_t efi_map_phys_src; /* From DTB */ 24 vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */ 25 26 typedef void (*efi_map_entry_cb)(struct efi_md *, void *argp); 27 28 static void 29 foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp) 30 { 31 struct efi_md *map, *p; 32 size_t efisz; 33 int ndesc, i; 34 35 /* 36 * Memory map data provided by UEFI via the GetMemoryMap 37 * Boot Services API. 38 */ 39 efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; 40 map = (struct efi_md *)((uint8_t *)efihdr + efisz); 41 42 if (efihdr->descriptor_size == 0) 43 return; 44 ndesc = efihdr->memory_size / efihdr->descriptor_size; 45 46 for (i = 0, p = map; i < ndesc; i++, 47 p = efi_next_descriptor(p, efihdr->descriptor_size)) { 48 cb(p, argp); 49 } 50 } 51 52 static void 53 print_efi_map_entry(struct efi_md *p, void *argp __unused) 54 { 55 const char *type; 56 static const char *types[] = { 57 "Reserved", 58 "LoaderCode", 59 "LoaderData", 60 "BootServicesCode", 61 "BootServicesData", 62 "RuntimeServicesCode", 63 "RuntimeServicesData", 64 "ConventionalMemory", 65 "UnusableMemory", 66 "ACPIReclaimMemory", 67 "ACPIMemoryNVS", 68 "MemoryMappedIO", 69 "MemoryMappedIOPortSpace", 70 "PalCode", 71 "PersistentMemory" 72 }; 73 74 if (p->md_type < nitems(types)) 75 type = types[p->md_type]; 76 else 77 type = "<INVALID>"; 78 printf("%23s %012lx %012lx %08lx ", type, p->md_phys, 79 p->md_virt, p->md_pages); 80 if (p->md_attr & EFI_MD_ATTR_UC) 81 printf("UC "); 82 if (p->md_attr & EFI_MD_ATTR_WC) 83 printf("WC "); 84 if (p->md_attr & EFI_MD_ATTR_WT) 85 printf("WT "); 86 if (p->md_attr & EFI_MD_ATTR_WB) 87 printf("WB "); 88 if (p->md_attr & EFI_MD_ATTR_UCE) 89 printf("UCE "); 90 if (p->md_attr & EFI_MD_ATTR_WP) 91 printf("WP "); 92 if (p->md_attr & EFI_MD_ATTR_RP) 93 printf("RP "); 94 if (p->md_attr & EFI_MD_ATTR_XP) 95 printf("XP "); 96 if (p->md_attr & EFI_MD_ATTR_NV) 97 printf("NV "); 98 if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE) 99 printf("MORE_RELIABLE "); 100 if (p->md_attr & EFI_MD_ATTR_RO) 101 printf("RO "); 102 if (p->md_attr & EFI_MD_ATTR_RT) 103 printf("RUNTIME"); 104 printf("\n"); 105 } 106 107 static bool 108 do_memory_from_fdt(int fd) 109 { 110 struct stat sb; 111 char *buf = NULL; 112 int len, offset, fd2 = -1; 113 uint32_t sz, ver, esz, efisz; 114 uint64_t mmap_pa; 115 const uint32_t *u32p; 116 const uint64_t *u64p; 117 struct efi_map_header *efihdr; 118 struct efi_md *map; 119 120 if (fstat(fd, &sb) < 0) 121 return false; 122 buf = malloc(sb.st_size); 123 if (buf == NULL) 124 return false; 125 len = read(fd, buf, sb.st_size); 126 /* NB: we're reading this from sysfs, so mismatch OK */ 127 if (len <= 0) 128 goto errout; 129 130 /* 131 * Look for /chosen to find these values: 132 * linux,uefi-system-table PA of the UEFI System Table. 133 * linux,uefi-mmap-start PA of the UEFI memory map 134 * linux,uefi-mmap-size Size of mmap 135 * linux,uefi-mmap-desc-size Size of each entry of mmap 136 * linux,uefi-mmap-desc-ver Format version, should be 1 137 */ 138 offset = fdt_path_offset(buf, "/chosen"); 139 if (offset <= 0) 140 goto errout; 141 u64p = fdt_getprop(buf, offset, "linux,uefi-system-table", &len); 142 if (u64p == NULL) 143 goto errout; 144 efi_systbl_phys = fdt64_to_cpu(*u64p); 145 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-ver", &len); 146 if (u32p == NULL) 147 goto errout; 148 ver = fdt32_to_cpu(*u32p); 149 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-size", &len); 150 if (u32p == NULL) 151 goto errout; 152 esz = fdt32_to_cpu(*u32p); 153 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-size", &len); 154 if (u32p == NULL) 155 goto errout; 156 sz = fdt32_to_cpu(*u32p); 157 u64p = fdt_getprop(buf, offset, "linux,uefi-mmap-start", &len); 158 if (u64p == NULL) 159 goto errout; 160 mmap_pa = fdt64_to_cpu(*u64p); 161 free(buf); 162 163 printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n", 164 ver, esz, sz, mmap_pa); 165 166 /* 167 * We may have no ability to read the PA that this map is in, so pass 168 * the address to FreeBSD via a rather odd flag entry as the first map 169 * so early boot can copy the memory map into this space and have the 170 * rest of the code cope. 171 */ 172 efisz = (sizeof(*efihdr) + 0xf) & ~0xf; 173 buf = malloc(sz + efisz); 174 if (buf == NULL) 175 return false; 176 efihdr = (struct efi_map_header *)buf; 177 map = (struct efi_md *)((uint8_t *)efihdr + efisz); 178 bzero(map, sz); 179 efihdr->memory_size = sz; 180 efihdr->descriptor_size = esz; 181 efihdr->descriptor_version = ver; 182 183 /* 184 * Save EFI table. Either this will be an empty table filled in by the trampoline, 185 * or we'll read it below. Either way, set these two variables so we share the best 186 * UEFI memory map with the kernel. 187 */ 188 efi_map_hdr = efihdr; 189 efi_map_size = sz + efisz; 190 191 /* 192 * Try to read in the actual UEFI map. 193 */ 194 fd2 = open("host:/dev/mem", O_RDONLY); 195 if (fd2 < 0) { 196 printf("Will read UEFI mem map in tramp: no /dev/mem, need CONFIG_DEVMEM=y\n"); 197 goto no_read; 198 } 199 if (lseek(fd2, mmap_pa, SEEK_SET) < 0) { 200 printf("Will read UEFI mem map in tramp: lseek failed\n"); 201 goto no_read; 202 } 203 len = read(fd2, map, sz); 204 if (len != sz) { 205 if (len < 0 && errno == EPERM) 206 printf("Will read UEFI mem map in tramp: kernel needs CONFIG_STRICT_DEVMEM=n\n"); 207 else 208 printf("Will read UEFI mem map in tramp: lean = %d errno = %d\n", len, errno); 209 goto no_read; 210 } 211 printf("Read UEFI mem map from physmem\n"); 212 efi_map_phys_src = 0; /* Mark MODINFOMD_EFI_MAP as valid */ 213 close(fd2); 214 printf("UEFI MAP:\n"); 215 printf("%23s %12s %12s %8s %4s\n", 216 "Type", "Physical", "Virtual", "#Pages", "Attr"); 217 foreach_efi_map_entry(efihdr, print_efi_map_entry, NULL); 218 return true; /* OK, we really have the memory map */ 219 220 no_read: 221 efi_map_phys_src = mmap_pa; 222 close(fd2); 223 return true; /* We can get it the trampoline */ 224 225 errout: 226 free(buf); 227 return false; 228 } 229 230 bool 231 enumerate_memory_arch(void) 232 { 233 int fd = -1; 234 bool rv = false; 235 236 fd = open("host:/sys/firmware/fdt", O_RDONLY); 237 if (fd != -1) { 238 rv = do_memory_from_fdt(fd); 239 close(fd); 240 /* 241 * So, we have physaddr to the memory table. However, we can't 242 * open /dev/mem on some platforms to get the actual table. So 243 * we have to fall through to get it from /proc/iomem. 244 */ 245 } 246 if (!rv) { 247 printf("Could not obtain UEFI memory tables, expect failure\n"); 248 } 249 250 populate_avail_from_iomem(); 251 252 print_avail(); 253 254 return true; 255 } 256 257 uint64_t 258 kboot_get_phys_load_segment(void) 259 { 260 #define HOLE_SIZE (64ul << 20) 261 #define KERN_ALIGN (2ul << 20) 262 static uint64_t s = 0; 263 264 if (s != 0) 265 return (s); 266 267 s = first_avail(KERN_ALIGN, HOLE_SIZE, SYSTEM_RAM); 268 if (s != 0) 269 return (s); 270 s = 0x40000000 | 0x4200000; /* should never get here */ 271 printf("Falling back to crazy address %#lx\n", s); 272 return (s); 273 } 274 275 void 276 bi_loadsmap(struct preloaded_file *kfp) 277 { 278 279 /* 280 * Make a note of a systbl. This is nearly mandatory on AARCH64. 281 */ 282 if (efi_systbl_phys) 283 file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(efi_systbl_phys), &efi_systbl_phys); 284 285 /* 286 * If we have efi_map_hdr, then it's a pointer to the PA where this 287 * memory map lives. The trampoline code will copy it over. If we don't 288 * have it, we use whatever we found in /proc/iomap. 289 */ 290 if (efi_map_hdr != NULL) { 291 file_addmetadata(kfp, MODINFOMD_EFI_MAP, efi_map_size, efi_map_hdr); 292 return; 293 } 294 panic("Can't get UEFI memory map, nor a pointer to it, can't proceed.\n"); 295 } 296