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 static bool 27 do_memory_from_fdt(int fd) 28 { 29 struct stat sb; 30 char *buf = NULL; 31 int len, offset, fd2 = -1; 32 uint32_t sz, ver, esz, efisz; 33 uint64_t mmap_pa; 34 const uint32_t *u32p; 35 const uint64_t *u64p; 36 struct efi_map_header *efihdr; 37 struct efi_md *map; 38 39 if (fstat(fd, &sb) < 0) 40 return false; 41 buf = malloc(sb.st_size); 42 if (buf == NULL) 43 return false; 44 len = read(fd, buf, sb.st_size); 45 /* NB: we're reading this from sysfs, so mismatch OK */ 46 if (len <= 0) 47 goto errout; 48 49 /* 50 * Look for /chosen to find these values: 51 * linux,uefi-system-table PA of the UEFI System Table. 52 * linux,uefi-mmap-start PA of the UEFI memory map 53 * linux,uefi-mmap-size Size of mmap 54 * linux,uefi-mmap-desc-size Size of each entry of mmap 55 * linux,uefi-mmap-desc-ver Format version, should be 1 56 */ 57 offset = fdt_path_offset(buf, "/chosen"); 58 if (offset <= 0) 59 goto errout; 60 u64p = fdt_getprop(buf, offset, "linux,uefi-system-table", &len); 61 if (u64p == NULL) 62 goto errout; 63 efi_systbl_phys = fdt64_to_cpu(*u64p); 64 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-ver", &len); 65 if (u32p == NULL) 66 goto errout; 67 ver = fdt32_to_cpu(*u32p); 68 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-size", &len); 69 if (u32p == NULL) 70 goto errout; 71 esz = fdt32_to_cpu(*u32p); 72 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-size", &len); 73 if (u32p == NULL) 74 goto errout; 75 sz = fdt32_to_cpu(*u32p); 76 u64p = fdt_getprop(buf, offset, "linux,uefi-mmap-start", &len); 77 if (u64p == NULL) 78 goto errout; 79 mmap_pa = fdt64_to_cpu(*u64p); 80 free(buf); 81 82 printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n", 83 ver, esz, sz, mmap_pa); 84 85 /* 86 * We may have no ability to read the PA that this map is in, so pass 87 * the address to FreeBSD via a rather odd flag entry as the first map 88 * so early boot can copy the memory map into this space and have the 89 * rest of the code cope. 90 */ 91 efisz = (sizeof(*efihdr) + 0xf) & ~0xf; 92 buf = malloc(sz + efisz); 93 if (buf == NULL) 94 return false; 95 efihdr = (struct efi_map_header *)buf; 96 map = (struct efi_md *)((uint8_t *)efihdr + efisz); 97 bzero(map, sz); 98 efihdr->memory_size = sz; 99 efihdr->descriptor_size = esz; 100 efihdr->descriptor_version = ver; 101 102 /* 103 * Save EFI table. Either this will be an empty table filled in by the trampoline, 104 * or we'll read it below. Either way, set these two variables so we share the best 105 * UEFI memory map with the kernel. 106 */ 107 efi_map_hdr = efihdr; 108 efi_map_size = sz + efisz; 109 110 /* 111 * Try to read in the actual UEFI map. 112 */ 113 fd2 = open("host:/dev/mem", O_RDONLY); 114 if (fd2 < 0) { 115 printf("Will read UEFI mem map in tramp: no /dev/mem, need CONFIG_DEVMEM=y\n"); 116 goto no_read; 117 } 118 if (lseek(fd2, mmap_pa, SEEK_SET) < 0) { 119 printf("Will read UEFI mem map in tramp: lseek failed\n"); 120 goto no_read; 121 } 122 len = read(fd2, map, sz); 123 if (len != sz) { 124 if (len < 0 && errno == EPERM) 125 printf("Will read UEFI mem map in tramp: kernel needs CONFIG_STRICT_DEVMEM=n\n"); 126 else 127 printf("Will read UEFI mem map in tramp: lean = %d errno = %d\n", len, errno); 128 goto no_read; 129 } 130 printf("Read UEFI mem map from physmem\n"); 131 efi_map_phys_src = 0; /* Mark MODINFOMD_EFI_MAP as valid */ 132 close(fd2); 133 return true; /* OK, we really have the memory map */ 134 135 no_read: 136 efi_map_phys_src = mmap_pa; 137 close(fd2); 138 return true; /* We can get it the trampoline */ 139 140 errout: 141 free(buf); 142 return false; 143 } 144 145 bool 146 enumerate_memory_arch(void) 147 { 148 int fd = -1; 149 bool rv = false; 150 151 fd = open("host:/sys/firmware/fdt", O_RDONLY); 152 if (fd != -1) { 153 rv = do_memory_from_fdt(fd); 154 close(fd); 155 /* 156 * So, we have physaddr to the memory table. However, we can't 157 * open /dev/mem on some platforms to get the actual table. So 158 * we have to fall through to get it from /proc/iomem. 159 */ 160 } 161 if (!rv) { 162 printf("Could not obtain UEFI memory tables, expect failure\n"); 163 } 164 165 populate_avail_from_iomem(); 166 167 print_avail(); 168 169 return true; 170 } 171 172 uint64_t 173 kboot_get_phys_load_segment(void) 174 { 175 #define HOLE_SIZE (64ul << 20) 176 #define KERN_ALIGN (2ul << 20) 177 static uint64_t s = 0; 178 179 if (s != 0) 180 return (s); 181 182 s = first_avail(KERN_ALIGN, HOLE_SIZE, SYSTEM_RAM); 183 if (s != 0) 184 return (s); 185 s = 0x40000000 | 0x4200000; /* should never get here */ 186 printf("Falling back to crazy address %#lx\n", s); 187 return (s); 188 } 189 190 void 191 bi_loadsmap(struct preloaded_file *kfp) 192 { 193 194 /* 195 * Make a note of a systbl. This is nearly mandatory on AARCH64. 196 */ 197 if (efi_systbl_phys) 198 file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(efi_systbl_phys), &efi_systbl_phys); 199 200 /* 201 * If we have efi_map_hdr, then it's a pointer to the PA where this 202 * memory map lives. The trampoline code will copy it over. If we don't 203 * have it, we use whatever we found in /proc/iomap. 204 */ 205 if (efi_map_hdr != NULL) { 206 file_addmetadata(kfp, MODINFOMD_EFI_MAP, efi_map_size, efi_map_hdr); 207 return; 208 } 209 panic("Can't get UEFI memory map, nor a pointer to it, can't proceed.\n"); 210 } 211