(rettype)r2;                                                    \
 })
 
+/*
+ * Use call_nodat() to call a function with DAT disabled.
+ * Proper sign and zero extension of function arguments is done.
+ * Usage:
+ *
+ * rc = call_nodat(nr, rettype, fn, t1, a1, t2, a2, ...)
+ *
+ * - nr specifies the number of function arguments of fn.
+ * - fn is the function to be called, where fn is a physical address.
+ * - rettype is the return type of fn.
+ * - t1, a1, ... are pairs, where t1 must match the type of the first
+ *   argument of fn, t2 the second, etc. a1 is the corresponding
+ *   first function argument (not name), etc.
+ *
+ * fn() is called with standard C function call ABI, with the exception
+ * that no useful stackframe or stackpointer is passed via register 15.
+ * Therefore the called function must not use r15 to access the stack.
+ */
+#define call_nodat(nr, rettype, fn, ...)                               \
+({                                                                     \
+       rettype (*__fn)(CALL_PARM_##nr(__VA_ARGS__)) = (fn);            \
+       psw_t psw_enter, psw_leave;                                     \
+       CALL_LARGS_##nr(__VA_ARGS__);                                   \
+       CALL_REGS_##nr;                                                 \
+                                                                       \
+       CALL_TYPECHECK_##nr(__VA_ARGS__);                               \
+       psw_enter.mask = PSW_KERNEL_BITS & ~PSW_MASK_DAT;               \
+       psw_enter.addr = (unsigned long)__fn;                           \
+       asm volatile(                                                   \
+               "       epsw    0,1\n"                                  \
+               "       risbg   1,0,0,31,32\n"                          \
+               "       larl    7,1f\n"                                 \
+               "       stg     1,%[psw_leave]\n"                       \
+               "       stg     7,8+%[psw_leave]\n"                     \
+               "       la      7,%[psw_leave]\n"                       \
+               "       lra     7,0(7)\n"                               \
+               "       larl    1,0f\n"                                 \
+               "       lra     14,0(1)\n"                              \
+               "       lpswe   %[psw_enter]\n"                         \
+               "0:     lpswe   0(7)\n"                                 \
+               "1:\n"                                                  \
+               : CALL_FMT_##nr, [psw_leave] "=Q" (psw_leave)           \
+               : [psw_enter] "Q" (psw_enter)                           \
+               : "7", CALL_CLOBBER_##nr);                              \
+       (rettype)r2;                                                    \
+})
+
 #endif /* _ASM_S390_STACKTRACE_H */
 
 #include <asm/sclp.h>
 
 typedef void (*relocate_kernel_t)(unsigned long, unsigned long, unsigned long);
+typedef int (*purgatory_t)(int);
 
 extern const unsigned char relocate_kernel[];
 extern const unsigned long long relocate_kernel_len;
  * Reset the system, copy boot CPU registers to absolute zero,
  * and jump to the kdump image
  */
-static void __do_machine_kdump(void *image)
+static void __do_machine_kdump(void *data)
 {
-       int (*start_kdump)(int);
+       struct kimage *image = data;
+       purgatory_t purgatory;
        unsigned long prefix;
 
+       purgatory = (purgatory_t)image->start;
+
        /* store_status() saved the prefix register to lowcore */
        prefix = (unsigned long) S390_lowcore.prefixreg_save_area;
 
        memcpy(absolute_pointer(__LC_FPREGS_SAVE_AREA),
               phys_to_virt(prefix + __LC_FPREGS_SAVE_AREA), 512);
 
-       __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA);
-       start_kdump = (void *)((struct kimage *) image)->start;
-       start_kdump(1);
+       call_nodat(1, int, purgatory, int, 1);
 
-       /* Die if start_kdump returns */
+       /* Die if kdump returns */
        disabled_wait();
 }
 
 
 static int do_start_kdump(struct kimage *image)
 {
-       int (*start_kdump)(int) = (void *)image->start;
-       int rc;
+       purgatory_t purgatory = (purgatory_t)image->start;
 
-       __arch_local_irq_stnsm(0xfb); /* disable DAT */
-       rc = start_kdump(0);
-       __arch_local_irq_stosm(0x04); /* enable DAT */
-       return rc;
+       return call_nodat(1, int, purgatory, int, 0);
 }
 
 #endif /* CONFIG_CRASH_DUMP */
                diag308_subcode |= DIAG308_FLAG_EI;
        s390_reset_system();
 
-       __arch_local_irq_stnsm(0xfb); /* disable DAT - avoid no-execute */
-       (*(relocate_kernel_t)data_mover)(entry, image->start, diag308_subcode);
+       call_nodat(3, void, (relocate_kernel_t)data_mover,
+                  unsigned long, entry,
+                  unsigned long, image->start,
+                  unsigned long, diag308_subcode);
 
        /* Die if kexec returns */
        disabled_wait();