aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2014-08-08 17:26:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-08 18:57:32 -0400
commit12db5562e0352986a265841638482b84f3a6899b (patch)
tree533100da8331131037128616b3f9d501c07a6def /arch
parent8fc5b4d4121c95482b2583a07863c6b0aba2d9e1 (diff)
kexec: load and relocate purgatory at kernel load time
Load purgatory code in RAM and relocate it based on the location. Relocation code has been inspired by module relocation code and purgatory relocation code in kexec-tools. Also compute the checksums of loaded kexec segments and store them in purgatory. Arch independent code provides this functionality so that arch dependent bootloaders can make use of it. Helper functions are provided to get/set symbol values in purgatory which are used by bootloaders later to set things like stack and entry point of second kernel etc. Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Cc: Borislav Petkov <bp@suse.de> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Eric Biederman <ebiederm@xmission.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Cc: Greg Kroah-Hartman <greg@kroah.com> Cc: Dave Young <dyoung@redhat.com> Cc: WANG Chao <chaowang@redhat.com> Cc: Baoquan He <bhe@redhat.com> Cc: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/ia64/Kconfig2
-rw-r--r--arch/m68k/Kconfig2
-rw-r--r--arch/mips/Kconfig2
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/s390/Kconfig2
-rw-r--r--arch/sh/Kconfig2
-rw-r--r--arch/tile/Kconfig2
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/kernel/machine_kexec_64.c142
10 files changed, 160 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8e9dbcbcf5af..cacc8d5355b3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2065,6 +2065,8 @@ config XIP_PHYS_ADDR
2065config KEXEC 2065config KEXEC
2066 bool "Kexec system call (EXPERIMENTAL)" 2066 bool "Kexec system call (EXPERIMENTAL)"
2067 depends on (!SMP || PM_SLEEP_SMP) 2067 depends on (!SMP || PM_SLEEP_SMP)
2068 select CRYPTO
2069 select CRYPTO_SHA256
2068 help 2070 help
2069 kexec is a system call that implements the ability to shutdown your 2071 kexec is a system call that implements the ability to shutdown your
2070 current kernel, and to start another kernel. It is like a reboot 2072 current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index c84c88bbbbd7..64aefb76bd69 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -549,6 +549,8 @@ source "drivers/sn/Kconfig"
549config KEXEC 549config KEXEC
550 bool "kexec system call" 550 bool "kexec system call"
551 depends on !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) 551 depends on !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
552 select CRYPTO
553 select CRYPTO_SHA256
552 help 554 help
553 kexec is a system call that implements the ability to shutdown your 555 kexec is a system call that implements the ability to shutdown your
554 current kernel, and to start another kernel. It is like a reboot 556 current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 87b7c7581b1d..3ff8c9a25335 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -91,6 +91,8 @@ config MMU_SUN3
91config KEXEC 91config KEXEC
92 bool "kexec system call" 92 bool "kexec system call"
93 depends on M68KCLASSIC 93 depends on M68KCLASSIC
94 select CRYPTO
95 select CRYPTO_SHA256
94 help 96 help
95 kexec is a system call that implements the ability to shutdown your 97 kexec is a system call that implements the ability to shutdown your
96 current kernel, and to start another kernel. It is like a reboot 98 current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 900c7e5333b6..df51e78a72cc 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2396,6 +2396,8 @@ source "kernel/Kconfig.preempt"
2396 2396
2397config KEXEC 2397config KEXEC
2398 bool "Kexec system call" 2398 bool "Kexec system call"
2399 select CRYPTO
2400 select CRYPTO_SHA256
2399 help 2401 help
2400 kexec is a system call that implements the ability to shutdown your 2402 kexec is a system call that implements the ability to shutdown your
2401 current kernel, and to start another kernel. It is like a reboot 2403 current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 4bc7b62fb4b6..a577609f8ed6 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -399,6 +399,8 @@ config PPC64_SUPPORTS_MEMORY_FAILURE
399config KEXEC 399config KEXEC
400 bool "kexec system call" 400 bool "kexec system call"
401 depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) 401 depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP))
402 select CRYPTO
403 select CRYPTO_SHA256
402 help 404 help
403 kexec is a system call that implements the ability to shutdown your 405 kexec is a system call that implements the ability to shutdown your
404 current kernel, and to start another kernel. It is like a reboot 406 current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 05c78bb5f570..ab39ceb89ecf 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -48,6 +48,8 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC
48 48
49config KEXEC 49config KEXEC
50 def_bool y 50 def_bool y
51 select CRYPTO
52 select CRYPTO_SHA256
51 53
52config AUDIT_ARCH 54config AUDIT_ARCH
53 def_bool y 55 def_bool y
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index aa2df3eaeb29..453fa5c09550 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -595,6 +595,8 @@ source kernel/Kconfig.hz
595config KEXEC 595config KEXEC
596 bool "kexec system call (EXPERIMENTAL)" 596 bool "kexec system call (EXPERIMENTAL)"
597 depends on SUPERH32 && MMU 597 depends on SUPERH32 && MMU
598 select CRYPTO
599 select CRYPTO_SHA256
598 help 600 help
599 kexec is a system call that implements the ability to shutdown your 601 kexec is a system call that implements the ability to shutdown your
600 current kernel, and to start another kernel. It is like a reboot 602 current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 7fcd492adbfc..a3ffe2dd4832 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -191,6 +191,8 @@ source "kernel/Kconfig.hz"
191 191
192config KEXEC 192config KEXEC
193 bool "kexec system call" 193 bool "kexec system call"
194 select CRYPTO
195 select CRYPTO_SHA256
194 ---help--- 196 ---help---
195 kexec is a system call that implements the ability to shutdown your 197 kexec is a system call that implements the ability to shutdown your
196 current kernel, and to start another kernel. It is like a reboot 198 current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 98fe3df6df82..9558b9fcafbf 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1583,6 +1583,8 @@ source kernel/Kconfig.hz
1583config KEXEC 1583config KEXEC
1584 bool "kexec system call" 1584 bool "kexec system call"
1585 select BUILD_BIN2C 1585 select BUILD_BIN2C
1586 select CRYPTO
1587 select CRYPTO_SHA256
1586 ---help--- 1588 ---help---
1587 kexec is a system call that implements the ability to shutdown your 1589 kexec is a system call that implements the ability to shutdown your
1588 current kernel, and to start another kernel. It is like a reboot 1590 current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index c8875b5545e1..88404c440727 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -6,6 +6,8 @@
6 * Version 2. See the file COPYING for more details. 6 * Version 2. See the file COPYING for more details.
7 */ 7 */
8 8
9#define pr_fmt(fmt) "kexec: " fmt
10
9#include <linux/mm.h> 11#include <linux/mm.h>
10#include <linux/kexec.h> 12#include <linux/kexec.h>
11#include <linux/string.h> 13#include <linux/string.h>
@@ -328,3 +330,143 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
328 330
329 return image->fops->cleanup(image); 331 return image->fops->cleanup(image);
330} 332}
333
334/*
335 * Apply purgatory relocations.
336 *
337 * ehdr: Pointer to elf headers
338 * sechdrs: Pointer to section headers.
339 * relsec: section index of SHT_RELA section.
340 *
341 * TODO: Some of the code belongs to generic code. Move that in kexec.c.
342 */
343int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr,
344 Elf64_Shdr *sechdrs, unsigned int relsec)
345{
346 unsigned int i;
347 Elf64_Rela *rel;
348 Elf64_Sym *sym;
349 void *location;
350 Elf64_Shdr *section, *symtabsec;
351 unsigned long address, sec_base, value;
352 const char *strtab, *name, *shstrtab;
353
354 /*
355 * ->sh_offset has been modified to keep the pointer to section
356 * contents in memory
357 */
358 rel = (void *)sechdrs[relsec].sh_offset;
359
360 /* Section to which relocations apply */
361 section = &sechdrs[sechdrs[relsec].sh_info];
362
363 pr_debug("Applying relocate section %u to %u\n", relsec,
364 sechdrs[relsec].sh_info);
365
366 /* Associated symbol table */
367 symtabsec = &sechdrs[sechdrs[relsec].sh_link];
368
369 /* String table */
370 if (symtabsec->sh_link >= ehdr->e_shnum) {
371 /* Invalid strtab section number */
372 pr_err("Invalid string table section index %d\n",
373 symtabsec->sh_link);
374 return -ENOEXEC;
375 }
376
377 strtab = (char *)sechdrs[symtabsec->sh_link].sh_offset;
378
379 /* section header string table */
380 shstrtab = (char *)sechdrs[ehdr->e_shstrndx].sh_offset;
381
382 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
383
384 /*
385 * rel[i].r_offset contains byte offset from beginning
386 * of section to the storage unit affected.
387 *
388 * This is location to update (->sh_offset). This is temporary
389 * buffer where section is currently loaded. This will finally
390 * be loaded to a different address later, pointed to by
391 * ->sh_addr. kexec takes care of moving it
392 * (kexec_load_segment()).
393 */
394 location = (void *)(section->sh_offset + rel[i].r_offset);
395
396 /* Final address of the location */
397 address = section->sh_addr + rel[i].r_offset;
398
399 /*
400 * rel[i].r_info contains information about symbol table index
401 * w.r.t which relocation must be made and type of relocation
402 * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get
403 * these respectively.
404 */
405 sym = (Elf64_Sym *)symtabsec->sh_offset +
406 ELF64_R_SYM(rel[i].r_info);
407
408 if (sym->st_name)
409 name = strtab + sym->st_name;
410 else
411 name = shstrtab + sechdrs[sym->st_shndx].sh_name;
412
413 pr_debug("Symbol: %s info: %02x shndx: %02x value=%llx size: %llx\n",
414 name, sym->st_info, sym->st_shndx, sym->st_value,
415 sym->st_size);
416
417 if (sym->st_shndx == SHN_UNDEF) {
418 pr_err("Undefined symbol: %s\n", name);
419 return -ENOEXEC;
420 }
421
422 if (sym->st_shndx == SHN_COMMON) {
423 pr_err("symbol '%s' in common section\n", name);
424 return -ENOEXEC;
425 }
426
427 if (sym->st_shndx == SHN_ABS)
428 sec_base = 0;
429 else if (sym->st_shndx >= ehdr->e_shnum) {
430 pr_err("Invalid section %d for symbol %s\n",
431 sym->st_shndx, name);
432 return -ENOEXEC;
433 } else
434 sec_base = sechdrs[sym->st_shndx].sh_addr;
435
436 value = sym->st_value;
437 value += sec_base;
438 value += rel[i].r_addend;
439
440 switch (ELF64_R_TYPE(rel[i].r_info)) {
441 case R_X86_64_NONE:
442 break;
443 case R_X86_64_64:
444 *(u64 *)location = value;
445 break;
446 case R_X86_64_32:
447 *(u32 *)location = value;
448 if (value != *(u32 *)location)
449 goto overflow;
450 break;
451 case R_X86_64_32S:
452 *(s32 *)location = value;
453 if ((s64)value != *(s32 *)location)
454 goto overflow;
455 break;
456 case R_X86_64_PC32:
457 value -= (u64)address;
458 *(u32 *)location = value;
459 break;
460 default:
461 pr_err("Unknown rela relocation: %llu\n",
462 ELF64_R_TYPE(rel[i].r_info));
463 return -ENOEXEC;
464 }
465 }
466 return 0;
467
468overflow:
469 pr_err("Overflow in relocation type %d value 0x%lx\n",
470 (int)ELF64_R_TYPE(rel[i].r_info), value);
471 return -ENOEXEC;
472}