forked from mirrors/linux
		
	arm64: Use common of_kexec_alloc_and_setup_fdt()
The code for setting up the /chosen node in the device tree and updating the memory reservation for the next kernel has been moved to of_kexec_alloc_and_setup_fdt() defined in "drivers/of/kexec.c". Use the common of_kexec_alloc_and_setup_fdt() to setup the device tree and update the memory reservation for kexec for arm64. Signed-off-by: Rob Herring <robh@kernel.org> Signed-off-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com> Reviewed-by: Thiago Jung Bauermann <bauerman@linux.ibm.com> Signed-off-by: Rob Herring <robh@kernel.org> Link: https://lore.kernel.org/r/20210221174930.27324-7-nramas@linux.microsoft.com
This commit is contained in:
		
							parent
							
								
									b30be4dc73
								
							
						
					
					
						commit
						ac10be5cdb
					
				
					 1 changed files with 8 additions and 174 deletions
				
			
		|  | @ -15,23 +15,12 @@ | ||||||
| #include <linux/kexec.h> | #include <linux/kexec.h> | ||||||
| #include <linux/libfdt.h> | #include <linux/libfdt.h> | ||||||
| #include <linux/memblock.h> | #include <linux/memblock.h> | ||||||
|  | #include <linux/of.h> | ||||||
| #include <linux/of_fdt.h> | #include <linux/of_fdt.h> | ||||||
| #include <linux/random.h> |  | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include <linux/string.h> | #include <linux/string.h> | ||||||
| #include <linux/types.h> | #include <linux/types.h> | ||||||
| #include <linux/vmalloc.h> | #include <linux/vmalloc.h> | ||||||
| #include <asm/byteorder.h> |  | ||||||
| 
 |  | ||||||
| /* relevant device tree properties */ |  | ||||||
| #define FDT_PROP_KEXEC_ELFHDR	"linux,elfcorehdr" |  | ||||||
| #define FDT_PROP_MEM_RANGE	"linux,usable-memory-range" |  | ||||||
| #define FDT_PROP_INITRD_START	"linux,initrd-start" |  | ||||||
| #define FDT_PROP_INITRD_END	"linux,initrd-end" |  | ||||||
| #define FDT_PROP_BOOTARGS	"bootargs" |  | ||||||
| #define FDT_PROP_KASLR_SEED	"kaslr-seed" |  | ||||||
| #define FDT_PROP_RNG_SEED	"rng-seed" |  | ||||||
| #define RNG_SEED_SIZE		128 |  | ||||||
| 
 | 
 | ||||||
