summaryrefslogtreecommitdiff
path: root/arch/s390/kernel/machine_kexec.c
diff options
context:
space:
mode:
authorAlexander Gordeev <agordeev@linux.ibm.com>2023-04-03 08:44:39 +0200
committerVasily Gorbik <gor@linux.ibm.com>2023-04-19 17:24:16 +0200
commit82caf7aba107dbc0e70c330786bed9961a098ab0 (patch)
tree0294836e444dcc17bc519a7a009fdb7a045050a7 /arch/s390/kernel/machine_kexec.c
parent39218bcf941ab1a5eabbf350c0f7a1f1325434b0 (diff)
s390/kdump: rework invocation of DAT-off code
Calling kdump kernel is a two-step process that involves invocation of the purgatory code: first time - to verify the new kernel checksum and second time - to call the new kernel itself. The purgatory code operates on real addresses and does not expect any memory protection. Therefore, before the purgatory code is entered the DAT mode is always turned off. However, it is only restored upon return from the new kernel checksum verification. In case the purgatory was called to start the new kernel and failed the control is returned to the old kernel, but the DAT mode continues staying off. The new kernel start failure is unlikely and leads to the disabled wait state anyway. Still that poses a risk, since the kernel code in general is not DAT-off safe and even calling the disabled_wait() function might crash. Introduce call_nodat() macro that allows entering DAT-off mode, calling an arbitrary function and restoring DAT mode back on. Switch all invocations of DAT-off code to that macro and avoid the above described scenario altogether. Name the call_nodat() macro in small letters after the already existing call_on_stack() and put it to the same header file. Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com> Reviewed-by: Heiko Carstens <hca@linux.ibm.com> [hca@linux.ibm.com: some small modifications to call_nodat() macro] Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch/s390/kernel/machine_kexec.c')
-rw-r--r--arch/s390/kernel/machine_kexec.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index fb887674e159..f5d8abf3b4fb 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -30,6 +30,7 @@
#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;
@@ -40,11 +41,14 @@ 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;
@@ -59,11 +63,9 @@ static void __do_machine_kdump(void *image)
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();
}
@@ -112,13 +114,9 @@ static noinline void __machine_kdump(void *image)
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 */
@@ -258,8 +256,10 @@ static void __do_machine_kexec(void *data)
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();