summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Rudo <prudo@linux.ibm.com>2019-03-07 15:56:34 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2019-04-29 10:44:00 +0200
commit653beba24d4cd281b078eab48c9bce956939061c (patch)
tree666e391e3156330ba0f82d216408aae68bd9e2e6
parent8e4964261374aaec9f4a83de076ceb11c8cdc044 (diff)
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 <prudo@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/kexec.h6
-rw-r--r--arch/s390/kernel/kexec_elf.c16
-rw-r--r--arch/s390/kernel/kexec_image.c9
-rw-r--r--arch/s390/kernel/machine_kexec_file.c12
-rw-r--r--arch/s390/kernel/relocate_kernel.S3
5 files changed, 28 insertions, 18 deletions
diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h
index a38a57ec6d8f..9ec077b0fb4d 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 c74ff6b54344..42bcd93f4318 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 d7e65eeae22f..7281540605b7 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 08409d61aeca..0e2a5a7a1b7c 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 c97c2d40fe15..1b56f087ce2c 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