diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/Kconfig | 2 | ||||
-rw-r--r-- | arch/ia64/Kconfig | 2 | ||||
-rw-r--r-- | arch/m68k/Kconfig | 2 | ||||
-rw-r--r-- | arch/mips/Kconfig | 2 | ||||
-rw-r--r-- | arch/powerpc/Kconfig | 2 | ||||
-rw-r--r-- | arch/s390/Kconfig | 2 | ||||
-rw-r--r-- | arch/sh/Kconfig | 2 | ||||
-rw-r--r-- | arch/tile/Kconfig | 2 | ||||
-rw-r--r-- | arch/x86/Kconfig | 2 | ||||
-rw-r--r-- | arch/x86/kernel/machine_kexec_64.c | 142 |
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 | |||
2065 | config KEXEC | 2065 | config 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" | |||
549 | config KEXEC | 549 | config 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 | |||
91 | config KEXEC | 91 | config 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 | ||
2397 | config KEXEC | 2397 | config 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 | |||
399 | config KEXEC | 399 | config 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 | ||
49 | config KEXEC | 49 | config KEXEC |
50 | def_bool y | 50 | def_bool y |
51 | select CRYPTO | ||
52 | select CRYPTO_SHA256 | ||
51 | 53 | ||
52 | config AUDIT_ARCH | 54 | config 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 | |||
595 | config KEXEC | 595 | config 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 | ||
192 | config KEXEC | 192 | config 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 | |||
1583 | config KEXEC | 1583 | config 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 | */ | ||
343 | int 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 | |||
468 | overflow: | ||
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 | } | ||