mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-15 15:04:27 +08:00
s390/mcck: move register validation to C code
This update partially reverts commit 3037a52f98
("s390/nmi:
do register validation as early as possible").
Storage error checks and control registers validation are left
in the assembler code, since correct ASCEs and page tables are
required to enable DAT - which is done before the C handler is
entered.
System damage, kernel instruction address and PSW MWP checks
are left in the assembler code as well, since there is no way
to proceed if one of these checks is failed.
The getcpu vdso syscall reads CPU number from the programmable
field of the TOD clock. Disregard the TOD programmable register
validity bit and load the CPU number into the TOD programmable
field unconditionally.
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
parent
9f744abb46
commit
5fa2ea0714
@ -21,8 +21,6 @@
|
||||
#define CR0_INTERRUPT_KEY_SUBMASK BIT(63 - 57)
|
||||
#define CR0_MEASUREMENT_ALERT_SUBMASK BIT(63 - 58)
|
||||
|
||||
#define CR2_GUARDED_STORAGE BIT(63 - 59)
|
||||
|
||||
#define CR14_UNUSED_32 BIT(63 - 32)
|
||||
#define CR14_UNUSED_33 BIT(63 - 33)
|
||||
#define CR14_CHANNEL_REPORT_SUBMASK BIT(63 - 35)
|
||||
|
@ -14,8 +14,6 @@
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm/idle.h>
|
||||
#include <asm/gmap.h>
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
int main(void)
|
||||
@ -108,7 +106,6 @@ int main(void)
|
||||
OFFSET(__LC_LAST_UPDATE_CLOCK, lowcore, last_update_clock);
|
||||
OFFSET(__LC_INT_CLOCK, lowcore, int_clock);
|
||||
OFFSET(__LC_MCCK_CLOCK, lowcore, mcck_clock);
|
||||
OFFSET(__LC_CLOCK_COMPARATOR, lowcore, clock_comparator);
|
||||
OFFSET(__LC_BOOT_CLOCK, lowcore, boot_clock);
|
||||
OFFSET(__LC_CURRENT, lowcore, current_task);
|
||||
OFFSET(__LC_KERNEL_STACK, lowcore, kernel_stack);
|
||||
@ -145,9 +142,6 @@ int main(void)
|
||||
OFFSET(__LC_CREGS_SAVE_AREA, lowcore, cregs_save_area);
|
||||
OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb);
|
||||
BLANK();
|
||||
/* extended machine check save area */
|
||||
OFFSET(__MCESA_GS_SAVE_AREA, mcesa, guarded_storage_save_area);
|
||||
BLANK();
|
||||
/* gmap/sie offsets */
|
||||
OFFSET(__GMAP_ASCE, gmap, asce);
|
||||
OFFSET(__SIE_PROG0C, kvm_s390_sie_block, prog0c);
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <asm/alternative-asm.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/cache.h>
|
||||
#include <asm/ctl_reg.h>
|
||||
#include <asm/dwarf.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/ptrace.h>
|
||||
@ -506,8 +505,6 @@ ENTRY(mcck_int_handler)
|
||||
BPOFF
|
||||
la %r1,4095 # validate r1
|
||||
spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # validate cpu timer
|
||||
sckc __LC_CLOCK_COMPARATOR # validate comparator
|
||||
lam %a0,%a15,__LC_AREGS_SAVE_AREA-4095(%r1) # validate acrs
|
||||
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# validate gprs
|
||||
lg %r12,__LC_CURRENT
|
||||
lmg %r8,%r9,__LC_MCK_OLD_PSW
|
||||
@ -518,41 +515,7 @@ ENTRY(mcck_int_handler)
|
||||
la %r14,4095
|
||||
lctlg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r14) # validate ctl regs
|
||||
ptlb
|
||||
lg %r11,__LC_MCESAD-4095(%r14) # extended machine check save area
|
||||
nill %r11,0xfc00 # MCESA_ORIGIN_MASK
|
||||
TSTMSK __LC_CREGS_SAVE_AREA+16-4095(%r14),CR2_GUARDED_STORAGE
|
||||
jno 0f
|
||||
TSTMSK __LC_MCCK_CODE,MCCK_CODE_GS_VALID
|
||||
jno 0f
|
||||
.insn rxy,0xe3000000004d,0,__MCESA_GS_SAVE_AREA(%r11) # LGSC
|
||||
0: l %r14,__LC_FP_CREG_SAVE_AREA-4095(%r14)
|
||||
TSTMSK __LC_MCCK_CODE,MCCK_CODE_FC_VALID
|
||||
jo 0f
|
||||
sr %r14,%r14
|
||||
0: sfpc %r14
|
||||
TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
|
||||
jo 0f
|
||||
lghi %r14,__LC_FPREGS_SAVE_AREA
|
||||
ld %f0,0(%r14)
|
||||
ld %f1,8(%r14)
|
||||
ld %f2,16(%r14)
|
||||
ld %f3,24(%r14)
|
||||
ld %f4,32(%r14)
|
||||
ld %f5,40(%r14)
|
||||
ld %f6,48(%r14)
|
||||
ld %f7,56(%r14)
|
||||
ld %f8,64(%r14)
|
||||
ld %f9,72(%r14)
|
||||
ld %f10,80(%r14)
|
||||
ld %f11,88(%r14)
|
||||
ld %f12,96(%r14)
|
||||
ld %f13,104(%r14)
|
||||
ld %f14,112(%r14)
|
||||
ld %f15,120(%r14)
|
||||
j 1f
|
||||
0: VLM %v0,%v15,0,%r11
|
||||
VLM %v16,%v31,256,%r11
|
||||
1: lghi %r14,__LC_CPU_TIMER_SAVE_AREA
|
||||
lghi %r14,__LC_CPU_TIMER_SAVE_AREA
|
||||
mvc __LC_MCCK_ENTER_TIMER(8),0(%r14)
|
||||
TSTMSK __LC_MCCK_CODE,MCCK_CODE_CPU_TIMER_VALID
|
||||
jo 3f
|
||||
|
@ -189,12 +189,16 @@ void noinstr s390_handle_mcck(void)
|
||||
* returns 0 if all required registers are available
|
||||
* returns 1 otherwise
|
||||
*/
|
||||
static int notrace s390_check_registers(union mci mci, int umode)
|
||||
static int notrace s390_validate_registers(union mci mci, int umode)
|
||||
{
|
||||
struct mcesa *mcesa;
|
||||
void *fpt_save_area;
|
||||
union ctlreg2 cr2;
|
||||
int kill_task;
|
||||
u64 zero;
|
||||
|
||||
kill_task = 0;
|
||||
zero = 0;
|
||||
|
||||
if (!mci.gr) {
|
||||
/*
|
||||
@ -217,35 +221,89 @@ static int notrace s390_check_registers(union mci mci, int umode)
|
||||
if (!test_cpu_flag(CIF_FPU))
|
||||
kill_task = 1;
|
||||
}
|
||||
fpt_save_area = &S390_lowcore.floating_pt_save_area;
|
||||
if (!mci.fc) {
|
||||
/*
|
||||
* Floating point control register can't be restored.
|
||||
* 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.
|
||||
* registers loaded it is terminated. Otherwise the
|
||||
* FPC is just validated.
|
||||
*/
|
||||
if (S390_lowcore.fpu_flags & KERNEL_FPC)
|
||||
s390_handle_damage();
|
||||
asm volatile(
|
||||
" lfpc %0\n"
|
||||
:
|
||||
: "Q" (zero));
|
||||
if (!test_cpu_flag(CIF_FPU))
|
||||
kill_task = 1;
|
||||
} else {
|
||||
asm volatile(
|
||||
" lfpc %0\n"
|
||||
:
|
||||
: "Q" (S390_lowcore.fpt_creg_save_area));
|
||||
}
|
||||
|
||||
if (MACHINE_HAS_VX) {
|
||||
mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK);
|
||||
if (!MACHINE_HAS_VX) {
|
||||
/* Validate floating point registers */
|
||||
asm volatile(
|
||||
" ld 0,0(%0)\n"
|
||||
" ld 1,8(%0)\n"
|
||||
" ld 2,16(%0)\n"
|
||||
" ld 3,24(%0)\n"
|
||||
" ld 4,32(%0)\n"
|
||||
" ld 5,40(%0)\n"
|
||||
" ld 6,48(%0)\n"
|
||||
" ld 7,56(%0)\n"
|
||||
" ld 8,64(%0)\n"
|
||||
" ld 9,72(%0)\n"
|
||||
" ld 10,80(%0)\n"
|
||||
" ld 11,88(%0)\n"
|
||||
" ld 12,96(%0)\n"
|
||||
" ld 13,104(%0)\n"
|
||||
" ld 14,112(%0)\n"
|
||||
" ld 15,120(%0)\n"
|
||||
:
|
||||
: "a" (fpt_save_area)
|
||||
: "memory");
|
||||
} else {
|
||||
/* Validate vector registers */
|
||||
union ctlreg0 cr0;
|
||||
|
||||
if (!mci.vr) {
|
||||
/*
|
||||
* 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.
|
||||
* loaded it is terminated. Otherwise just validate
|
||||
* the registers.
|
||||
*/
|
||||
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;
|
||||
__ctl_load(cr0.val, 0, 0);
|
||||
asm volatile(
|
||||
" la 1,%0\n"
|
||||
" .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
|
||||
" .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
|
||||
:
|
||||
: "Q" (*(struct vx_array *)mcesa->vector_save_area)
|
||||
: "1");
|
||||
__ctl_load(S390_lowcore.cregs_save_area[0], 0, 0);
|
||||
}
|
||||
/* Check if access registers are valid */
|
||||
/* Validate access registers */
|
||||
asm volatile(
|
||||
" lam 0,15,0(%0)\n"
|
||||
:
|
||||
: "a" (&S390_lowcore.access_regs_save_area)
|
||||
: "memory");
|
||||
if (!mci.ar) {
|
||||
/*
|
||||
* Access registers have unknown contents.
|
||||
@ -253,7 +311,7 @@ static int notrace s390_check_registers(union mci mci, int umode)
|
||||
*/
|
||||
kill_task = 1;
|
||||
}
|
||||
/* Check guarded storage registers */
|
||||
/* Validate guarded storage registers */
|
||||
cr2.val = S390_lowcore.cregs_save_area[2];
|
||||
if (cr2.gse) {
|
||||
if (!mci.gs) {
|
||||
@ -263,15 +321,26 @@ static int notrace s390_check_registers(union mci mci, int umode)
|
||||
* It has to be terminated.
|
||||
*/
|
||||
kill_task = 1;
|
||||
} else {
|
||||
load_gs_cb((struct gs_cb *)mcesa->guarded_storage_save_area);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The getcpu vdso syscall reads CPU number from the programmable
|
||||
* field of the TOD clock. Disregard the TOD programmable register
|
||||
* validity bit and load the CPU number into the TOD programmable
|
||||
* field unconditionally.
|
||||
*/
|
||||
set_tod_programmable_field(raw_smp_processor_id());
|
||||
/* Validate clock comparator register */
|
||||
set_clock_comparator(S390_lowcore.clock_comparator);
|
||||
|
||||
if (!mci.ms || !mci.pm || !mci.ia)
|
||||
kill_task = 1;
|
||||
|
||||
return kill_task;
|
||||
}
|
||||
NOKPROBE_SYMBOL(s390_check_registers);
|
||||
NOKPROBE_SYMBOL(s390_validate_registers);
|
||||
|
||||
/*
|
||||
* Backup the guest's machine check info to its description block
|
||||
@ -369,7 +438,7 @@ int notrace s390_do_machine_check(struct pt_regs *regs)
|
||||
s390_handle_damage();
|
||||
}
|
||||
}
|
||||
if (s390_check_registers(mci, user_mode(regs))) {
|
||||
if (s390_validate_registers(mci, user_mode(regs))) {
|
||||
/*
|
||||
* Couldn't restore all register contents for the
|
||||
* user space process -> mark task for termination.
|
||||
|
Loading…
Reference in New Issue
Block a user