Skip to content

Commit 70c7c76

Browse files
paulburtonsmb49
authored andcommitted
MIPS: tlbex: Fix build_restore_pagemask KScratch restore
BugLink: https://bugs.launchpad.net/bugs/1850456 commit b42aa3f upstream. build_restore_pagemask() will restore the value of register $1/$at when its restore_scratch argument is non-zero, and aims to do so by filling a branch delay slot. Commit 0b24cae ("MIPS: Add missing EHB in mtc0 -> mfc0 sequence.") added an EHB instruction (Execution Hazard Barrier) prior to restoring $1 from a KScratch register, in order to resolve a hazard that can result in stale values of the KScratch register being observed. In particular, P-class CPUs from MIPS with out of order execution pipelines such as the P5600 & P6600 are affected. Unfortunately this EHB instruction was inserted in the branch delay slot causing the MFC0 instruction which performs the restoration to no longer execute along with the branch. The result is that the $1 register isn't actually restored, ie. the TLB refill exception handler clobbers it - which is exactly the problem the EHB is meant to avoid for the P-class CPUs. Similarly build_get_pgd_vmalloc() will restore the value of $1/$at when its mode argument equals refill_scratch, and suffers from the same problem. Fix this by in both cases moving the EHB earlier in the emitted code. There's no reason it needs to immediately precede the MFC0 - it simply needs to be between the MTC0 & MFC0. This bug only affects Cavium Octeon systems which use build_fast_tlb_refill_handler(). Signed-off-by: Paul Burton <[email protected]> Fixes: 0b24cae ("MIPS: Add missing EHB in mtc0 -> mfc0 sequence.") Cc: Dmitry Korotin <[email protected]> Cc: [email protected] # v3.15+ Cc: [email protected] Cc: [email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Connor Kuehl <[email protected]> Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
1 parent c648b49 commit 70c7c76

File tree

1 file changed

+15
-8
lines changed

1 file changed

+15
-8
lines changed

arch/mips/mm/tlbex.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,13 @@ static void build_restore_pagemask(u32 **p, struct uasm_reloc **r,
655655
int restore_scratch)
656656
{
657657
if (restore_scratch) {
658+
/*
659+
* Ensure the MFC0 below observes the value written to the
660+
* KScratch register by the prior MTC0.
661+
*/
662+
if (scratch_reg >= 0)
663+
uasm_i_ehb(p);
664+
658665
/* Reset default page size */
659666
if (PM_DEFAULT_MASK >> 16) {
660667
uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16);
@@ -669,12 +676,10 @@ static void build_restore_pagemask(u32 **p, struct uasm_reloc **r,
669676
uasm_i_mtc0(p, 0, C0_PAGEMASK);
670677
uasm_il_b(p, r, lid);
671678
}
672-
if (scratch_reg >= 0) {
673-
uasm_i_ehb(p);
679+
if (scratch_reg >= 0)
674680
UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
675-
} else {
681+
else
676682
UASM_i_LW(p, 1, scratchpad_offset(0), 0);
677-
}
678683
} else {
679684
/* Reset default page size */
680685
if (PM_DEFAULT_MASK >> 16) {
@@ -923,6 +928,10 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
923928
}
924929
if (mode != not_refill && check_for_high_segbits) {
925930
uasm_l_large_segbits_fault(l, *p);
931+
932+
if (mode == refill_scratch && scratch_reg >= 0)
933+
uasm_i_ehb(p);
934+
926935
/*
927936
* We get here if we are an xsseg address, or if we are
928937
* an xuseg address above (PGDIR_SHIFT+PGDIR_BITS) boundary.
@@ -941,12 +950,10 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
941950
uasm_i_jr(p, ptr);
942951

943952
if (mode == refill_scratch) {
944-
if (scratch_reg >= 0) {
945-
uasm_i_ehb(p);
953+
if (scratch_reg >= 0)
946954
UASM_i_MFC0(p, 1, c0_kscratch(), scratch_reg);
947-
} else {
955+
else
948956
UASM_i_LW(p, 1, scratchpad_offset(0), 0);
949-
}
950957
} else {
951958
uasm_i_nop(p);
952959
}

0 commit comments

Comments
 (0)