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>
This commit is contained in:
Philipp Rudo 2017-06-19 10:45:33 +02:00 committed by Martin Schwidefsky
parent 840798a1f5
commit 71406883fd
6 changed files with 144 additions and 0 deletions

View 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

View 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

View 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

View 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)

View file

@ -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);
}

View file

@ -388,3 +388,4 @@
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