]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
s390/mm: Fix __ptep_rdp() inline assembly
authorHeiko Carstens <hca@linux.ibm.com>
Thu, 13 Nov 2025 12:21:47 +0000 (13:21 +0100)
committerHeiko Carstens <hca@linux.ibm.com>
Fri, 14 Nov 2025 14:58:20 +0000 (15:58 +0100)
When a zero ASCE is passed to the __ptep_rdp() inline assembly, the
generated instruction should have the R3 field of the instruction set to
zero. However the inline assembly is written incorrectly: for such cases a
zero is loaded into a register allocated by the compiler and this register
is then used by the instruction.

This means that selected TLB entries may not be flushed since the specified
ASCE does not match the one which was used when the selected TLB entries
were created.

Fix this by removing the asce and opt parameters of __ptep_rdp(), since
all callers always pass zero, and use a hard-coded register zero for
the R3 field.

Fixes: 0807b856521f ("s390/mm: add support for RDP (Reset DAT-Protection)")
Cc: stable@vger.kernel.org
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/pgtable.h
arch/s390/mm/pgtable.c

index b7100c6a405449bb292b22dc7194e9c7061f81c9..6663f1619abbae03dc9f4758c3f070c9f773755c 100644 (file)
@@ -1154,17 +1154,15 @@ static inline pte_t pte_mkhuge(pte_t pte)
 #define IPTE_NODAT     0x400
 #define IPTE_GUEST_ASCE        0x800
 
-static __always_inline void __ptep_rdp(unsigned long addr, pte_t *ptep,
-                                      unsigned long opt, unsigned long asce,
-                                      int local)
+static __always_inline void __ptep_rdp(unsigned long addr, pte_t *ptep, int local)
 {
        unsigned long pto;
 
        pto = __pa(ptep) & ~(PTRS_PER_PTE * sizeof(pte_t) - 1);
-       asm volatile(".insn rrf,0xb98b0000,%[r1],%[r2],%[asce],%[m4]"
+       asm volatile(".insn     rrf,0xb98b0000,%[r1],%[r2],%%r0,%[m4]"
                     : "+m" (*ptep)
-                    : [r1] "a" (pto), [r2] "a" ((addr & PAGE_MASK) | opt),
-                      [asce] "a" (asce), [m4] "i" (local));
+                    : [r1] "a" (pto), [r2] "a" (addr & PAGE_MASK),
+                      [m4] "i" (local));
 }
 
 static __always_inline void __ptep_ipte(unsigned long address, pte_t *ptep,
@@ -1348,7 +1346,7 @@ static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma,
         * A local RDP can be used to do the flush.
         */
        if (cpu_has_rdp() && !(pte_val(*ptep) & _PAGE_PROTECT))
-               __ptep_rdp(address, ptep, 0, 0, 1);
+               __ptep_rdp(address, ptep, 1);
 }
 #define flush_tlb_fix_spurious_fault flush_tlb_fix_spurious_fault
 
index 0fde20bbc50bf3801efacb55e26cee8a87e55fb5..05974304d6222e2f261da1d9a3438beecb029c16 100644 (file)
@@ -274,9 +274,9 @@ void ptep_reset_dat_prot(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
        preempt_disable();
        atomic_inc(&mm->context.flush_count);
        if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
-               __ptep_rdp(addr, ptep, 0, 0, 1);
+               __ptep_rdp(addr, ptep, 1);
        else
-               __ptep_rdp(addr, ptep, 0, 0, 0);
+               __ptep_rdp(addr, ptep, 0);
        /*
         * PTE is not invalidated by RDP, only _PAGE_PROTECT is cleared. That
         * means it is still valid and active, and must not be changed according