s390/kexec_file: Load new kernel to absolute 0
authorPhilipp Rudo <prudo@linux.ibm.com>
Thu, 7 Mar 2019 14:56:34 +0000 (15:56 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 29 Apr 2019 08:44:00 +0000 (10:44 +0200)
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>
arch/s390/include/asm/kexec.h
arch/s390/kernel/kexec_elf.c
arch/s390/kernel/kexec_image.c
arch/s390/kernel/machine_kexec_file.c
arch/s390/kernel/relocate_kernel.S

index a38a57ec6d8f13197425f1f7338f4d7bbf476f5f..9ec077b0fb4d83d6549b37080cb115431afadd40 100644 (file)
@@ -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;
 
index c74ff6b54344f1c6f2090dfdcdaa627625eb088a..42bcd93f4318b16b51a7ebba4616057da9978ca3 100644 (file)
@@ -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;
index d7e65eeae22f943f655645235219c7e3002b7d05..7281540605b70b0c43b8516f699dba7c2e438305 100644 (file)
@@ -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);
 }
index 08409d61aecaa4924c1b30c17907fe0e83a3ad9b..0e2a5a7a1b7c4593dfec9d52efb370f3c9b6968a 100644 (file)
@@ -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;
 }
 
index c97c2d40fe15aae36d446036043cb4cf70fe2dd7..1b56f087ce2cea60b9b918157a5c66ea11dcae12 100644 (file)
@@ -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