xref: /linux/arch/arm64/kernel/kexec_image.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Kexec image loader
4  
5   * Copyright (C) 2018 Linaro Limited
6   * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
7   */
8  
9  #define pr_fmt(fmt)	"kexec_file(Image): " fmt
10  
11  #include <linux/err.h>
12  #include <linux/errno.h>
13  #include <linux/kernel.h>
14  #include <linux/kexec.h>
15  #include <linux/pe.h>
16  #include <linux/string.h>
17  #include <asm/byteorder.h>
18  #include <asm/cpufeature.h>
19  #include <asm/image.h>
20  #include <asm/memory.h>
21  
image_probe(const char * kernel_buf,unsigned long kernel_len)22  static int image_probe(const char *kernel_buf, unsigned long kernel_len)
23  {
24  	const struct arm64_image_header *h =
25  		(const struct arm64_image_header *)(kernel_buf);
26  
27  	if (!h || (kernel_len < sizeof(*h)))
28  		return -EINVAL;
29  
30  	if (memcmp(&h->magic, ARM64_IMAGE_MAGIC, sizeof(h->magic)))
31  		return -EINVAL;
32  
33  	return 0;
34  }
35  
image_load(struct kimage * image,char * kernel,unsigned long kernel_len,char * initrd,unsigned long initrd_len,char * cmdline,unsigned long cmdline_len)36  static void *image_load(struct kimage *image,
37  				char *kernel, unsigned long kernel_len,
38  				char *initrd, unsigned long initrd_len,
39  				char *cmdline, unsigned long cmdline_len)
40  {
41  	struct arm64_image_header *h;
42  	u64 flags, value;
43  	bool be_image, be_kernel;
44  	struct kexec_buf kbuf;
45  	unsigned long text_offset, kernel_segment_number;
46  	struct kexec_segment *kernel_segment;
47  	int ret;
48  
49  	/*
50  	 * We require a kernel with an unambiguous Image header. Per
51  	 * Documentation/arch/arm64/booting.rst, this is the case when image_size
52  	 * is non-zero (practically speaking, since v3.17).
53  	 */
54  	h = (struct arm64_image_header *)kernel;
55  	if (!h->image_size)
56  		return ERR_PTR(-EINVAL);
57  
58  	/* Check cpu features */
59  	flags = le64_to_cpu(h->flags);
60  	be_image = arm64_image_flag_field(flags, ARM64_IMAGE_FLAG_BE);
61  	be_kernel = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
62  	if ((be_image != be_kernel) && !system_supports_mixed_endian())
63  		return ERR_PTR(-EINVAL);
64  
65  	value = arm64_image_flag_field(flags, ARM64_IMAGE_FLAG_PAGE_SIZE);
66  	if (((value == ARM64_IMAGE_FLAG_PAGE_SIZE_4K) &&
67  			!system_supports_4kb_granule()) ||
68  	    ((value == ARM64_IMAGE_FLAG_PAGE_SIZE_64K) &&
69  			!system_supports_64kb_granule()) ||
70  	    ((value == ARM64_IMAGE_FLAG_PAGE_SIZE_16K) &&
71  			!system_supports_16kb_granule()))
72  		return ERR_PTR(-EINVAL);
73  
74  	/* Load the kernel */
75  	kbuf.image = image;
76  	kbuf.buf_min = 0;
77  	kbuf.buf_max = ULONG_MAX;
78  	kbuf.top_down = false;
79  
80  	kbuf.buffer = kernel;
81  	kbuf.bufsz = kernel_len;
82  	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
83  	kbuf.memsz = le64_to_cpu(h->image_size);
84  	text_offset = le64_to_cpu(h->text_offset);
85  	kbuf.buf_align = MIN_KIMG_ALIGN;
86  
87  	/* Adjust kernel segment with TEXT_OFFSET */
88  	kbuf.memsz += text_offset;
89  
90  	kernel_segment_number = image->nr_segments;
91  
92  	/*
93  	 * The location of the kernel segment may make it impossible to satisfy
94  	 * the other segment requirements, so we try repeatedly to find a
95  	 * location that will work.
96  	 */
97  	while ((ret = kexec_add_buffer(&kbuf)) == 0) {
98  		/* Try to load additional data */
99  		kernel_segment = &image->segment[kernel_segment_number];
100  		ret = load_other_segments(image, kernel_segment->mem,
101  					  kernel_segment->memsz, initrd,
102  					  initrd_len, cmdline);
103  		if (!ret)
104  			break;
105  
106  		/*
107  		 * We couldn't find space for the other segments; erase the
108  		 * kernel segment and try the next available hole.
109  		 */
110  		image->nr_segments -= 1;
111  		kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
112  		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
113  	}
114  
115  	if (ret) {
116  		pr_err("Could not find any suitable kernel location!");
117  		return ERR_PTR(ret);
118  	}
119  
120  	kernel_segment = &image->segment[kernel_segment_number];
121  	kernel_segment->mem += text_offset;
122  	kernel_segment->memsz -= text_offset;
123  	image->start = kernel_segment->mem;
124  
125  	kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
126  		      kernel_segment->mem, kbuf.bufsz,
127  		      kernel_segment->memsz);
128  
129  	return NULL;
130  }
131  
132  const struct kexec_file_ops kexec_image_ops = {
133  	.probe = image_probe,
134  	.load = image_load,
135  #ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
136  	.verify_sig = kexec_kernel_verify_pe_sig,
137  #endif
138  };
139