]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
s390/entry: compare gmap asce to determine guest/host fault
authorSven Schnelle <svens@linux.ibm.com>
Wed, 13 Mar 2024 08:51:22 +0000 (09:51 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Sun, 17 Mar 2024 18:08:50 +0000 (19:08 +0100)
With the current implementation, there are some cornercases where
a host fault would be treated as a guest fault, for example
when the sie instruction causes a program check. Therefore store
the gmap asce in ptregs, and use that to compare the primary asce
from the fault instead of matching instruction addresses.

Suggested-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/ptrace.h
arch/s390/kernel/entry.S
arch/s390/mm/fault.c

index 788bc4467445c9da9471cf5037bcf2887f1303e8..2ad9324f633876d84d22025419256aa0ba251dc5 100644 (file)
 #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)
index a0543db0bcae82f1a6d248c9d0d8804b14ae3445..787394978bc0f86400ce30214c2e1b8eb3e82675 100644 (file)
@@ -119,8 +119,8 @@ _LPP_OFFSET = __LC_LPP
        .endm
 
 #if IS_ENABLED(CONFIG_KVM)
-       .macro SIEEXIT
-       lg      %r9,__SF_SIE_CONTROL(%r15)      # get control block pointer
+       .macro SIEEXIT sie_control
+       lg      %r9,\sie_control                # get control block pointer
        ni      __SIE_PROG0C+3(%r9),0xfe        # no longer in SIE
        lctlg   %c1,%c1,__LC_KERNEL_ASCE        # load primary asce
        ni      __LC_CPU_FLAGS+7,255-_CIF_SIE
@@ -316,21 +316,13 @@ SYM_CODE_START(pgm_check_handler)
        stpt    __LC_SYS_ENTER_TIMER
        BPOFF
        stmg    %r8,%r15,__LC_SAVE_AREA_SYNC
-       lghi    %r10,0
+       lgr     %r10,%r15
        lmg     %r8,%r9,__LC_PGM_OLD_PSW
        tmhh    %r8,0x0001              # coming from user space?
        jno     .Lpgm_skip_asce
        lctlg   %c1,%c1,__LC_KERNEL_ASCE
        j       3f                      # -> fault in user space
 .Lpgm_skip_asce:
-#if IS_ENABLED(CONFIG_KVM)
-       # cleanup critical section for program checks in __sie64a
-       TSTMSK  __LC_CPU_FLAGS,_CIF_SIE
-       jz      1f
-       BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
-       SIEEXIT
-       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,0x80     # check for per exception
@@ -341,13 +333,20 @@ SYM_CODE_START(pgm_check_handler)
        CHECK_VMAP_STACK __LC_SAVE_AREA_SYNC,4f
 3:     lg      %r15,__LC_KERNEL_STACK
 4:     la      %r11,STACK_FRAME_OVERHEAD(%r15)
-       stg     %r10,__PT_FLAGS(%r11)
+       xc      __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
        xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
        stmg    %r0,%r7,__PT_R0(%r11)
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        mvc     __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK
-       stmg    %r8,%r9,__PT_PSW(%r11)
-
+       stctg   %c1,%c1,__PT_CR1(%r11)
+#if IS_ENABLED(CONFIG_KVM)
+       lg      %r12,__LC_GMAP
+       clc     __GMAP_ASCE(8,%r12), __PT_CR1(%r11)
+       jne     5f
+       BPENTER __SF_SIE_FLAGS(%r10),_TIF_ISOLATE_BP_GUEST
+       SIEEXIT __SF_SIE_CONTROL(%r10)
+#endif
+5:     stmg    %r8,%r9,__PT_PSW(%r11)
        # clear user controlled registers to prevent speculative use
        xgr     %r0,%r0
        xgr     %r1,%r1
@@ -399,7 +398,7 @@ SYM_CODE_START(\name)
        TSTMSK  __LC_CPU_FLAGS,_CIF_SIE
        jz      0f
        BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
-       SIEEXIT
+       SIEEXIT __SF_SIE_CONTROL(%r15)
 #endif
 0:     CHECK_STACK __LC_SAVE_AREA_ASYNC
        aghi    %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
@@ -507,7 +506,7 @@ SYM_CODE_START(mcck_int_handler)
        clgrjhe %r9,%r14, 4f
        oi      __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
 4:     BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST
-       SIEEXIT
+       SIEEXIT __SF_SIE_CONTROL(%r15)
 #endif
 .Lmcck_user:
        lg      %r15,__LC_MCCK_STACK
index ac4c78546d973713859079520552148ae7b2c0b7..c421dd44ffbe0346ab31028d433e5b3b7a2df626 100644 (file)
@@ -67,13 +67,15 @@ 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;
-               if (test_pt_regs_flag(regs, PIF_GUEST_FAULT))
+               gmap = (struct gmap *)S390_lowcore.gmap;
+               if (regs->cr1 == gmap->asce)
                        return GMAP_FAULT;
                return KERNEL_FAULT;
        }