selfboot.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <commonlib/bsd/compression.h> 4 #include <commonlib/endian.h> 5 #include <console/console.h> 6 #include <string.h> 7 #include <symbols.h> 8 #include <cbfs.h> 9 #include <lib.h> 10 #include <bootmem.h> 11 #include <program_loading.h> 12 #include <timestamp.h> 13 #include <cbmem.h> 14 #include <types.h> 15 16 /* The type syntax for C is essentially unparsable. -- Rob Pike */ 17 typedef int (*checker_t)(struct cbfs_payload_segment *cbfssegs, void *args); 18 19 /* Decode a serialized cbfs payload segment 20 * from memory into native endianness. 21 */ 22 static void cbfs_decode_payload_segment(struct cbfs_payload_segment *segment, 23 const struct cbfs_payload_segment *src) 24 { 25 segment->type = read_be32(&src->type); 26 segment->compression = read_be32(&src->compression); 27 segment->offset = read_be32(&src->offset); 28 segment->load_addr = read_be64(&src->load_addr); 29 segment->len = read_be32(&src->len); 30 segment->mem_len = read_be32(&src->mem_len); 31 } 32 33 static int segment_targets_type(void *dest, unsigned long memsz, 34 enum bootmem_type dest_type) 35 { 36 /* No bootmem to check in earlier stages, caller should not use 37 selfload_check(). */ 38 if (!ENV_RAMSTAGE) { 39 printk(BIOS_ERR, 40 "Callers not supposed to call selfload_check() in romstage"); 41 return 0; 42 } 43 44 uintptr_t d = (uintptr_t) dest; 45 if (bootmem_region_targets_type(d, memsz, dest_type)) 46 return 1; 47 48 if (payload_arch_usable_ram_quirk(d, memsz)) 49 return 1; 50 51 printk(BIOS_ERR, "SELF segment doesn't target RAM: %p, %lu bytes\n", dest, memsz); 52 bootmem_dump_ranges(); 53 return 0; 54 } 55 56 static int load_one_segment(uint8_t *dest, 57 uint8_t *src, 58 size_t len, 59 size_t memsz, 60 uint32_t compression, 61 int flags) 62 { 63 unsigned char *middle, *end; 64 printk(BIOS_DEBUG, "Loading Segment: addr: %p memsz: 0x%016zx filesz: 0x%016zx\n", 65 dest, memsz, len); 66 67 /* Compute the boundaries of the segment */ 68 end = dest + memsz; 69 70 /* Copy data from the initial buffer */ 71 switch (compression) { 72 case CBFS_COMPRESS_LZMA: { 73 printk(BIOS_DEBUG, "using LZMA\n"); 74 timestamp_add_now(TS_ULZMA_START); 75 len = ulzman(src, len, dest, memsz); 76 timestamp_add_now(TS_ULZMA_END); 77 if (!len) /* Decompression Error. */ 78 return 0; 79 break; 80 } 81 case CBFS_COMPRESS_LZ4: { 82 printk(BIOS_DEBUG, "using LZ4\n"); 83 timestamp_add_now(TS_ULZ4F_START); 84 len = ulz4fn(src, len, dest, memsz); 85 timestamp_add_now(TS_ULZ4F_END); 86 if (!len) /* Decompression Error. */ 87 return 0; 88 break; 89 } 90 case CBFS_COMPRESS_NONE: { 91 printk(BIOS_DEBUG, "it's not compressed!\n"); 92 memcpy(dest, src, len); 93 break; 94 } 95 default: 96 printk(BIOS_INFO, "CBFS: Unknown compression type %d\n", compression); 97 return 0; 98 } 99 /* Calculate middle after any changes to len. */ 100 middle = dest + len; 101 printk(BIOS_SPEW, "[ 0x%08lx, %08lx, 0x%08lx) <- %08lx\n", 102 (unsigned long)dest, 103 (unsigned long)middle, 104 (unsigned long)end, 105 (unsigned long)src); 106 107 /* Zero the extra bytes between middle & end */ 108 if (middle < end) { 109 printk(BIOS_DEBUG, 110 "Clearing Segment: addr: 0x%016lx memsz: 0x%016lx\n", 111 (unsigned long)middle, 112 (unsigned long)(end - middle)); 113 114 /* Zero the extra bytes */ 115 memset(middle, 0, end - middle); 116 } 117 118 /* 119 * Each architecture can perform additional operations 120 * on the loaded segment 121 */ 122 prog_segment_loaded((uintptr_t)dest, memsz, flags); 123 124 return 1; 125 } 126 127 /* Note: this function is a bit dangerous so is not exported. 128 * It assumes you're smart enough not to call it with the very 129 * last segment, since it uses seg + 1 */ 130 static int last_loadable_segment(struct cbfs_payload_segment *seg) 131 { 132 return read_be32(&(seg + 1)->type) == PAYLOAD_SEGMENT_ENTRY; 133 } 134 135 static int check_payload_segments(struct cbfs_payload_segment *cbfssegs, 136 enum bootmem_type dest_type) 137 { 138 uint8_t *dest; 139 size_t memsz; 140 struct cbfs_payload_segment *seg, segment; 141 142 /* dest_type == INVALID means we're not supposed to check anything. */ 143 if (dest_type == BM_MEM_INVALID) 144 return 0; 145 146 for (seg = cbfssegs;; ++seg) { 147 printk(BIOS_DEBUG, "Checking segment from ROM address %p\n", seg); 148 cbfs_decode_payload_segment(&segment, seg); 149 dest = (uint8_t *)(uintptr_t)segment.load_addr; 150 memsz = segment.mem_len; 151 if (segment.type == PAYLOAD_SEGMENT_ENTRY) 152 break; 153 if (!segment_targets_type(dest, memsz, dest_type)) 154 return -1; 155 } 156 return 0; 157 } 158 159 static int load_payload_segments(struct cbfs_payload_segment *cbfssegs, uintptr_t *entry) 160 { 161 uint8_t *dest, *src; 162 size_t filesz, memsz; 163 uint32_t compression; 164 struct cbfs_payload_segment *first_segment, *seg, segment; 165 int flags = 0; 166 167 for (first_segment = seg = cbfssegs;; ++seg) { 168 printk(BIOS_DEBUG, "Loading segment from ROM address %p\n", seg); 169 170 cbfs_decode_payload_segment(&segment, seg); 171 dest = (uint8_t *)(uintptr_t)segment.load_addr; 172 memsz = segment.mem_len; 173 compression = segment.compression; 174 filesz = segment.len; 175 176 switch (segment.type) { 177 case PAYLOAD_SEGMENT_CODE: 178 case PAYLOAD_SEGMENT_DATA: 179 printk(BIOS_DEBUG, " %s (compression=%x)\n", 180 segment.type == PAYLOAD_SEGMENT_CODE 181 ? "code" : "data", segment.compression); 182 src = ((uint8_t *)first_segment) + segment.offset; 183 printk(BIOS_DEBUG, 184 " New segment dstaddr %p memsize 0x%zx srcaddr %p filesize 0x%zx\n", 185 dest, memsz, src, filesz); 186 187 /* Clean up the values */ 188 if (filesz > memsz) { 189 filesz = memsz; 190 printk(BIOS_DEBUG, " cleaned up filesize 0x%zx\n", filesz); 191 } 192 break; 193 194 case PAYLOAD_SEGMENT_BSS: 195 printk(BIOS_DEBUG, " BSS %p (%d byte)\n", (void *) 196 (intptr_t)segment.load_addr, segment.mem_len); 197 filesz = 0; 198 src = ((uint8_t *)first_segment) + segment.offset; 199 compression = CBFS_COMPRESS_NONE; 200 break; 201 202 case PAYLOAD_SEGMENT_ENTRY: 203 printk(BIOS_DEBUG, " Entry Point %p\n", (void *) 204 (intptr_t)segment.load_addr); 205 206 *entry = segment.load_addr; 207 /* Per definition, a payload always has the entry point 208 * as last segment. Thus, we use the occurrence of the 209 * entry point as break condition for the loop. 210 */ 211 return 0; 212 213 default: 214 /* We found something that we don't know about. Throw 215 * hands into the sky and run away! 216 */ 217 printk(BIOS_EMERG, "Bad segment type %x\n", segment.type); 218 return -1; 219 } 220 /* Note that the 'seg + 1' is safe as we only call this 221 * function on "not the last" * items, since entry 222 * is always last. */ 223 if (last_loadable_segment(seg)) 224 flags = SEG_FINAL; 225 if (!load_one_segment(dest, src, filesz, memsz, compression, flags)) 226 return -1; 227 } 228 229 return 1; 230 } 231 232 __weak int payload_arch_usable_ram_quirk(uint64_t start, uint64_t size) 233 { 234 return 0; 235 } 236 237 bool selfload_mapped(struct prog *payload, void *mapping, 238 enum bootmem_type dest_type) 239 { 240 uintptr_t entry = 0; 241 struct cbfs_payload_segment *cbfssegs; 242 243 cbfssegs = &((struct cbfs_payload *)mapping)->segments; 244 245 if (check_payload_segments(cbfssegs, dest_type)) 246 return false; 247 248 if (load_payload_segments(cbfssegs, &entry)) 249 return false; 250 251 printk(BIOS_SPEW, "Loaded segments\n"); 252 253 /* Pass cbtables to payload if architecture desires it. */ 254 prog_set_entry(payload, (void *)entry, cbmem_find(CBMEM_ID_CBTABLE)); 255 256 return true; 257 } 258 259 bool selfload_check(struct prog *payload, enum bootmem_type dest_type) 260 { 261 if (prog_locate_hook(payload)) 262 return false; 263 264 payload->cbfs_type = CBFS_TYPE_SELF; 265 void *mapping = cbfs_type_map(prog_name(payload), NULL, &payload->cbfs_type); 266 if (!mapping) 267 return false; 268 269 bool ret = selfload_mapped(payload, mapping, dest_type); 270 271 cbfs_unmap(mapping); 272 return ret; 273 } 274 275 bool selfload(struct prog *payload) 276 { 277 return selfload_check(payload, BM_MEM_INVALID); 278 }