|
|
@@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(s390_handle_mcck);
|
|
|
* returns 0 if all registers could be validated
|
|
|
* returns 1 otherwise
|
|
|
*/
|
|
|
-static int notrace s390_validate_registers(union mci mci)
|
|
|
+static int notrace s390_validate_registers(union mci mci, int umode)
|
|
|
{
|
|
|
int kill_task;
|
|
|
u64 zero;
|
|
|
@@ -110,26 +110,41 @@ static int notrace s390_validate_registers(union mci mci)
|
|
|
if (!mci.gr) {
|
|
|
/*
|
|
|
* General purpose registers couldn't be restored and have
|
|
|
- * unknown contents. Process needs to be terminated.
|
|
|
+ * unknown contents. Stop system or terminate process.
|
|
|
*/
|
|
|
+ if (!umode)
|
|
|
+ s390_handle_damage();
|
|
|
kill_task = 1;
|
|
|
}
|
|
|
if (!mci.fp) {
|
|
|
/*
|
|
|
- * Floating point registers can't be restored and
|
|
|
- * therefore the process needs to be terminated.
|
|
|
+ * Floating point registers can't be restored. If the
|
|
|
+ * kernel currently uses floating point registers the
|
|
|
+ * system is stopped. If the process has its floating
|
|
|
+ * pointer registers loaded it is terminated.
|
|
|
+ * Otherwise just revalidate the registers.
|
|
|
*/
|
|
|
- kill_task = 1;
|
|
|
+ if (S390_lowcore.fpu_flags & KERNEL_VXR_V0V7)
|
|
|
+ s390_handle_damage();
|
|
|
+ if (!test_cpu_flag(CIF_FPU))
|
|
|
+ kill_task = 1;
|
|
|
}
|
|
|
fpt_save_area = &S390_lowcore.floating_pt_save_area;
|
|
|
fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
|
|
|
if (!mci.fc) {
|
|
|
/*
|
|
|
* Floating point control register can't be restored.
|
|
|
- * Task will be terminated.
|
|
|
+ * If the kernel currently uses the floating pointer
|
|
|
+ * registers and needs the FPC register the system is
|
|
|
+ * stopped. If the process has its floating pointer
|
|
|
+ * registers loaded it is terminated. Otherwiese the
|
|
|
+ * FPC is just revalidated.
|
|
|
*/
|
|
|
+ if (S390_lowcore.fpu_flags & KERNEL_FPC)
|
|
|
+ s390_handle_damage();
|
|
|
asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
|
|
|
- kill_task = 1;
|
|
|
+ if (!test_cpu_flag(CIF_FPU))
|
|
|
+ kill_task = 1;
|
|
|
} else
|
|
|
asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area));
|
|
|
|
|
|
@@ -159,10 +174,16 @@ static int notrace s390_validate_registers(union mci mci)
|
|
|
|
|
|
if (!mci.vr) {
|
|
|
/*
|
|
|
- * Vector registers can't be restored and therefore
|
|
|
- * the process needs to be terminated.
|
|
|
+ * Vector registers can't be restored. If the kernel
|
|
|
+ * currently uses vector registers the system is
|
|
|
+ * stopped. If the process has its vector registers
|
|
|
+ * loaded it is terminated. Otherwise just revalidate
|
|
|
+ * the registers.
|
|
|
*/
|
|
|
- kill_task = 1;
|
|
|
+ if (S390_lowcore.fpu_flags & KERNEL_VXR)
|
|
|
+ s390_handle_damage();
|
|
|
+ if (!test_cpu_flag(CIF_FPU))
|
|
|
+ kill_task = 1;
|
|
|
}
|
|
|
cr0.val = S390_lowcore.cregs_save_area[0];
|
|
|
cr0.afp = cr0.vx = 1;
|
|
|
@@ -250,13 +271,11 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
|
|
struct mcck_struct *mcck;
|
|
|
unsigned long long tmp;
|
|
|
union mci mci;
|
|
|
- int umode;
|
|
|
|
|
|
nmi_enter();
|
|
|
inc_irq_stat(NMI_NMI);
|
|
|
mci.val = S390_lowcore.mcck_interruption_code;
|
|
|
mcck = this_cpu_ptr(&cpu_mcck);
|
|
|
- umode = user_mode(regs);
|
|
|
|
|
|
if (mci.sd) {
|
|
|
/* System damage -> stopping machine */
|
|
|
@@ -297,22 +316,14 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
|
|
|
s390_handle_damage();
|
|
|
}
|
|
|
}
|
|
|
- if (s390_validate_registers(mci)) {
|
|
|
- if (umode) {
|
|
|
- /*
|
|
|
- * Couldn't restore all register contents while in
|
|
|
- * user mode -> mark task for termination.
|
|
|
- */
|
|
|
- mcck->kill_task = 1;
|
|
|
- mcck->mcck_code = mci.val;
|
|
|
- set_cpu_flag(CIF_MCCK_PENDING);
|
|
|
- } else {
|
|
|
- /*
|
|
|
- * Couldn't restore all register contents while in
|
|
|
- * kernel mode -> stopping machine.
|
|
|
- */
|
|
|
- s390_handle_damage();
|
|
|
- }
|
|
|
+ if (s390_validate_registers(mci, user_mode(regs))) {
|
|
|
+ /*
|
|
|
+ * Couldn't restore all register contents for the
|
|
|
+ * user space process -> mark task for termination.
|
|
|
+ */
|
|
|
+ mcck->kill_task = 1;
|
|
|
+ mcck->mcck_code = mci.val;
|
|
|
+ set_cpu_flag(CIF_MCCK_PENDING);
|
|
|
}
|
|
|
if (mci.cd) {
|
|
|
/* Timing facility damage */
|