| const struct kexec_file_ops * const kexec_file_loaders[] = { | const struct kexec_file_ops * const kexec_file_loaders[] = { | ||||||
| 	&kexec_image_ops, | 	&kexec_image_ops, | ||||||
|  | @ -40,7 +29,7 @@ const struct kexec_file_ops * const kexec_file_loaders[] = { | ||||||
| 
 | 
 | ||||||
| int arch_kimage_file_post_load_cleanup(struct kimage *image) | int arch_kimage_file_post_load_cleanup(struct kimage *image) | ||||||
| { | { | ||||||
| 	vfree(image->arch.dtb); | 	kvfree(image->arch.dtb); | ||||||
| 	image->arch.dtb = NULL; | 	image->arch.dtb = NULL; | ||||||
| 
 | 
 | ||||||
| 	vfree(image->elf_headers); | 	vfree(image->elf_headers); | ||||||
|  | @ -50,164 +39,6 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image) | ||||||
| 	return kexec_image_post_load_cleanup_default(image); | 	return kexec_image_post_load_cleanup_default(image); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int setup_dtb(struct kimage *image, |  | ||||||
| 		     unsigned long initrd_load_addr, unsigned long initrd_len, |  | ||||||
| 		     char *cmdline, void *dtb) |  | ||||||
| { |  | ||||||
| 	int off, ret; |  | ||||||
| 
 |  | ||||||
| 	ret = fdt_path_offset(dtb, "/chosen"); |  | ||||||
| 	if (ret < 0) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	off = ret; |  | ||||||
| 
 |  | ||||||
| 	ret = fdt_delprop(dtb, off, FDT_PROP_KEXEC_ELFHDR); |  | ||||||
| 	if (ret && ret != -FDT_ERR_NOTFOUND) |  | ||||||
| 		goto out; |  | ||||||
| 	ret = fdt_delprop(dtb, off, FDT_PROP_MEM_RANGE); |  | ||||||
| 	if (ret && ret != -FDT_ERR_NOTFOUND) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	if (image->type == KEXEC_TYPE_CRASH) { |  | ||||||
| 		/* add linux,elfcorehdr */ |  | ||||||
| 		ret = fdt_appendprop_addrrange(dtb, 0, off, |  | ||||||
| 				FDT_PROP_KEXEC_ELFHDR, |  | ||||||
| 				image->elf_load_addr, |  | ||||||
| 				image->elf_headers_sz); |  | ||||||
| 		if (ret) |  | ||||||
| 			return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL); |  | ||||||
| 
 |  | ||||||
| 		/* add linux,usable-memory-range */ |  | ||||||
| 		ret = fdt_appendprop_addrrange(dtb, 0, off, |  | ||||||
| 				FDT_PROP_MEM_RANGE, |  | ||||||
| 				crashk_res.start, |  | ||||||
| 				crashk_res.end - crashk_res.start + 1); |  | ||||||
| 		if (ret) |  | ||||||
| 			return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* add bootargs */ |  | ||||||
| 	if (cmdline) { |  | ||||||
| 		ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto out; |  | ||||||
| 	} else { |  | ||||||
| 		ret = fdt_delprop(dtb, off, FDT_PROP_BOOTARGS); |  | ||||||
| 		if (ret && (ret != -FDT_ERR_NOTFOUND)) |  | ||||||
| 			goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* add initrd-* */ |  | ||||||
| 	if (initrd_load_addr) { |  | ||||||
| 		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_START, |  | ||||||
| 				      initrd_load_addr); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto out; |  | ||||||
| 
 |  | ||||||
| 		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_END, |  | ||||||
| 				      initrd_load_addr + initrd_len); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto out; |  | ||||||
| 	} else { |  | ||||||
| 		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_START); |  | ||||||
| 		if (ret && (ret != -FDT_ERR_NOTFOUND)) |  | ||||||
| 			goto out; |  | ||||||
| 
 |  | ||||||
| 		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_END); |  | ||||||
| 		if (ret && (ret != -FDT_ERR_NOTFOUND)) |  | ||||||
| 			goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* add kaslr-seed */ |  | ||||||
| 	ret = fdt_delprop(dtb, off, FDT_PROP_KASLR_SEED); |  | ||||||
| 	if (ret == -FDT_ERR_NOTFOUND) |  | ||||||
| 		ret = 0; |  | ||||||
| 	else if (ret) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	if (rng_is_initialized()) { |  | ||||||
| 		u64 seed = get_random_u64(); |  | ||||||
| 		ret = fdt_setprop_u64(dtb, off, FDT_PROP_KASLR_SEED, seed); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto out; |  | ||||||
| 	} else { |  | ||||||
| 		pr_notice("RNG is not initialised: omitting \"%s\" property\n", |  | ||||||
| 				FDT_PROP_KASLR_SEED); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* add rng-seed */ |  | ||||||
| 	if (rng_is_initialized()) { |  | ||||||
| 		void *rng_seed; |  | ||||||
| 		ret = fdt_setprop_placeholder(dtb, off, FDT_PROP_RNG_SEED, |  | ||||||
| 				RNG_SEED_SIZE, &rng_seed); |  | ||||||
| 		if (ret) |  | ||||||
| 			goto out; |  | ||||||
| 		get_random_bytes(rng_seed, RNG_SEED_SIZE); |  | ||||||
| 	} else { |  | ||||||
| 		pr_notice("RNG is not initialised: omitting \"%s\" property\n", |  | ||||||
| 				FDT_PROP_RNG_SEED); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| out: |  | ||||||
| 	if (ret) |  | ||||||
| 		return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * More space needed so that we can add initrd, bootargs, kaslr-seed, |  | ||||||
|  * rng-seed, userable-memory-range and elfcorehdr. |  | ||||||
|  */ |  | ||||||
| #define DTB_EXTRA_SPACE 0x1000 |  | ||||||
| 
 |  | ||||||
| static int create_dtb(struct kimage *image, |  | ||||||
| 		      unsigned long initrd_load_addr, unsigned long initrd_len, |  | ||||||
| 		      char *cmdline, void **dtb) |  | ||||||
| { |  | ||||||
| 	void *buf; |  | ||||||
| 	size_t buf_size; |  | ||||||
| 	size_t cmdline_len; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	cmdline_len = cmdline ? strlen(cmdline) : 0; |  | ||||||
| 	buf_size = fdt_totalsize(initial_boot_params) |  | ||||||
| 			+ cmdline_len + DTB_EXTRA_SPACE; |  | ||||||
| 
 |  | ||||||
| 	for (;;) { |  | ||||||
| 		buf = vmalloc(buf_size); |  | ||||||
| 		if (!buf) |  | ||||||
| 			return -ENOMEM; |  | ||||||
| 
 |  | ||||||
| 		/* duplicate a device tree blob */ |  | ||||||
| 		ret = fdt_open_into(initial_boot_params, buf, buf_size); |  | ||||||
| 		if (ret) { |  | ||||||
| 			vfree(buf); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		ret = setup_dtb(image, initrd_load_addr, initrd_len, |  | ||||||
| 				cmdline, buf); |  | ||||||
| 		if (ret) { |  | ||||||
| 			vfree(buf); |  | ||||||
| 			if (ret == -ENOMEM) { |  | ||||||
| 				/* unlikely, but just in case */ |  | ||||||
| 				buf_size += DTB_EXTRA_SPACE; |  | ||||||
| 				continue; |  | ||||||
| 			} else { |  | ||||||
| 				return ret; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/* trim it */ |  | ||||||
| 		fdt_pack(buf); |  | ||||||
| 		*dtb = buf; |  | ||||||
| 
 |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int prepare_elf_headers(void **addr, unsigned long *sz) | static int prepare_elf_headers(void **addr, unsigned long *sz) | ||||||
| { | { | ||||||
| 	struct crash_mem *cmem; | 	struct crash_mem *cmem; | ||||||
|  | @ -314,12 +145,15 @@ int load_other_segments(struct kimage *image, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* load dtb */ | 	/* load dtb */ | ||||||
| 	ret = create_dtb(image, initrd_load_addr, initrd_len, cmdline, &dtb); | 	dtb = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr, | ||||||
| 	if (ret) { | 					   initrd_len, cmdline, 0); | ||||||
|  | 	if (!dtb) { | ||||||
| 		pr_err("Preparing for new dtb failed\n"); | 		pr_err("Preparing for new dtb failed\n"); | ||||||
| 		goto out_err; | 		goto out_err; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/* trim it */ | ||||||
|  | 	fdt_pack(dtb); | ||||||
| 	dtb_len = fdt_totalsize(dtb); | 	dtb_len = fdt_totalsize(dtb); | ||||||
| 	kbuf.buffer = dtb; | 	kbuf.buffer = dtb; | ||||||
| 	kbuf.bufsz = dtb_len; | 	kbuf.bufsz = dtb_len; | ||||||
|  | @ -343,6 +177,6 @@ int load_other_segments(struct kimage *image, | ||||||
| 
 | 
 | ||||||
| out_err: | out_err: | ||||||
| 	image->nr_segments = orig_segments; | 	image->nr_segments = orig_segments; | ||||||
| 	vfree(dtb); | 	kvfree(dtb); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Rob Herring
						Rob Herring