~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm64/kernel/kexec_image.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 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 
 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php