s390/kexec: set end-of-ipl flag in last diag308 call
authorAlexander Egorenkov <egorenar@linux.ibm.com>
Fri, 3 Sep 2021 09:08:48 +0000 (11:08 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Mon, 25 Apr 2022 11:54:12 +0000 (13:54 +0200)
If the facility IPL-complete-control is present then the last diag308
call made by kexec shall set the end-of-ipl flag in the subcode register
to signal the hypervisor that this is the last diag308 call made by Linux.
Only the diag308 calls made during a regular kexec need to set
the end-of-ipl flag, in all other cases the hypervisor will ignore it.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/ipl.h
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/relocate_kernel.S

index 3f8ee25..a405b6b 100644 (file)
@@ -133,6 +133,8 @@ int ipl_report_add_certificate(struct ipl_report *report, void *key,
  * DIAG 308 support
  */
 enum diag308_subcode  {
+       DIAG308_CLEAR_RESET = 0,
+       DIAG308_LOAD_NORMAL_RESET = 1,
        DIAG308_REL_HSA = 2,
        DIAG308_LOAD_CLEAR = 3,
        DIAG308_LOAD_NORMAL_DUMP = 4,
@@ -141,6 +143,10 @@ enum diag308_subcode  {
        DIAG308_LOAD_NORMAL = 7,
 };
 
+enum diag308_subcode_flags {
+       DIAG308_FLAG_EI = 1UL << 16,
+};
+
 enum diag308_rc {
        DIAG308_RC_OK           = 0x0001,
        DIAG308_RC_NOCONFIG     = 0x0102,
index 6ebf02e..ab761c0 100644 (file)
 #include <asm/stacktrace.h>
 #include <asm/switch_to.h>
 #include <asm/nmi.h>
+#include <asm/sclp.h>
 
-typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long);
+typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long,
+                                 unsigned long);
 
 extern const unsigned char relocate_kernel[];
 extern const unsigned long long relocate_kernel_len;
@@ -243,6 +245,7 @@ void machine_crash_shutdown(struct pt_regs *regs)
  */
 static void __do_machine_kexec(void *data)
 {
+       unsigned long diag308_subcode;
        relocate_kernel_t data_mover;
        struct kimage *image = data;
 
@@ -251,7 +254,10 @@ static void __do_machine_kexec(void *data)
 
        __arch_local_irq_stnsm(0xfb); /* disable DAT - avoid no-execute */
        /* Call the moving routine */
-       (*data_mover)(&image->head, image->start);
+       diag308_subcode = DIAG308_CLEAR_RESET;
+       if (sclp.has_iplcc)
+               diag308_subcode |= DIAG308_FLAG_EI;
+       (*data_mover)(&image->head, image->start, diag308_subcode);
 
        /* Die if kexec returns */
        disabled_wait();
index 9438368..a9a1a6f 100644 (file)
@@ -14,6 +14,7 @@
  * moves the new kernel to its destination...
  * %r2 = pointer to first kimage_entry_t
  * %r3 = start address - where to jump to after the job is done...
+ * %r4 = subcode
  *
  * %r5 will be used as temp. storage
  * %r6 holds the destination address
@@ -56,7 +57,7 @@ ENTRY(relocate_kernel)
                jo      0b
                j       .base
        .done:
-               sgr     %r0,%r0         # clear register r0
+               lgr     %r0,%r4         # subcode
                cghi    %r3,0
                je      .diag
                la      %r4,load_psw-.base(%r13)        # load psw-address into the register