13ddd9992SAKASHI Takahiro // SPDX-License-Identifier: GPL-2.0
23ddd9992SAKASHI Takahiro /*
33ddd9992SAKASHI Takahiro  * kexec_file for arm64
43ddd9992SAKASHI Takahiro  *
53ddd9992SAKASHI Takahiro  * Copyright (C) 2018 Linaro Limited
63ddd9992SAKASHI Takahiro  * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
73ddd9992SAKASHI Takahiro  *
852b2a8afSAKASHI Takahiro  * Most code is derived from arm64 port of kexec-tools
93ddd9992SAKASHI Takahiro  */
103ddd9992SAKASHI Takahiro 
113ddd9992SAKASHI Takahiro #define pr_fmt(fmt) "kexec_file: " fmt
123ddd9992SAKASHI Takahiro 
1352b2a8afSAKASHI Takahiro #include <linux/ioport.h>
1452b2a8afSAKASHI Takahiro #include <linux/kernel.h>
153ddd9992SAKASHI Takahiro #include <linux/kexec.h>
1652b2a8afSAKASHI Takahiro #include <linux/libfdt.h>
1752b2a8afSAKASHI Takahiro #include <linux/memblock.h>
1852b2a8afSAKASHI Takahiro #include <linux/of_fdt.h>
19884143f6SAKASHI Takahiro #include <linux/random.h>
203751e728SAKASHI Takahiro #include <linux/slab.h>
2152b2a8afSAKASHI Takahiro #include <linux/string.h>
2252b2a8afSAKASHI Takahiro #include <linux/types.h>
23732291c4SArnd Bergmann #include <linux/vmalloc.h>
2452b2a8afSAKASHI Takahiro #include <asm/byteorder.h>
2552b2a8afSAKASHI Takahiro 
2652b2a8afSAKASHI Takahiro /* relevant device tree properties */
273751e728SAKASHI Takahiro #define FDT_PROP_KEXEC_ELFHDR	"linux,elfcorehdr"
283751e728SAKASHI Takahiro #define FDT_PROP_MEM_RANGE	"linux,usable-memory-range"
29121ca8e5SWill Deacon #define FDT_PROP_INITRD_START	"linux,initrd-start"
30121ca8e5SWill Deacon #define FDT_PROP_INITRD_END	"linux,initrd-end"
31121ca8e5SWill Deacon #define FDT_PROP_BOOTARGS	"bootargs"
32121ca8e5SWill Deacon #define FDT_PROP_KASLR_SEED	"kaslr-seed"
337f591fa7SHsin-Yi Wang #define FDT_PROP_RNG_SEED	"rng-seed"
347f591fa7SHsin-Yi Wang #define RNG_SEED_SIZE		128
353ddd9992SAKASHI Takahiro 
363ddd9992SAKASHI Takahiro const struct kexec_file_ops * const kexec_file_loaders[] = {
37f3b70e50SAKASHI Takahiro 	&kexec_image_ops,
383ddd9992SAKASHI Takahiro 	NULL
393ddd9992SAKASHI Takahiro };
4052b2a8afSAKASHI Takahiro 
4152b2a8afSAKASHI Takahiro int arch_kimage_file_post_load_cleanup(struct kimage *image)
4252b2a8afSAKASHI Takahiro {
4352b2a8afSAKASHI Takahiro 	vfree(image->arch.dtb);
4452b2a8afSAKASHI Takahiro 	image->arch.dtb = NULL;
4552b2a8afSAKASHI Takahiro 
463751e728SAKASHI Takahiro 	vfree(image->arch.elf_headers);
473751e728SAKASHI Takahiro 	image->arch.elf_headers = NULL;
483751e728SAKASHI Takahiro 	image->arch.elf_headers_sz = 0;
493751e728SAKASHI Takahiro 
5052b2a8afSAKASHI Takahiro 	return kexec_image_post_load_cleanup_default(image);
5152b2a8afSAKASHI Takahiro }
5252b2a8afSAKASHI Takahiro 
5352b2a8afSAKASHI Takahiro static int setup_dtb(struct kimage *image,
5452b2a8afSAKASHI Takahiro 		     unsigned long initrd_load_addr, unsigned long initrd_len,
5552b2a8afSAKASHI Takahiro 		     char *cmdline, void *dtb)
5652b2a8afSAKASHI Takahiro {
57121ca8e5SWill Deacon 	int off, ret;
5852b2a8afSAKASHI Takahiro 
59121ca8e5SWill Deacon 	ret = fdt_path_offset(dtb, "/chosen");
60121ca8e5SWill Deacon 	if (ret < 0)
61121ca8e5SWill Deacon 		goto out;
62121ca8e5SWill Deacon 
63121ca8e5SWill Deacon 	off = ret;
6452b2a8afSAKASHI Takahiro 
653751e728SAKASHI Takahiro 	ret = fdt_delprop(dtb, off, FDT_PROP_KEXEC_ELFHDR);
663751e728SAKASHI Takahiro 	if (ret && ret != -FDT_ERR_NOTFOUND)
673751e728SAKASHI Takahiro 		goto out;
683751e728SAKASHI Takahiro 	ret = fdt_delprop(dtb, off, FDT_PROP_MEM_RANGE);
693751e728SAKASHI Takahiro 	if (ret && ret != -FDT_ERR_NOTFOUND)
703751e728SAKASHI Takahiro 		goto out;
713751e728SAKASHI Takahiro 
723751e728SAKASHI Takahiro 	if (image->type == KEXEC_TYPE_CRASH) {
733751e728SAKASHI Takahiro 		/* add linux,elfcorehdr */
743751e728SAKASHI Takahiro 		ret = fdt_appendprop_addrrange(dtb, 0, off,
753751e728SAKASHI Takahiro 				FDT_PROP_KEXEC_ELFHDR,
763751e728SAKASHI Takahiro 				image->arch.elf_headers_mem,
773751e728SAKASHI Takahiro 				image->arch.elf_headers_sz);
783751e728SAKASHI Takahiro 		if (ret)
793751e728SAKASHI Takahiro 			return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
803751e728SAKASHI Takahiro 
813751e728SAKASHI Takahiro 		/* add linux,usable-memory-range */
823751e728SAKASHI Takahiro 		ret = fdt_appendprop_addrrange(dtb, 0, off,
833751e728SAKASHI Takahiro 				FDT_PROP_MEM_RANGE,
843751e728SAKASHI Takahiro 				crashk_res.start,
853751e728SAKASHI Takahiro 				crashk_res.end - crashk_res.start + 1);
863751e728SAKASHI Takahiro 		if (ret)
873751e728SAKASHI Takahiro 			return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
883751e728SAKASHI Takahiro 	}
893751e728SAKASHI Takahiro 
9052b2a8afSAKASHI Takahiro 	/* add bootargs */
9152b2a8afSAKASHI Takahiro 	if (cmdline) {
92121ca8e5SWill Deacon 		ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline);
9352b2a8afSAKASHI Takahiro 		if (ret)
94121ca8e5SWill Deacon 			goto out;
9552b2a8afSAKASHI Takahiro 	} else {
96121ca8e5SWill Deacon 		ret = fdt_delprop(dtb, off, FDT_PROP_BOOTARGS);
9752b2a8afSAKASHI Takahiro 		if (ret && (ret != -FDT_ERR_NOTFOUND))
98121ca8e5SWill Deacon 			goto out;
9952b2a8afSAKASHI Takahiro 	}
10052b2a8afSAKASHI Takahiro 
10152b2a8afSAKASHI Takahiro 	/* add initrd-* */
10252b2a8afSAKASHI Takahiro 	if (initrd_load_addr) {
103121ca8e5SWill Deacon 		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_START,
10452b2a8afSAKASHI Takahiro 				      initrd_load_addr);
10552b2a8afSAKASHI Takahiro 		if (ret)
106121ca8e5SWill Deacon 			goto out;
10752b2a8afSAKASHI Takahiro 
108121ca8e5SWill Deacon 		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_END,
10952b2a8afSAKASHI Takahiro 				      initrd_load_addr + initrd_len);
11052b2a8afSAKASHI Takahiro 		if (ret)
111121ca8e5SWill Deacon 			goto out;
11252b2a8afSAKASHI Takahiro 	} else {
113121ca8e5SWill Deacon 		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_START);
11452b2a8afSAKASHI Takahiro 		if (ret && (ret != -FDT_ERR_NOTFOUND))
115121ca8e5SWill Deacon 			goto out;
11652b2a8afSAKASHI Takahiro 
117121ca8e5SWill Deacon 		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_END);
11852b2a8afSAKASHI Takahiro 		if (ret && (ret != -FDT_ERR_NOTFOUND))
119121ca8e5SWill Deacon 			goto out;
12052b2a8afSAKASHI Takahiro 	}
12152b2a8afSAKASHI Takahiro 
122884143f6SAKASHI Takahiro 	/* add kaslr-seed */
123121ca8e5SWill Deacon 	ret = fdt_delprop(dtb, off, FDT_PROP_KASLR_SEED);
12427966721SAKASHI Takahiro 	if (ret == -FDT_ERR_NOTFOUND)
12527966721SAKASHI Takahiro 		ret = 0;
12627966721SAKASHI Takahiro 	else if (ret)
127121ca8e5SWill Deacon 		goto out;
128884143f6SAKASHI Takahiro 
129884143f6SAKASHI Takahiro 	if (rng_is_initialized()) {
130121ca8e5SWill Deacon 		u64 seed = get_random_u64();
131121ca8e5SWill Deacon 		ret = fdt_setprop_u64(dtb, off, FDT_PROP_KASLR_SEED, seed);
132884143f6SAKASHI Takahiro 		if (ret)
133121ca8e5SWill Deacon 			goto out;
134884143f6SAKASHI Takahiro 	} else {
135884143f6SAKASHI Takahiro 		pr_notice("RNG is not initialised: omitting \"%s\" property\n",
136121ca8e5SWill Deacon 				FDT_PROP_KASLR_SEED);
137884143f6SAKASHI Takahiro 	}
138884143f6SAKASHI Takahiro 
1397f591fa7SHsin-Yi Wang 	/* add rng-seed */
1407f591fa7SHsin-Yi Wang 	if (rng_is_initialized()) {
14199ee28d9SGeorge Spelvin 		void *rng_seed;
14299ee28d9SGeorge Spelvin 		ret = fdt_setprop_placeholder(dtb, off, FDT_PROP_RNG_SEED,
14399ee28d9SGeorge Spelvin 				RNG_SEED_SIZE, &rng_seed);
1447f591fa7SHsin-Yi Wang 		if (ret)
1457f591fa7SHsin-Yi Wang 			goto out;
14699ee28d9SGeorge Spelvin 		get_random_bytes(rng_seed, RNG_SEED_SIZE);
1477f591fa7SHsin-Yi Wang 	} else {
1487f591fa7SHsin-Yi Wang 		pr_notice("RNG is not initialised: omitting \"%s\" property\n",
1497f591fa7SHsin-Yi Wang 				FDT_PROP_RNG_SEED);
1507f591fa7SHsin-Yi Wang 	}
1517f591fa7SHsin-Yi Wang 
152121ca8e5SWill Deacon out:
153121ca8e5SWill Deacon 	if (ret)
154121ca8e5SWill Deacon 		return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL;
155121ca8e5SWill Deacon 
15652b2a8afSAKASHI Takahiro 	return 0;
15752b2a8afSAKASHI Takahiro }
15852b2a8afSAKASHI Takahiro 
15952b2a8afSAKASHI Takahiro /*
1603751e728SAKASHI Takahiro  * More space needed so that we can add initrd, bootargs, kaslr-seed,
1613751e728SAKASHI Takahiro  * rng-seed, userable-memory-range and elfcorehdr.
16252b2a8afSAKASHI Takahiro  */
16352b2a8afSAKASHI Takahiro #define DTB_EXTRA_SPACE 0x1000
16452b2a8afSAKASHI Takahiro 
16552b2a8afSAKASHI Takahiro static int create_dtb(struct kimage *image,
16652b2a8afSAKASHI Takahiro 		      unsigned long initrd_load_addr, unsigned long initrd_len,
16752b2a8afSAKASHI Takahiro 		      char *cmdline, void **dtb)
16852b2a8afSAKASHI Takahiro {
16952b2a8afSAKASHI Takahiro 	void *buf;
17052b2a8afSAKASHI Takahiro 	size_t buf_size;
171ea573680SJean-Philippe Brucker 	size_t cmdline_len;
17252b2a8afSAKASHI Takahiro 	int ret;
17352b2a8afSAKASHI Takahiro 
174ea573680SJean-Philippe Brucker 	cmdline_len = cmdline ? strlen(cmdline) : 0;
17552b2a8afSAKASHI Takahiro 	buf_size = fdt_totalsize(initial_boot_params)
176ea573680SJean-Philippe Brucker 			+ cmdline_len + DTB_EXTRA_SPACE;
17752b2a8afSAKASHI Takahiro 
17852b2a8afSAKASHI Takahiro 	for (;;) {
17952b2a8afSAKASHI Takahiro 		buf = vmalloc(buf_size);
18052b2a8afSAKASHI Takahiro 		if (!buf)
18152b2a8afSAKASHI Takahiro 			return -ENOMEM;
18252b2a8afSAKASHI Takahiro 
18352b2a8afSAKASHI Takahiro 		/* duplicate a device tree blob */
18452b2a8afSAKASHI Takahiro 		ret = fdt_open_into(initial_boot_params, buf, buf_size);
18552b2a8afSAKASHI Takahiro 		if (ret)
18652b2a8afSAKASHI Takahiro 			return -EINVAL;
18752b2a8afSAKASHI Takahiro 
18852b2a8afSAKASHI Takahiro 		ret = setup_dtb(image, initrd_load_addr, initrd_len,
18952b2a8afSAKASHI Takahiro 				cmdline, buf);
19052b2a8afSAKASHI Takahiro 		if (ret) {
19152b2a8afSAKASHI Takahiro 			vfree(buf);
19252b2a8afSAKASHI Takahiro 			if (ret == -ENOMEM) {
19352b2a8afSAKASHI Takahiro 				/* unlikely, but just in case */
19452b2a8afSAKASHI Takahiro 				buf_size += DTB_EXTRA_SPACE;
19552b2a8afSAKASHI Takahiro 				continue;
19652b2a8afSAKASHI Takahiro 			} else {
19752b2a8afSAKASHI Takahiro 				return ret;
19852b2a8afSAKASHI Takahiro 			}
19952b2a8afSAKASHI Takahiro 		}
20052b2a8afSAKASHI Takahiro 
20152b2a8afSAKASHI Takahiro 		/* trim it */
20252b2a8afSAKASHI Takahiro 		fdt_pack(buf);
20352b2a8afSAKASHI Takahiro 		*dtb = buf;
20452b2a8afSAKASHI Takahiro 
20552b2a8afSAKASHI Takahiro 		return 0;
20652b2a8afSAKASHI Takahiro 	}
20752b2a8afSAKASHI Takahiro }
20852b2a8afSAKASHI Takahiro 
2093751e728SAKASHI Takahiro static int prepare_elf_headers(void **addr, unsigned long *sz)
2103751e728SAKASHI Takahiro {
2113751e728SAKASHI Takahiro 	struct crash_mem *cmem;
2123751e728SAKASHI Takahiro 	unsigned int nr_ranges;
2133751e728SAKASHI Takahiro 	int ret;
2143751e728SAKASHI Takahiro 	u64 i;
2153751e728SAKASHI Takahiro 	phys_addr_t start, end;
2163751e728SAKASHI Takahiro 
2173751e728SAKASHI Takahiro 	nr_ranges = 1; /* for exclusion of crashkernel region */
2186e245ad4SMike Rapoport 	for_each_mem_range(i, &start, &end)
2193751e728SAKASHI Takahiro 		nr_ranges++;
2203751e728SAKASHI Takahiro 
221bf508ec9SGustavo A. R. Silva 	cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL);
2223751e728SAKASHI Takahiro 	if (!cmem)
2233751e728SAKASHI Takahiro 		return -ENOMEM;
2243751e728SAKASHI Takahiro 
2253751e728SAKASHI Takahiro 	cmem->max_nr_ranges = nr_ranges;
2263751e728SAKASHI Takahiro 	cmem->nr_ranges = 0;
2276e245ad4SMike Rapoport 	for_each_mem_range(i, &start, &end) {
2283751e728SAKASHI Takahiro 		cmem->ranges[cmem->nr_ranges].start = start;
2293751e728SAKASHI Takahiro 		cmem->ranges[cmem->nr_ranges].end = end - 1;
2303751e728SAKASHI Takahiro 		cmem->nr_ranges++;
2313751e728SAKASHI Takahiro 	}
2323751e728SAKASHI Takahiro 
2333751e728SAKASHI Takahiro 	/* Exclude crashkernel region */
2343751e728SAKASHI Takahiro 	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
2353751e728SAKASHI Takahiro 
2363751e728SAKASHI Takahiro 	if (!ret)
2373751e728SAKASHI Takahiro 		ret =  crash_prepare_elf64_headers(cmem, true, addr, sz);
2383751e728SAKASHI Takahiro 
2393751e728SAKASHI Takahiro 	kfree(cmem);
2403751e728SAKASHI Takahiro 	return ret;
2413751e728SAKASHI Takahiro }
2423751e728SAKASHI Takahiro 
24352b2a8afSAKASHI Takahiro int load_other_segments(struct kimage *image,
24452b2a8afSAKASHI Takahiro 			unsigned long kernel_load_addr,
24552b2a8afSAKASHI Takahiro 			unsigned long kernel_size,
24652b2a8afSAKASHI Takahiro 			char *initrd, unsigned long initrd_len,
24752b2a8afSAKASHI Takahiro 			char *cmdline)
24852b2a8afSAKASHI Takahiro {
24952b2a8afSAKASHI Takahiro 	struct kexec_buf kbuf;
2503751e728SAKASHI Takahiro 	void *headers, *dtb = NULL;
2513751e728SAKASHI Takahiro 	unsigned long headers_sz, initrd_load_addr = 0, dtb_len;
25252b2a8afSAKASHI Takahiro 	int ret = 0;
25352b2a8afSAKASHI Takahiro 
25452b2a8afSAKASHI Takahiro 	kbuf.image = image;
25552b2a8afSAKASHI Takahiro 	/* not allocate anything below the kernel */
25652b2a8afSAKASHI Takahiro 	kbuf.buf_min = kernel_load_addr + kernel_size;
25752b2a8afSAKASHI Takahiro 
2583751e728SAKASHI Takahiro 	/* load elf core header */
2593751e728SAKASHI Takahiro 	if (image->type == KEXEC_TYPE_CRASH) {
2603751e728SAKASHI Takahiro 		ret = prepare_elf_headers(&headers, &headers_sz);
2613751e728SAKASHI Takahiro 		if (ret) {
2623751e728SAKASHI Takahiro 			pr_err("Preparing elf core header failed\n");
2633751e728SAKASHI Takahiro 			goto out_err;
2643751e728SAKASHI Takahiro 		}
2653751e728SAKASHI Takahiro 
2663751e728SAKASHI Takahiro 		kbuf.buffer = headers;
2673751e728SAKASHI Takahiro 		kbuf.bufsz = headers_sz;
2683751e728SAKASHI Takahiro 		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
2693751e728SAKASHI Takahiro 		kbuf.memsz = headers_sz;
2703751e728SAKASHI Takahiro 		kbuf.buf_align = SZ_64K; /* largest supported page size */
2713751e728SAKASHI Takahiro 		kbuf.buf_max = ULONG_MAX;
2723751e728SAKASHI Takahiro 		kbuf.top_down = true;
2733751e728SAKASHI Takahiro 
2743751e728SAKASHI Takahiro 		ret = kexec_add_buffer(&kbuf);
2753751e728SAKASHI Takahiro 		if (ret) {
2763751e728SAKASHI Takahiro 			vfree(headers);
2773751e728SAKASHI Takahiro 			goto out_err;
2783751e728SAKASHI Takahiro 		}
2793751e728SAKASHI Takahiro 		image->arch.elf_headers = headers;
2803751e728SAKASHI Takahiro 		image->arch.elf_headers_mem = kbuf.mem;
2813751e728SAKASHI Takahiro 		image->arch.elf_headers_sz = headers_sz;
2823751e728SAKASHI Takahiro 
2833751e728SAKASHI Takahiro 		pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
28451075e0cSŁukasz Stelmach 			 image->arch.elf_headers_mem, kbuf.bufsz, kbuf.memsz);
2853751e728SAKASHI Takahiro 	}
2863751e728SAKASHI Takahiro 
28752b2a8afSAKASHI Takahiro 	/* load initrd */
28852b2a8afSAKASHI Takahiro 	if (initrd) {
28952b2a8afSAKASHI Takahiro 		kbuf.buffer = initrd;
29052b2a8afSAKASHI Takahiro 		kbuf.bufsz = initrd_len;
291c19d050fSBhupesh Sharma 		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
29252b2a8afSAKASHI Takahiro 		kbuf.memsz = initrd_len;
29352b2a8afSAKASHI Takahiro 		kbuf.buf_align = 0;
29452b2a8afSAKASHI Takahiro 		/* within 1GB-aligned window of up to 32GB in size */
29552b2a8afSAKASHI Takahiro 		kbuf.buf_max = round_down(kernel_load_addr, SZ_1G)
29652b2a8afSAKASHI Takahiro 						+ (unsigned long)SZ_1G * 32;
29752b2a8afSAKASHI Takahiro 		kbuf.top_down = false;
29852b2a8afSAKASHI Takahiro 
29952b2a8afSAKASHI Takahiro 		ret = kexec_add_buffer(&kbuf);
30052b2a8afSAKASHI Takahiro 		if (ret)
30152b2a8afSAKASHI Takahiro 			goto out_err;
30252b2a8afSAKASHI Takahiro 		initrd_load_addr = kbuf.mem;
30352b2a8afSAKASHI Takahiro 
30452b2a8afSAKASHI Takahiro 		pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
30551075e0cSŁukasz Stelmach 				initrd_load_addr, kbuf.bufsz, kbuf.memsz);
30652b2a8afSAKASHI Takahiro 	}
30752b2a8afSAKASHI Takahiro 
30852b2a8afSAKASHI Takahiro 	/* load dtb */
30952b2a8afSAKASHI Takahiro 	ret = create_dtb(image, initrd_load_addr, initrd_len, cmdline, &dtb);
31052b2a8afSAKASHI Takahiro 	if (ret) {
31152b2a8afSAKASHI Takahiro 		pr_err("Preparing for new dtb failed\n");
31252b2a8afSAKASHI Takahiro 		goto out_err;
31352b2a8afSAKASHI Takahiro 	}
31452b2a8afSAKASHI Takahiro 
31552b2a8afSAKASHI Takahiro 	dtb_len = fdt_totalsize(dtb);
31652b2a8afSAKASHI Takahiro 	kbuf.buffer = dtb;
31752b2a8afSAKASHI Takahiro 	kbuf.bufsz = dtb_len;
318c19d050fSBhupesh Sharma 	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
31952b2a8afSAKASHI Takahiro 	kbuf.memsz = dtb_len;
32052b2a8afSAKASHI Takahiro 	/* not across 2MB boundary */
32152b2a8afSAKASHI Takahiro 	kbuf.buf_align = SZ_2M;
32252b2a8afSAKASHI Takahiro 	kbuf.buf_max = ULONG_MAX;
32352b2a8afSAKASHI Takahiro 	kbuf.top_down = true;
32452b2a8afSAKASHI Takahiro 
32552b2a8afSAKASHI Takahiro 	ret = kexec_add_buffer(&kbuf);
32652b2a8afSAKASHI Takahiro 	if (ret)
32752b2a8afSAKASHI Takahiro 		goto out_err;
32852b2a8afSAKASHI Takahiro 	image->arch.dtb = dtb;
32952b2a8afSAKASHI Takahiro 	image->arch.dtb_mem = kbuf.mem;
33052b2a8afSAKASHI Takahiro 
33152b2a8afSAKASHI Takahiro 	pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
33251075e0cSŁukasz Stelmach 			kbuf.mem, kbuf.bufsz, kbuf.memsz);
33352b2a8afSAKASHI Takahiro 
33452b2a8afSAKASHI Takahiro 	return 0;
33552b2a8afSAKASHI Takahiro 
33652b2a8afSAKASHI Takahiro out_err:
33752b2a8afSAKASHI Takahiro 	vfree(dtb);
33852b2a8afSAKASHI Takahiro 	return ret;
33952b2a8afSAKASHI Takahiro }
340