Commit f96cb0d6 authored by Claudio Imbrenda's avatar Claudio Imbrenda Committed by Heiko Carstens
Browse files

s390/entry: Remove __GMAP_ASCE and use _PIF_GUEST_FAULT again



Now that the guest ASCE is passed as a parameter to __sie64a(),
_PIF_GUEST_FAULT can be used again to determine whether the fault was a
guest or host fault.

Since the guest ASCE will not be taken from the gmap pointer in lowcore
anymore, __GMAP_ASCE can be removed. For the same reason the guest
ASCE needs now to be saved into the cr1 save area unconditionally.

Signed-off-by: default avatarClaudio Imbrenda <imbrenda@linux.ibm.com>
Acked-by: default avatarJanosch Frank <frankja@linux.ibm.com>
Reviewed-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Link: https://lore.kernel.org/r/20241022120601.167009-2-imbrenda@linux.ibm.com


Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent f4d5e64c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -14,11 +14,13 @@
#define PIF_SYSCALL			0	/* inside a system call */
#define PIF_EXECVE_PGSTE_RESTART	1	/* restart execve for PGSTE binaries */
#define PIF_SYSCALL_RET_SET		2	/* return value was set via ptrace */
#define PIF_GUEST_FAULT			3	/* indicates program check in sie64a */
#define PIF_FTRACE_FULL_REGS		4	/* all register contents valid (ftrace) */

#define _PIF_SYSCALL			BIT(PIF_SYSCALL)
#define _PIF_EXECVE_PGSTE_RESTART	BIT(PIF_EXECVE_PGSTE_RESTART)
#define _PIF_SYSCALL_RET_SET		BIT(PIF_SYSCALL_RET_SET)
#define _PIF_GUEST_FAULT		BIT(PIF_GUEST_FAULT)
#define _PIF_FTRACE_FULL_REGS		BIT(PIF_FTRACE_FULL_REGS)

#define PSW32_MASK_PER		_AC(0x40000000, UL)
+0 −2
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@
#include <linux/purgatory.h>
#include <linux/pgtable.h>
#include <linux/ftrace.h>
#include <asm/gmap.h>
#include <asm/stacktrace.h>

int main(void)
@@ -161,7 +160,6 @@ int main(void)
	OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb);
	BLANK();
	/* gmap/sie offsets */
	OFFSET(__GMAP_ASCE, gmap, asce);
	OFFSET(__SIE_PROG0C, kvm_s390_sie_block, prog0c);
	OFFSET(__SIE_PROG20, kvm_s390_sie_block, prog20);
	/* kexec_sha_region */
+14 −12
Original line number Diff line number Diff line
@@ -327,13 +327,23 @@ SYM_CODE_START(pgm_check_handler)
	GET_LC	%r13
	stpt	__LC_SYS_ENTER_TIMER(%r13)
	BPOFF
	lgr	%r10,%r15
	lmg	%r8,%r9,__LC_PGM_OLD_PSW(%r13)
	xgr	%r10,%r10
	xgr	%r12,%r12
	tmhh	%r8,0x0001		# coming from user space?
	jno	.Lpgm_skip_asce
	lctlg	%c1,%c1,__LC_KERNEL_ASCE(%r13)
	j	3f			# -> fault in user space
.Lpgm_skip_asce:
#if IS_ENABLED(CONFIG_KVM)
	lg	%r11,__LC_CURRENT(%r13)
	tm	__TI_sie(%r11),0xff
	jz	1f
	BPENTER	__SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
	SIEEXIT __SF_SIE_CONTROL(%r15),%r13
	lg	%r12,__SF_SIE_GUEST_ASCE(%r15)
	lghi	%r10,_PIF_GUEST_FAULT
#endif
1:	tmhh	%r8,0x4000		# PER bit set in old PSW ?
	jnz	2f			# -> enabled, can't be a double fault
	tm	__LC_PGM_ILC+3(%r13),0x80	# check for per exception
@@ -344,21 +354,13 @@ SYM_CODE_START(pgm_check_handler)
	CHECK_VMAP_STACK __LC_SAVE_AREA,%r13,4f
3:	lg	%r15,__LC_KERNEL_STACK(%r13)
4:	la	%r11,STACK_FRAME_OVERHEAD(%r15)
	xc	__PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
	stg	%r10,__PT_FLAGS(%r11)
	stg	%r12,__PT_CR1(%r11)
	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
	stmg	%r0,%r7,__PT_R0(%r11)
	mvc	__PT_R8(64,%r11),__LC_SAVE_AREA(%r13)
	mvc	__PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK(%r13)
	stctg	%c1,%c1,__PT_CR1(%r11)
#if IS_ENABLED(CONFIG_KVM)
	ltg	%r12,__LC_GMAP(%r13)
	jz	5f
	clc	__GMAP_ASCE(8,%r12), __PT_CR1(%r11)
	jne	5f
	BPENTER	__SF_SIE_FLAGS(%r10),_TIF_ISOLATE_BP_GUEST
	SIEEXIT __SF_SIE_CONTROL(%r10),%r13
#endif
5:	stmg	%r8,%r9,__PT_PSW(%r11)
	stmg	%r8,%r9,__PT_PSW(%r11)
	# clear user controlled registers to prevent speculative use
	xgr	%r0,%r0
	xgr	%r1,%r1
+2 −4
Original line number Diff line number Diff line
@@ -68,15 +68,13 @@ early_initcall(fault_init);
static enum fault_type get_fault_type(struct pt_regs *regs)
{
	union teid teid = { .val = regs->int_parm_long };
	struct gmap *gmap;

	if (likely(teid.as == PSW_BITS_AS_PRIMARY)) {
		if (user_mode(regs))
			return USER_FAULT;
		if (!IS_ENABLED(CONFIG_PGSTE))
			return KERNEL_FAULT;
		gmap = (struct gmap *)get_lowcore()->gmap;
		if (gmap && gmap->asce == regs->cr1)
		if (test_pt_regs_flag(regs, PIF_GUEST_FAULT))
			return GMAP_FAULT;
		return KERNEL_FAULT;
	}
@@ -187,7 +185,7 @@ static void dump_fault_info(struct pt_regs *regs)
		pr_cont("user ");
		break;
	case GMAP_FAULT:
		asce = ((struct gmap *)get_lowcore()->gmap)->asce;
		asce = regs->cr1;
		pr_cont("gmap ");
		break;
	case KERNEL_FAULT: