1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020 Arm Limited 4 * 5 * Based on arch/arm64/kernel/machine_kexec_file.c: 6 * Copyright (C) 2018 Linaro Limited 7 * 8 * And arch/powerpc/kexec/file_load.c: 9 * Copyright (C) 2016 IBM Corporation 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/kexec.h> 14 #include <linux/memblock.h> 15 #include <linux/libfdt.h> 16 #include <linux/of.h> 17 #include <linux/of_fdt.h> 18 #include <linux/random.h> 19 #include <linux/slab.h> 20 #include <linux/types.h> 21 22 #define RNG_SEED_SIZE 128 23 24 /* 25 * Additional space needed for the FDT buffer so that we can add initrd, 26 * bootargs, kaslr-seed, rng-seed, useable-memory-range and elfcorehdr. 27 */ 28 #define FDT_EXTRA_SPACE 0x1000 29 30 /** 31 * fdt_find_and_del_mem_rsv - delete memory reservation with given address and size 32 * 33 * @fdt: Flattened device tree for the current kernel. 34 * @start: Starting address of the reserved memory. 35 * @size: Size of the reserved memory. 36 * 37 * Return: 0 on success, or negative errno on error. 38 */ 39 static int fdt_find_and_del_mem_rsv(void *fdt, unsigned long start, unsigned long size) 40 { 41 int i, ret, num_rsvs = fdt_num_mem_rsv(fdt); 42 43 for (i = 0; i < num_rsvs; i++) { 44 u64 rsv_start, rsv_size; 45 46 ret = fdt_get_mem_rsv(fdt, i, &rsv_start, &rsv_size); 47 if (ret) { 48 pr_err("Malformed device tree.\n"); 49 return -EINVAL; 50 } 51 52 if (rsv_start == start && rsv_size == size) { 53 ret = fdt_del_mem_rsv(fdt, i); 54 if (ret) { 55 pr_err("Error deleting device tree reservation.\n"); 56 return -EINVAL; 57 } 58 59 return 0; 60 } 61 } 62 63 return -ENOENT; 64 } 65 66 /** 67 * get_addr_size_cells - Get address and size of root node 68 * 69 * @addr_cells: Return address of the root node 70 * @size_cells: Return size of the root node 71 * 72 * Return: 0 on success, or negative errno on error. 73 */ 74 static int get_addr_size_cells(int *addr_cells, int *size_cells) 75 { 76 struct device_node *root; 77 78 root = of_find_node_by_path("/"); 79 if (!root) 80 return -EINVAL; 81 82 *addr_cells = of_n_addr_cells(root); 83 *size_cells = of_n_size_cells(root); 84 85 of_node_put(root); 86 87 return 0; 88 } 89 90 /** 91 * do_get_kexec_buffer - Get address and size of device tree property 92 * 93 * @prop: Device tree property 94 * @len: Size of @prop 95 * @addr: Return address of the node 96 * @size: Return size of the node 97 * 98 * Return: 0 on success, or negative errno on error. 99 */ 100 static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr, 101 size_t *size) 102 { 103 int ret, addr_cells, size_cells; 104 105 ret = get_addr_size_cells(&addr_cells, &size_cells); 106 if (ret) 107 return ret; 108 109 if (len < 4 * (addr_cells + size_cells)) 110 return -ENOENT; 111 112 *addr = of_read_number(prop, addr_cells); 113 *size = of_read_number(prop + 4 * addr_cells, size_cells); 114 115 return 0; 116 } 117 118 /** 119 * ima_get_kexec_buffer - get IMA buffer from the previous kernel 120 * @addr: On successful return, set to point to the buffer contents. 121 * @size: On successful return, set to the buffer size. 122 * 123 * Return: 0 on success, negative errno on error. 124 */ 125 int ima_get_kexec_buffer(void **addr, size_t *size) 126 { 127 int ret, len; 128 unsigned long tmp_addr; 129 size_t tmp_size; 130 const void *prop; 131 132 if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC)) 133 return -ENOTSUPP; 134 135 prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len); 136 if (!prop) 137 return -ENOENT; 138 139 ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size); 140 if (ret) 141 return ret; 142 143 *addr = __va(tmp_addr); 144 *size = tmp_size; 145 146 return 0; 147 } 148 149 /** 150 * ima_free_kexec_buffer - free memory used by the IMA buffer 151 */ 152 int ima_free_kexec_buffer(void) 153 { 154 int ret; 155 unsigned long addr; 156 size_t size; 157 struct property *prop; 158 159 if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC)) 160 return -ENOTSUPP; 161 162 prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL); 163 if (!prop) 164 return -ENOENT; 165 166 ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size); 167 if (ret) 168 return ret; 169 170 ret = of_remove_property(of_chosen, prop); 171 if (ret) 172 return ret; 173 174 return memblock_free(addr, size); 175 176 } 177 178 /** 179 * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt 180 * 181 * @fdt: Flattened Device Tree to update 182 * @chosen_node: Offset to the chosen node in the device tree 183 * 184 * The IMA measurement buffer is of no use to a subsequent kernel, so we always 185 * remove it from the device tree. 186 */ 187 static void remove_ima_buffer(void *fdt, int chosen_node) 188 { 189 int ret, len; 190 unsigned long addr; 191 size_t size; 192 const void *prop; 193 194 if (!IS_ENABLED(CONFIG_HAVE_IMA_KEXEC)) 195 return; 196 197 prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len); 198 if (!prop) 199 return; 200 201 ret = do_get_kexec_buffer(prop, len, &addr, &size); 202 fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer"); 203 if (ret) 204 return; 205 206 ret = fdt_find_and_del_mem_rsv(fdt, addr, size); 207 if (!ret) 208 pr_debug("Removed old IMA buffer reservation.\n"); 209 } 210 211 #ifdef CONFIG_IMA_KEXEC 212 /** 213 * setup_ima_buffer - add IMA buffer information to the fdt 214 * @image: kexec image being loaded. 215 * @fdt: Flattened device tree for the next kernel. 216 * @chosen_node: Offset to the chosen node. 217 * 218 * Return: 0 on success, or negative errno on error. 219 */ 220 static int setup_ima_buffer(const struct kimage *image, void *fdt, 221 int chosen_node) 222 { 223 int ret; 224 225 if (!image->ima_buffer_size) 226 return 0; 227 228 ret = fdt_appendprop_addrrange(fdt, 0, chosen_node, 229 "linux,ima-kexec-buffer", 230 image->ima_buffer_addr, 231 image->ima_buffer_size); 232 if (ret < 0) 233 return -EINVAL; 234 235 ret = fdt_add_mem_rsv(fdt, image->ima_buffer_addr, 236 image->ima_buffer_size); 237 if (ret) 238 return -EINVAL; 239 240 pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n", 241 image->ima_buffer_addr, image->ima_buffer_size); 242 243 return 0; 244 } 245 #else /* CONFIG_IMA_KEXEC */ 246 static inline int setup_ima_buffer(const struct kimage *image, void *fdt, 247 int chosen_node) 248 { 249 return 0; 250 } 251 #endif /* CONFIG_IMA_KEXEC */ 252 253 /* 254 * of_kexec_alloc_and_setup_fdt - Alloc and setup a new Flattened Device Tree 255 * 256 * @image: kexec image being loaded. 257 * @initrd_load_addr: Address where the next initrd will be loaded. 258 * @initrd_len: Size of the next initrd, or 0 if there will be none. 259 * @cmdline: Command line for the next kernel, or NULL if there will 260 * be none. 261 * @extra_fdt_size: Additional size for the new FDT buffer. 262 * 263 * Return: fdt on success, or NULL errno on error. 264 */ 265 void *of_kexec_alloc_and_setup_fdt(const struct kimage *image, 266 unsigned long initrd_load_addr, 267 unsigned long initrd_len, 268 const char *cmdline, size_t extra_fdt_size) 269 { 270 void *fdt; 271 int ret, chosen_node; 272 const void *prop; 273 size_t fdt_size; 274 275 fdt_size = fdt_totalsize(initial_boot_params) + 276 (cmdline ? strlen(cmdline) : 0) + 277 FDT_EXTRA_SPACE + 278 extra_fdt_size; 279 fdt = kvmalloc(fdt_size, GFP_KERNEL); 280 if (!fdt) 281 return NULL; 282 283 ret = fdt_open_into(initial_boot_params, fdt, fdt_size); 284 if (ret < 0) { 285 pr_err("Error %d setting up the new device tree.\n", ret); 286 goto out; 287 } 288 289 /* Remove memory reservation for the current device tree. */ 290 ret = fdt_find_and_del_mem_rsv(fdt, __pa(initial_boot_params), 291 fdt_totalsize(initial_boot_params)); 292 if (ret == -EINVAL) { 293 pr_err("Error removing memory reservation.\n"); 294 goto out; 295 } 296 297 chosen_node = fdt_path_offset(fdt, "/chosen"); 298 if (chosen_node == -FDT_ERR_NOTFOUND) 299 chosen_node = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), 300 "chosen"); 301 if (chosen_node < 0) { 302 ret = chosen_node; 303 goto out; 304 } 305 306 ret = fdt_delprop(fdt, chosen_node, "linux,elfcorehdr"); 307 if (ret && ret != -FDT_ERR_NOTFOUND) 308 goto out; 309 ret = fdt_delprop(fdt, chosen_node, "linux,usable-memory-range"); 310 if (ret && ret != -FDT_ERR_NOTFOUND) 311 goto out; 312 313 /* Did we boot using an initrd? */ 314 prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", NULL); 315 if (prop) { 316 u64 tmp_start, tmp_end, tmp_size; 317 318 tmp_start = fdt64_to_cpu(*((const fdt64_t *) prop)); 319 320 prop = fdt_getprop(fdt, chosen_node, "linux,initrd-end", NULL); 321 if (!prop) { 322 ret = -EINVAL; 323 goto out; 324 } 325 326 tmp_end = fdt64_to_cpu(*((const fdt64_t *) prop)); 327 328 /* 329 * kexec reserves exact initrd size, while firmware may 330 * reserve a multiple of PAGE_SIZE, so check for both. 331 */ 332 tmp_size = tmp_end - tmp_start; 333 ret = fdt_find_and_del_mem_rsv(fdt, tmp_start, tmp_size); 334 if (ret == -ENOENT) 335 ret = fdt_find_and_del_mem_rsv(fdt, tmp_start, 336 round_up(tmp_size, PAGE_SIZE)); 337 if (ret == -EINVAL) 338 goto out; 339 } 340 341 /* add initrd-* */ 342 if (initrd_load_addr) { 343 ret = fdt_setprop_u64(fdt, chosen_node, "linux,initrd-start", 344 initrd_load_addr); 345 if (ret) 346 goto out; 347 348 ret = fdt_setprop_u64(fdt, chosen_node, "linux,initrd-end", 349 initrd_load_addr + initrd_len); 350 if (ret) 351 goto out; 352 353 ret = fdt_add_mem_rsv(fdt, initrd_load_addr, initrd_len); 354 if (ret) 355 goto out; 356 357 } else { 358 ret = fdt_delprop(fdt, chosen_node, "linux,initrd-start"); 359 if (ret && (ret != -FDT_ERR_NOTFOUND)) 360 goto out; 361 362 ret = fdt_delprop(fdt, chosen_node, "linux,initrd-end"); 363 if (ret && (ret != -FDT_ERR_NOTFOUND)) 364 goto out; 365 } 366 367 if (image->type == KEXEC_TYPE_CRASH) { 368 /* add linux,elfcorehdr */ 369 ret = fdt_appendprop_addrrange(fdt, 0, chosen_node, 370 "linux,elfcorehdr", image->elf_load_addr, 371 image->elf_headers_sz); 372 if (ret) 373 goto out; 374 375 /* 376 * Avoid elfcorehdr from being stomped on in kdump kernel by 377 * setting up memory reserve map. 378 */ 379 ret = fdt_add_mem_rsv(fdt, image->elf_load_addr, 380 image->elf_headers_sz); 381 if (ret) 382 goto out; 383 384 /* add linux,usable-memory-range */ 385 ret = fdt_appendprop_addrrange(fdt, 0, chosen_node, 386 "linux,usable-memory-range", crashk_res.start, 387 crashk_res.end - crashk_res.start + 1); 388 if (ret) 389 goto out; 390 } 391 392 /* add bootargs */ 393 if (cmdline) { 394 ret = fdt_setprop_string(fdt, chosen_node, "bootargs", cmdline); 395 if (ret) 396 goto out; 397 } else { 398 ret = fdt_delprop(fdt, chosen_node, "bootargs"); 399 if (ret && (ret != -FDT_ERR_NOTFOUND)) 400 goto out; 401 } 402 403 /* add kaslr-seed */ 404 ret = fdt_delprop(fdt, chosen_node, "kaslr-seed"); 405 if (ret == -FDT_ERR_NOTFOUND) 406 ret = 0; 407 else if (ret) 408 goto out; 409 410 if (rng_is_initialized()) { 411 u64 seed = get_random_u64(); 412 413 ret = fdt_setprop_u64(fdt, chosen_node, "kaslr-seed", seed); 414 if (ret) 415 goto out; 416 } else { 417 pr_notice("RNG is not initialised: omitting \"%s\" property\n", 418 "kaslr-seed"); 419 } 420 421 /* add rng-seed */ 422 if (rng_is_initialized()) { 423 void *rng_seed; 424 425 ret = fdt_setprop_placeholder(fdt, chosen_node, "rng-seed", 426 RNG_SEED_SIZE, &rng_seed); 427 if (ret) 428 goto out; 429 get_random_bytes(rng_seed, RNG_SEED_SIZE); 430 } else { 431 pr_notice("RNG is not initialised: omitting \"%s\" property\n", 432 "rng-seed"); 433 } 434 435 ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0); 436 if (ret) 437 goto out; 438 439 remove_ima_buffer(fdt, chosen_node); 440 ret = setup_ima_buffer(image, fdt, fdt_path_offset(fdt, "/chosen")); 441 442 out: 443 if (ret) { 444 kvfree(fdt); 445 fdt = NULL; 446 } 447 448 return fdt; 449 } 450