s390/kexec_file: Add kexec_file_load system call
authorPhilipp Rudo <prudo@linux.vnet.ibm.com>
Mon, 19 Jun 2017 08:45:33 +0000 (10:45 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 16 Apr 2018 07:10:22 +0000 (09:10 +0200)
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>
arch/s390/Kconfig
arch/s390/configs/default_defconfig
arch/s390/kernel/Makefile
arch/s390/kernel/compat_wrapper.c
arch/s390/kernel/machine_kexec_file.c [new file with mode: 0644]
arch/s390/kernel/syscalls/syscall.tbl

index 5b8d0859b317c62c829dd6e1c9e8793ac17e5391..3223ce0680c094020c875cb05e010eb80a4475b6 100644 (file)
@@ -51,6 +51,19 @@ config KEXEC
        def_bool y
        select KEXEC_CORE
 
+config KEXEC_FILE
+       bool "kexec file based system call"
+       select KEXEC_CORE
+       select BUILD_BIN2C
+       depends on CRYPTO
+       depends on CRYPTO_SHA256
+       depends on CRYPTO_SHA256_S390
+       ---help---
+         This is new version of kexec system call. This system call is
+         file based and takes file descriptors as system call argument
+         for kernel and initramfs as opposed to list of segments as
+         accepted by previous system call.
+
 config ARCH_HAS_KEXEC_PURGATORY
        def_bool y
        depends on KEXEC_FILE
index 5af8458951cf9db3a1802de32111d26c5a355d5b..2310315b07442bd66e7ae969feade568a8b902f6 100644 (file)
@@ -719,3 +719,4 @@ CONFIG_APPLDATA_BASE=y
 CONFIG_KVM=m
 CONFIG_KVM_S390_UCONTROL=y
 CONFIG_VHOST_NET=m
+CONFIG_KEXEC_FILE=y
index b06a6f79c1ec3b3dba230e6c7a3eadf8e935beea..35bec1ab84e387d39f595cfe9b84801ef8a9d28f 100644 (file)
@@ -82,6 +82,8 @@ obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
 obj-$(CONFIG_UPROBES)          += uprobes.o
 
+obj-$(CONFIG_KEXEC_FILE)       += machine_kexec_file.o
+
 obj-$(CONFIG_PERF_EVENTS)      += perf_event.o perf_cpum_cf.o perf_cpum_sf.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_cpum_cf_events.o perf_regs.o
 
index 11e9d8b5c1b0633ba4eb41eb26c73fc9e78a3a78..607c5e9fba3ddcdfe762c347c8441c447fc529f5 100644 (file)
@@ -182,3 +182,4 @@ COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int,
 COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb);
 COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
 COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags);
+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 (file)
index 0000000..d9b4f9d
--- /dev/null
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * s390 code for kexec_file_load system call
+ *
+ * Copyright IBM Corp. 2018
+ *
+ * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
+ */
+
+#include <linux/elf.h>
+#include <linux/kexec.h>
+#include <asm/setup.h>
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+       NULL,
+};
+
+/*
+ * The kernel is loaded to a fixed location. Turn off kexec_locate_mem_hole
+ * and provide kbuf->mem by hand.
+ */
+int arch_kexec_walk_mem(struct kexec_buf *kbuf,
+                       int (*func)(struct resource *, void *))
+{
+       return 1;
+}
+
+int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
+                                    Elf_Shdr *section,
+                                    const Elf_Shdr *relsec,
+                                    const Elf_Shdr *symtab)
+{
+       Elf_Rela *relas;
+       int i;
+
+       relas = (void *)pi->ehdr + relsec->sh_offset;
+
+       for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) {
+               const Elf_Sym *sym;     /* symbol to relocate */
+               unsigned long addr;     /* final location after relocation */
+               unsigned long val;      /* relocated symbol value */
+               void *loc;              /* tmp location to modify */
+
+               sym = (void *)pi->ehdr + symtab->sh_offset;
+               sym += ELF64_R_SYM(relas[i].r_info);
+
+               if (sym->st_shndx == SHN_UNDEF)
+                       return -ENOEXEC;
+
+               if (sym->st_shndx == SHN_COMMON)
+                       return -ENOEXEC;
+
+               if (sym->st_shndx >= pi->ehdr->e_shnum &&
+                   sym->st_shndx != SHN_ABS)
+                       return -ENOEXEC;
+
+               loc = pi->purgatory_buf;
+               loc += section->sh_offset;
+               loc += relas[i].r_offset;
+
+               val = sym->st_value;
+               if (sym->st_shndx != SHN_ABS)
+                       val += pi->sechdrs[sym->st_shndx].sh_addr;
+               val += relas[i].r_addend;
+
+               addr = section->sh_addr + relas[i].r_offset;
+
+               switch (ELF64_R_TYPE(relas[i].r_info)) {
+               case R_390_8:           /* Direct 8 bit.   */
+                       *(u8 *)loc = val;
+                       break;
+               case R_390_12:          /* Direct 12 bit.  */
+                       *(u16 *)loc &= 0xf000;
+                       *(u16 *)loc |= val & 0xfff;
+                       break;
+               case R_390_16:          /* Direct 16 bit.  */
+                       *(u16 *)loc = val;
+                       break;
+               case R_390_20:          /* Direct 20 bit.  */
+                       *(u32 *)loc &= 0xf00000ff;
+                       *(u32 *)loc |= (val & 0xfff) << 16;     /* DL */
+                       *(u32 *)loc |= (val & 0xff000) >> 4;    /* DH */
+                       break;
+               case R_390_32:          /* Direct 32 bit.  */
+                       *(u32 *)loc = val;
+                       break;
+               case R_390_64:          /* Direct 64 bit.  */
+                       *(u64 *)loc = val;
+                       break;
+               case R_390_PC16:        /* PC relative 16 bit.  */
+                       *(u16 *)loc = (val - addr);
+                       break;
+               case R_390_PC16DBL:     /* PC relative 16 bit shifted by 1.  */
+                       *(u16 *)loc = (val - addr) >> 1;
+                       break;
+               case R_390_PC32DBL:     /* PC relative 32 bit shifted by 1.  */
+                       *(u32 *)loc = (val - addr) >> 1;
+                       break;
+               case R_390_PC32:        /* PC relative 32 bit.  */
+                       *(u32 *)loc = (val - addr);
+                       break;
+               case R_390_PC64:        /* PC relative 64 bit.  */
+                       *(u64 *)loc = (val - addr);
+                       break;
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
+                                 unsigned long buf_len)
+{
+       /* A kernel must be at least large enough to contain head.S. During
+        * load memory in head.S will be accessed, e.g. to register the next
+        * command line. If the next kernel were smaller the current kernel
+        * will panic at load.
+        *
+        * 0x11000 = sizeof(head.S)
+        */
+       if (buf_len < 0x11000)
+               return -ENOEXEC;
+
+       return kexec_image_probe_default(image, buf, buf_len);
+}
index b38d48464368dc5fe102f58e109a68ab80004d84..8b210ead79569413ab74e3a1c03b506f48a1622f 100644 (file)
 378  common    s390_guarded_storage    sys_s390_guarded_storage        compat_sys_s390_guarded_storage
 379  common    statx                   sys_statx                       compat_sys_statx
 380  common    s390_sthyi              sys_s390_sthyi                  compat_sys_s390_sthyi
+381  common    kexec_file_load         sys_kexec_file_load             compat_sys_kexec_file_load