diff options
author | Philipp Rudo <prudo@linux.vnet.ibm.com> | 2017-06-19 04:45:33 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-04-16 03:10:22 -0400 |
commit | 71406883fd35794d573b3085433c41d0a3bf6c21 (patch) | |
tree | 757865f09f0b8a41357c2c1ec7b1df915b057cbf | |
parent | 840798a1f52994c172270893bd2ec6013cc92e40 (diff) |
s390/kexec_file: Add kexec_file_load system call
This patch adds the kexec_file_load system call to s390 as well as the arch
specific functions common code requires to work. Loaders for the different
file types will be added later.
Signed-off-by: Philipp Rudo <prudo@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/Kconfig | 13 | ||||
-rw-r--r-- | arch/s390/configs/default_defconfig | 1 | ||||
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/compat_wrapper.c | 1 | ||||
-rw-r--r-- | arch/s390/kernel/machine_kexec_file.c | 126 | ||||
-rw-r--r-- | arch/s390/kernel/syscalls/syscall.tbl | 1 |
6 files changed, 144 insertions, 0 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 5b8d0859b317..3223ce0680c0 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -51,6 +51,19 @@ config KEXEC | |||
51 | def_bool y | 51 | def_bool y |
52 | select KEXEC_CORE | 52 | select KEXEC_CORE |
53 | 53 | ||
54 | config KEXEC_FILE | ||
55 | bool "kexec file based system call" | ||
56 | select KEXEC_CORE | ||
57 | select BUILD_BIN2C | ||
58 | depends on CRYPTO | ||
59 | depends on CRYPTO_SHA256 | ||
60 | depends on CRYPTO_SHA256_S390 | ||
61 | ---help--- | ||
62 | This is new version of kexec system call. This system call is | ||
63 | file based and takes file descriptors as system call argument | ||
64 | for kernel and initramfs as opposed to list of segments as | ||
65 | accepted by previous system call. | ||
66 | |||
54 | config ARCH_HAS_KEXEC_PURGATORY | 67 | config ARCH_HAS_KEXEC_PURGATORY |
55 | def_bool y | 68 | def_bool y |
56 | depends on KEXEC_FILE | 69 | depends on KEXEC_FILE |
diff --git a/arch/s390/configs/default_defconfig b/arch/s390/configs/default_defconfig index 5af8458951cf..2310315b0744 100644 --- a/arch/s390/configs/default_defconfig +++ b/arch/s390/configs/default_defconfig | |||
@@ -719,3 +719,4 @@ CONFIG_APPLDATA_BASE=y | |||
719 | CONFIG_KVM=m | 719 | CONFIG_KVM=m |
720 | CONFIG_KVM_S390_UCONTROL=y | 720 | CONFIG_KVM_S390_UCONTROL=y |
721 | CONFIG_VHOST_NET=m | 721 | CONFIG_VHOST_NET=m |
722 | CONFIG_KEXEC_FILE=y | ||
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index b06a6f79c1ec..35bec1ab84e3 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -82,6 +82,8 @@ obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o | |||
82 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 82 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
83 | obj-$(CONFIG_UPROBES) += uprobes.o | 83 | obj-$(CONFIG_UPROBES) += uprobes.o |
84 | 84 | ||
85 | obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o | ||
86 | |||
85 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o | 87 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o |
86 | obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o perf_regs.o | 88 | obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o perf_regs.o |
87 | 89 | ||
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c index 11e9d8b5c1b0..607c5e9fba3d 100644 --- a/arch/s390/kernel/compat_wrapper.c +++ b/arch/s390/kernel/compat_wrapper.c | |||
@@ -182,3 +182,4 @@ COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, | |||
182 | COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb); | 182 | COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb); |
183 | COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer); | 183 | COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer); |
184 | COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags); | 184 | COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags); |
185 | COMPAT_SYSCALL_WRAP5(kexec_file_load, int, kernel_fd, int, initrd_fd, unsigned long, cmdline_len, const char __user *, cmdline_ptr, unsigned long, flags) | ||
diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c new file mode 100644 index 000000000000..d9b4f9d23e9f --- /dev/null +++ b/arch/s390/kernel/machine_kexec_file.c | |||
@@ -0,0 +1,126 @@ | |||
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 | |||
10 | #include <linux/elf.h> | ||
11 | #include <linux/kexec.h> | ||
12 | #include <asm/setup.h> | ||
13 | |||
14 | const struct kexec_file_ops * const kexec_file_loaders[] = { | ||
15 | NULL, | ||
16 | }; | ||
17 | |||
18 | /* | ||
19 | * The kernel is loaded to a fixed location. Turn off kexec_locate_mem_hole | ||
20 | * and provide kbuf->mem by hand. | ||
21 | */ | ||
22 | int arch_kexec_walk_mem(struct kexec_buf *kbuf, | ||
23 | int (*func)(struct resource *, void *)) | ||
24 | { | ||
25 | return 1; | ||
26 | } | ||
27 | |||
28 | int arch_kexec_apply_relocations_add(struct purgatory_info *pi, | ||
29 | Elf_Shdr *section, | ||
30 | const Elf_Shdr *relsec, | ||
31 | const Elf_Shdr *symtab) | ||
32 | { | ||
33 | Elf_Rela *relas; | ||
34 | int i; | ||
35 | |||
36 | relas = (void *)pi->ehdr + relsec->sh_offset; | ||
37 | |||
38 | for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) { | ||
39 | const Elf_Sym *sym; /* symbol to relocate */ | ||
40 | unsigned long addr; /* final location after relocation */ | ||
41 | unsigned long val; /* relocated symbol value */ | ||
42 | void *loc; /* tmp location to modify */ | ||
43 | |||
44 | sym = (void *)pi->ehdr + symtab->sh_offset; | ||
45 | sym += ELF64_R_SYM(relas[i].r_info); | ||
46 | |||
47 | if (sym->st_shndx == SHN_UNDEF) | ||
48 | return -ENOEXEC; | ||
49 | |||
50 | if (sym->st_shndx == SHN_COMMON) | ||
51 | return -ENOEXEC; | ||
52 | |||
53 | if (sym->st_shndx >= pi->ehdr->e_shnum && | ||
54 | sym->st_shndx != SHN_ABS) | ||
55 | return -ENOEXEC; | ||
56 | |||
57 | loc = pi->purgatory_buf; | ||
58 | loc += section->sh_offset; | ||
59 | loc += relas[i].r_offset; | ||
60 | |||
61 | val = sym->st_value; | ||
62 | if (sym->st_shndx != SHN_ABS) | ||
63 | val += pi->sechdrs[sym->st_shndx].sh_addr; | ||
64 | val += relas[i].r_addend; | ||
65 | |||
66 | addr = section->sh_addr + relas[i].r_offset; | ||
67 | |||
68 | switch (ELF64_R_TYPE(relas[i].r_info)) { | ||
69 | case R_390_8: /* Direct 8 bit. */ | ||
70 | *(u8 *)loc = val; | ||
71 | break; | ||
72 | case R_390_12: /* Direct 12 bit. */ | ||
73 | *(u16 *)loc &= 0xf000; | ||
74 | *(u16 *)loc |= val & 0xfff; | ||
75 | break; | ||
76 | case R_390_16: /* Direct 16 bit. */ | ||
77 | *(u16 *)loc = val; | ||
78 | break; | ||
79 | case R_390_20: /* Direct 20 bit. */ | ||
80 | *(u32 *)loc &= 0xf00000ff; | ||
81 | *(u32 *)loc |= (val & 0xfff) << 16; /* DL */ | ||
82 | *(u32 *)loc |= (val & 0xff000) >> 4; /* DH */ | ||
83 | break; | ||
84 | case R_390_32: /* Direct 32 bit. */ | ||
85 | *(u32 *)loc = val; | ||
86 | break; | ||
87 | case R_390_64: /* Direct 64 bit. */ | ||
88 | *(u64 *)loc = val; | ||
89 | break; | ||
90 | case R_390_PC16: /* PC relative 16 bit. */ | ||
91 | *(u16 *)loc = (val - addr); | ||
92 | break; | ||
93 | case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ | ||
94 | *(u16 *)loc = (val - addr) >> 1; | ||
95 | break; | ||
96 | case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */ | ||
97 | *(u32 *)loc = (val - addr) >> 1; | ||
98 | break; | ||
99 | case R_390_PC32: /* PC relative 32 bit. */ | ||
100 | *(u32 *)loc = (val - addr); | ||
101 | break; | ||
102 | case R_390_PC64: /* PC relative 64 bit. */ | ||
103 | *(u64 *)loc = (val - addr); | ||
104 | break; | ||
105 | default: | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, | ||
113 | unsigned long buf_len) | ||
114 | { | ||
115 | /* A kernel must be at least large enough to contain head.S. During | ||
116 | * load memory in head.S will be accessed, e.g. to register the next | ||
117 | * command line. If the next kernel were smaller the current kernel | ||
118 | * will panic at load. | ||
119 | * | ||
120 | * 0x11000 = sizeof(head.S) | ||
121 | */ | ||
122 | if (buf_len < 0x11000) | ||
123 | return -ENOEXEC; | ||
124 | |||
125 | return kexec_image_probe_default(image, buf, buf_len); | ||
126 | } | ||
diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl index b38d48464368..8b210ead7956 100644 --- a/arch/s390/kernel/syscalls/syscall.tbl +++ b/arch/s390/kernel/syscalls/syscall.tbl | |||
@@ -388,3 +388,4 @@ | |||
388 | 378 common s390_guarded_storage sys_s390_guarded_storage compat_sys_s390_guarded_storage | 388 | 378 common s390_guarded_storage sys_s390_guarded_storage compat_sys_s390_guarded_storage |
389 | 379 common statx sys_statx compat_sys_statx | 389 | 379 common statx sys_statx compat_sys_statx |
390 | 380 common s390_sthyi sys_s390_sthyi compat_sys_s390_sthyi | 390 | 380 common s390_sthyi sys_s390_sthyi compat_sys_s390_sthyi |
391 | 381 common kexec_file_load sys_kexec_file_load compat_sys_kexec_file_load | ||