kexec_image.c 3.7 KB

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