1 /*- 2 * Copyright (c) 2022 Netflix, Inc 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <sys/param.h> 8 #include <machine/metadata.h> 9 #include <sys/linker.h> 10 #include <fdt_platform.h> 11 #include <libfdt.h> 12 13 #include "kboot.h" 14 #include "efi.h" 15 16 static bool 17 do_memory_from_fdt(int fd) 18 { 19 struct stat sb; 20 char *buf = NULL; 21 int len, offset; 22 uint32_t sz, ver, esz; 23 uint64_t mmap_pa; 24 const uint32_t *u32p; 25 const uint64_t *u64p; 26 27 if (fstat(fd, &sb) < 0) 28 return false; 29 buf = malloc(sb.st_size); 30 if (buf == NULL) 31 return false; 32 len = read(fd, buf, sb.st_size); 33 /* NB: we're reading this from sysfs, so mismatch OK */ 34 if (len <= 0) 35 goto errout; 36 37 /* 38 * Look for /chosen to find these values: 39 * linux,uefi-system-table PA of the UEFI System Table. 40 * linux,uefi-mmap-start PA of the UEFI memory map 41 * linux,uefi-mmap-size Size of mmap 42 * linux,uefi-mmap-desc-size Size of each entry of mmap 43 * linux,uefi-mmap-desc-ver Format version, should be 1 44 */ 45 offset = fdt_path_offset(buf, "/chosen"); 46 if (offset <= 0) 47 goto errout; 48 u64p = fdt_getprop(buf, offset, "linux,uefi-system-table", &len); 49 if (u64p == NULL) 50 goto errout; 51 efi_set_systbl(fdt64_to_cpu(*u64p)); 52 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-ver", &len); 53 if (u32p == NULL) 54 goto errout; 55 ver = fdt32_to_cpu(*u32p); 56 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-desc-size", &len); 57 if (u32p == NULL) 58 goto errout; 59 esz = fdt32_to_cpu(*u32p); 60 u32p = fdt_getprop(buf, offset, "linux,uefi-mmap-size", &len); 61 if (u32p == NULL) 62 goto errout; 63 sz = fdt32_to_cpu(*u32p); 64 u64p = fdt_getprop(buf, offset, "linux,uefi-mmap-start", &len); 65 if (u64p == NULL) 66 goto errout; 67 mmap_pa = fdt64_to_cpu(*u64p); 68 free(buf); 69 70 printf("UEFI MMAP: Ver %d Ent Size %d Tot Size %d PA %#lx\n", 71 ver, esz, sz, mmap_pa); 72 73 efi_read_from_pa(mmap_pa, sz, esz, ver); 74 return true; 75 76 errout: 77 free(buf); 78 return false; 79 } 80 81 bool 82 enumerate_memory_arch(void) 83 { 84 int fd = -1; 85 bool rv = false; 86 87 /* 88 * FDT publishes the parameters for the memory table in a series of 89 * nodes in the DTB. One of them is the physical address for the memory 90 * table. Try to open the fdt nblob to find this information if we can 91 * and try to grab things from memory. If we return rv == TRUE then 92 * we found it. The global efi_map_phys_src is set != 0 when we know 93 * the PA but can't read it. 94 */ 95 fd = open("host:/sys/firmware/fdt", O_RDONLY); 96 if (fd != -1) { 97 rv = do_memory_from_fdt(fd); 98 close(fd); 99 } 100 101 /* 102 * One would think that one could use the raw EFI map to find memory 103 * that's free to boot the kernel with. However, Linux reserves some 104 * areas that it needs to properly. I'm not sure if the printf should be 105 * a panic, but for now, so I can debug (maybe at the loader prompt), 106 * I'm printing and carrying on. 107 */ 108 if (!rv) { 109 printf("Could not obtain UEFI memory tables, expect failure\n"); 110 } 111 112 populate_avail_from_iomem(); 113 print_avail(); 114 115 return true; 116 } 117 118 uint64_t 119 kboot_get_phys_load_segment(void) 120 { 121 #define HOLE_SIZE (64ul << 20) 122 #define KERN_ALIGN (2ul << 20) 123 static uint64_t s = 0; 124 125 if (s != 0) 126 return (s); 127 128 print_avail(); 129 s = first_avail(KERN_ALIGN, HOLE_SIZE, SYSTEM_RAM); 130 printf("KBOOT GET PHYS Using %#llx\n", (long long)s); 131 if (s != 0) 132 return (s); 133 s = 0x40000000 | 0x4200000; /* should never get here */ 134 /* XXX PANIC? XXX */ 135 printf("Falling back to the crazy address %#lx which works in qemu\n", s); 136 return (s); 137 } 138 139 void 140 bi_loadsmap(struct preloaded_file *kfp) 141 { 142 efi_bi_loadsmap(kfp); 143 } 144