From f996068f9c42aa7320534aada65c2449b3671847 Mon Sep 17 00:00:00 2001 From: Philipp Rudo Date: Thu, 7 Mar 2019 15:56:34 +0100 Subject: [PATCH] s390/kexec_file: Load new kernel to absolute 0 The leading 64 kB of a kernel image doesn't contain any data needed to boot the new kernel when it was loaded via kexec_file. Thus kexec_file currently strips them off before loading the image. Keep the leading 64 kB in order to be able to pass a ipl_report to the next kernel. Signed-off-by: Philipp Rudo Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/kexec.h | 6 ++++++ arch/s390/kernel/kexec_elf.c | 16 ++++------------ arch/s390/kernel/kexec_image.c | 9 +++++---- arch/s390/kernel/machine_kexec_file.c | 12 ++++++++++-- arch/s390/kernel/relocate_kernel.S | 3 +++ 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h index a38a57ec6d8f1..9ec077b0fb4d8 100644 --- a/arch/s390/include/asm/kexec.h +++ b/arch/s390/include/asm/kexec.h @@ -43,6 +43,9 @@ /* The native architecture */ #define KEXEC_ARCH KEXEC_ARCH_S390 +/* Allow kexec_file to load a segment to 0 */ +#define KEXEC_BUF_MEM_UNKNOWN -1 + /* Provide a dummy definition to avoid build failures. */ static inline void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) { } @@ -52,6 +55,9 @@ struct s390_load_data { /* Pointer to the kernel buffer. Used to register cmdline etc.. */ void *kernel_buf; + /* Load address of the kernel_buf. */ + unsigned long kernel_mem; + /* Parmarea in the kernel buffer. */ struct parmarea *parm; diff --git a/arch/s390/kernel/kexec_elf.c b/arch/s390/kernel/kexec_elf.c index c74ff6b54344f..42bcd93f4318b 100644 --- a/arch/s390/kernel/kexec_elf.c +++ b/arch/s390/kernel/kexec_elf.c @@ -39,28 +39,20 @@ static int kexec_file_add_kernel_elf(struct kimage *image, buf.bufsz = phdr->p_filesz; buf.mem = ALIGN(phdr->p_paddr, phdr->p_align); + if (image->type == KEXEC_TYPE_CRASH) + buf.mem += crashk_res.start; buf.memsz = phdr->p_memsz; + data->memsz = ALIGN(data->memsz, phdr->p_align) + buf.memsz; if (entry - phdr->p_paddr < phdr->p_memsz) { data->kernel_buf = buf.buffer; + data->kernel_mem = buf.mem; data->parm = buf.buffer + PARMAREA; - data->memsz += STARTUP_NORMAL_OFFSET; - - buf.buffer += STARTUP_NORMAL_OFFSET; - buf.bufsz -= STARTUP_NORMAL_OFFSET; - - buf.mem += STARTUP_NORMAL_OFFSET; - buf.memsz -= STARTUP_NORMAL_OFFSET; } - if (image->type == KEXEC_TYPE_CRASH) - buf.mem += crashk_res.start; - ret = kexec_add_buffer(&buf); if (ret) return ret; - - data->memsz = ALIGN(data->memsz, phdr->p_align) + buf.memsz; } return data->memsz ? 0 : -EINVAL; diff --git a/arch/s390/kernel/kexec_image.c b/arch/s390/kernel/kexec_image.c index d7e65eeae22f9..7281540605b70 100644 --- a/arch/s390/kernel/kexec_image.c +++ b/arch/s390/kernel/kexec_image.c @@ -19,17 +19,18 @@ static int kexec_file_add_kernel_image(struct kimage *image, buf.image = image; - buf.buffer = image->kernel_buf + STARTUP_NORMAL_OFFSET; - buf.bufsz = image->kernel_buf_len - STARTUP_NORMAL_OFFSET; + buf.buffer = image->kernel_buf; + buf.bufsz = image->kernel_buf_len; - buf.mem = STARTUP_NORMAL_OFFSET; + buf.mem = 0; if (image->type == KEXEC_TYPE_CRASH) buf.mem += crashk_res.start; buf.memsz = buf.bufsz; data->kernel_buf = image->kernel_buf; + data->kernel_mem = buf.mem; data->parm = image->kernel_buf + PARMAREA; - data->memsz += buf.memsz + STARTUP_NORMAL_OFFSET; + data->memsz += buf.memsz; return kexec_add_buffer(&buf); } diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c index 08409d61aecaa..0e2a5a7a1b7c4 100644 --- a/arch/s390/kernel/machine_kexec_file.c +++ b/arch/s390/kernel/machine_kexec_file.c @@ -17,7 +17,8 @@ const struct kexec_file_ops * const kexec_file_loaders[] = { NULL, }; -static int kexec_file_update_purgatory(struct kimage *image) +static int kexec_file_update_purgatory(struct kimage *image, + struct s390_load_data *data) { u64 entry, type; int ret; @@ -76,7 +77,7 @@ static int kexec_file_add_purgatory(struct kimage *image, if (ret) return ret; - ret = kexec_file_update_purgatory(image); + ret = kexec_file_update_purgatory(image, data); return ret; } @@ -136,6 +137,13 @@ void *kexec_file_add_components(struct kimage *image, if (ret) return ERR_PTR(ret); + if (data.kernel_mem == 0) { + unsigned long restart_psw = 0x0008000080000000UL; + restart_psw += image->start; + memcpy(data.kernel_buf, &restart_psw, sizeof(restart_psw)); + image->start = 0; + } + return NULL; } diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S index c97c2d40fe15a..1b56f087ce2ce 100644 --- a/arch/s390/kernel/relocate_kernel.S +++ b/arch/s390/kernel/relocate_kernel.S @@ -58,10 +58,13 @@ ENTRY(relocate_kernel) j .base .done: sgr %r0,%r0 # clear register r0 + cghi %r3,0 + je .diag la %r4,load_psw-.base(%r13) # load psw-address into the register o %r3,4(%r4) # or load address into psw st %r3,4(%r4) mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0 + .diag: diag %r0,%r0,0x308 .align 8 -- 2.39.5