machine_kexec_file.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * s390 code for kexec_file_load system call
  4. *
  5. * Copyright IBM Corp. 2018
  6. *
  7. * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
  8. */
  9. #include <linux/elf.h>
  10. #include <linux/kexec.h>
  11. #include <asm/setup.h>
  12. const struct kexec_file_ops * const kexec_file_loaders[] = {
  13. &s390_kexec_elf_ops,
  14. &s390_kexec_image_ops,
  15. NULL,
  16. };
  17. int *kexec_file_update_kernel(struct kimage *image,
  18. struct s390_load_data *data)
  19. {
  20. unsigned long *loc;
  21. if (image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE)
  22. return ERR_PTR(-EINVAL);
  23. if (image->cmdline_buf_len)
  24. memcpy(data->kernel_buf + COMMAND_LINE_OFFSET,
  25. image->cmdline_buf, image->cmdline_buf_len);
  26. if (image->type == KEXEC_TYPE_CRASH) {
  27. loc = (unsigned long *)(data->kernel_buf + OLDMEM_BASE_OFFSET);
  28. *loc = crashk_res.start;
  29. loc = (unsigned long *)(data->kernel_buf + OLDMEM_SIZE_OFFSET);
  30. *loc = crashk_res.end - crashk_res.start + 1;
  31. }
  32. if (image->initrd_buf) {
  33. loc = (unsigned long *)(data->kernel_buf + INITRD_START_OFFSET);
  34. *loc = data->initrd_load_addr;
  35. loc = (unsigned long *)(data->kernel_buf + INITRD_SIZE_OFFSET);
  36. *loc = image->initrd_buf_len;
  37. }
  38. return NULL;
  39. }
  40. static int kexec_file_update_purgatory(struct kimage *image)
  41. {
  42. u64 entry, type;
  43. int ret;
  44. if (image->type == KEXEC_TYPE_CRASH) {
  45. entry = STARTUP_KDUMP_OFFSET;
  46. type = KEXEC_TYPE_CRASH;
  47. } else {
  48. entry = STARTUP_NORMAL_OFFSET;
  49. type = KEXEC_TYPE_DEFAULT;
  50. }
  51. ret = kexec_purgatory_get_set_symbol(image, "kernel_entry", &entry,
  52. sizeof(entry), false);
  53. if (ret)
  54. return ret;
  55. ret = kexec_purgatory_get_set_symbol(image, "kernel_type", &type,
  56. sizeof(type), false);
  57. if (ret)
  58. return ret;
  59. if (image->type == KEXEC_TYPE_CRASH) {
  60. u64 crash_size;
  61. ret = kexec_purgatory_get_set_symbol(image, "crash_start",
  62. &crashk_res.start,
  63. sizeof(crashk_res.start),
  64. false);
  65. if (ret)
  66. return ret;
  67. crash_size = crashk_res.end - crashk_res.start + 1;
  68. ret = kexec_purgatory_get_set_symbol(image, "crash_size",
  69. &crash_size,
  70. sizeof(crash_size),
  71. false);
  72. }
  73. return ret;
  74. }
  75. int kexec_file_add_purgatory(struct kimage *image, struct s390_load_data *data)
  76. {
  77. struct kexec_buf buf;
  78. int ret;
  79. buf.image = image;
  80. data->memsz = ALIGN(data->memsz, PAGE_SIZE);
  81. buf.mem = data->memsz;
  82. if (image->type == KEXEC_TYPE_CRASH)
  83. buf.mem += crashk_res.start;
  84. ret = kexec_load_purgatory(image, &buf);
  85. if (ret)
  86. return ret;
  87. ret = kexec_file_update_purgatory(image);
  88. return ret;
  89. }
  90. int kexec_file_add_initrd(struct kimage *image, struct s390_load_data *data,
  91. char *initrd, unsigned long initrd_len)
  92. {
  93. struct kexec_buf buf;
  94. int ret;
  95. buf.image = image;
  96. buf.buffer = initrd;
  97. buf.bufsz = initrd_len;
  98. data->memsz = ALIGN(data->memsz, PAGE_SIZE);
  99. buf.mem = data->memsz;
  100. if (image->type == KEXEC_TYPE_CRASH)
  101. buf.mem += crashk_res.start;
  102. buf.memsz = buf.bufsz;
  103. data->initrd_load_addr = buf.mem;
  104. data->memsz += buf.memsz;
  105. ret = kexec_add_buffer(&buf);
  106. return ret;
  107. }
  108. /*
  109. * The kernel is loaded to a fixed location. Turn off kexec_locate_mem_hole
  110. * and provide kbuf->mem by hand.
  111. */
  112. int arch_kexec_walk_mem(struct kexec_buf *kbuf,
  113. int (*func)(struct resource *, void *))
  114. {
  115. return 1;
  116. }
  117. int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
  118. Elf_Shdr *section,
  119. const Elf_Shdr *relsec,
  120. const Elf_Shdr *symtab)
  121. {
  122. Elf_Rela *relas;
  123. int i;
  124. relas = (void *)pi->ehdr + relsec->sh_offset;
  125. for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) {
  126. const Elf_Sym *sym; /* symbol to relocate */
  127. unsigned long addr; /* final location after relocation */
  128. unsigned long val; /* relocated symbol value */
  129. void *loc; /* tmp location to modify */
  130. sym = (void *)pi->ehdr + symtab->sh_offset;
  131. sym += ELF64_R_SYM(relas[i].r_info);
  132. if (sym->st_shndx == SHN_UNDEF)
  133. return -ENOEXEC;
  134. if (sym->st_shndx == SHN_COMMON)
  135. return -ENOEXEC;
  136. if (sym->st_shndx >= pi->ehdr->e_shnum &&
  137. sym->st_shndx != SHN_ABS)
  138. return -ENOEXEC;
  139. loc = pi->purgatory_buf;
  140. loc += section->sh_offset;
  141. loc += relas[i].r_offset;
  142. val = sym->st_value;
  143. if (sym->st_shndx != SHN_ABS)
  144. val += pi->sechdrs[sym->st_shndx].sh_addr;
  145. val += relas[i].r_addend;
  146. addr = section->sh_addr + relas[i].r_offset;
  147. switch (ELF64_R_TYPE(relas[i].r_info)) {
  148. case R_390_8: /* Direct 8 bit. */
  149. *(u8 *)loc = val;
  150. break;
  151. case R_390_12: /* Direct 12 bit. */
  152. *(u16 *)loc &= 0xf000;
  153. *(u16 *)loc |= val & 0xfff;
  154. break;
  155. case R_390_16: /* Direct 16 bit. */
  156. *(u16 *)loc = val;
  157. break;
  158. case R_390_20: /* Direct 20 bit. */
  159. *(u32 *)loc &= 0xf00000ff;
  160. *(u32 *)loc |= (val & 0xfff) << 16; /* DL */
  161. *(u32 *)loc |= (val & 0xff000) >> 4; /* DH */
  162. break;
  163. case R_390_32: /* Direct 32 bit. */
  164. *(u32 *)loc = val;
  165. break;
  166. case R_390_64: /* Direct 64 bit. */
  167. *(u64 *)loc = val;
  168. break;
  169. case R_390_PC16: /* PC relative 16 bit. */
  170. *(u16 *)loc = (val - addr);
  171. break;
  172. case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
  173. *(u16 *)loc = (val - addr) >> 1;
  174. break;
  175. case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */
  176. *(u32 *)loc = (val - addr) >> 1;
  177. break;
  178. case R_390_PC32: /* PC relative 32 bit. */
  179. *(u32 *)loc = (val - addr);
  180. break;
  181. case R_390_PC64: /* PC relative 64 bit. */
  182. *(u64 *)loc = (val - addr);
  183. break;
  184. default:
  185. break;
  186. }
  187. }
  188. return 0;
  189. }
  190. int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
  191. unsigned long buf_len)
  192. {
  193. /* A kernel must be at least large enough to contain head.S. During
  194. * load memory in head.S will be accessed, e.g. to register the next
  195. * command line. If the next kernel were smaller the current kernel
  196. * will panic at load.
  197. *
  198. * 0x11000 = sizeof(head.S)
  199. */
  200. if (buf_len < 0x11000)
  201. return -ENOEXEC;
  202. return kexec_image_probe_default(image, buf, buf_len);
  203. }