mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
s390/mm: Fix __ptep_rdp() inline assembly
[ Upstream commit31475b8811] 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:0807b85652("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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
23ba534d73
commit
b514ad872a
@@ -1109,17 +1109,15 @@ static inline pte_t pte_mkhuge(pte_t pte)
|
|||||||
#define IPTE_NODAT 0x400
|
#define IPTE_NODAT 0x400
|
||||||
#define IPTE_GUEST_ASCE 0x800
|
#define IPTE_GUEST_ASCE 0x800
|
||||||
|
|
||||||
static __always_inline void __ptep_rdp(unsigned long addr, pte_t *ptep,
|
static __always_inline void __ptep_rdp(unsigned long addr, pte_t *ptep, int local)
|
||||||
unsigned long opt, unsigned long asce,
|
|
||||||
int local)
|
|
||||||
{
|
{
|
||||||
unsigned long pto;
|
unsigned long pto;
|
||||||
|
|
||||||
pto = __pa(ptep) & ~(PTRS_PER_PTE * sizeof(pte_t) - 1);
|
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)
|
: "+m" (*ptep)
|
||||||
: [r1] "a" (pto), [r2] "a" ((addr & PAGE_MASK) | opt),
|
: [r1] "a" (pto), [r2] "a" (addr & PAGE_MASK),
|
||||||
[asce] "a" (asce), [m4] "i" (local));
|
[m4] "i" (local));
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline void __ptep_ipte(unsigned long address, pte_t *ptep,
|
static __always_inline void __ptep_ipte(unsigned long address, pte_t *ptep,
|
||||||
@@ -1303,7 +1301,7 @@ static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma,
|
|||||||
* A local RDP can be used to do the flush.
|
* A local RDP can be used to do the flush.
|
||||||
*/
|
*/
|
||||||
if (MACHINE_HAS_RDP && !(pte_val(*ptep) & _PAGE_PROTECT))
|
if (MACHINE_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
|
#define flush_tlb_fix_spurious_fault flush_tlb_fix_spurious_fault
|
||||||
|
|
||||||
|
|||||||
@@ -293,9 +293,9 @@ void ptep_reset_dat_prot(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
|
|||||||
preempt_disable();
|
preempt_disable();
|
||||||
atomic_inc(&mm->context.flush_count);
|
atomic_inc(&mm->context.flush_count);
|
||||||
if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
|
if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
|
||||||
__ptep_rdp(addr, ptep, 0, 0, 1);
|
__ptep_rdp(addr, ptep, 1);
|
||||||
else
|
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
|
* 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
|
* means it is still valid and active, and must not be changed according
|
||||||
|
|||||||
Reference in New Issue
Block a user