Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: tlbex: Properly fix HUGE TLB Refill exception handler

In commit 8393c524a25609 (MIPS: tlbex: Fix a missing statement for
HUGETLB), the TLB Refill handler was fixed so that non-OCTEON targets
would work properly with huge pages. The change was incorrect in that
it broke the OCTEON case.

The problem is shown here:

xxx0: df7a0000 ld k0,0(k1)
.
.
.
xxxc0: df610000 ld at,0(k1)
xxxc4: 335a0ff0 andi k0,k0,0xff0
xxxc8: e825ffcd bbit1 at,0x5,0x0
xxxcc: 003ad82d daddu k1,at,k0
.
.
.

In the non-octeon case there is a destructive test for the huge PTE
bit, and then at 0, $k0 is reloaded (that is what the 8393c524a25609
patch added).

In the octeon case, we modify k1 in the branch delay slot, but we
never need k0 again, so the new load is not needed, but since k1 is
modified, if we do the load, we load from a garbage location and then
get a nested TLB Refill, which is seen in userspace as either SIGBUS
or SIGSEGV (depending on the garbage).

The real fix is to only do this reloading if it is needed, and never
where it is harmful.

Signed-off-by: David Daney <david.daney@cavium.com>
Cc: Huacai Chen <chenhc@lemote.com>
Cc: Fuxin Zhang <zhangfx@lemote.com>
Cc: Zhangjin Wu <wuzhangjin@gmail.com>
Cc: stable@vger.kernel.org
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/8151/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

David Daney and committed by
Ralf Baechle
9e0f162a aa08ed55

+5 -1
+5 -1
arch/mips/mm/tlbex.c
··· 1062 1062 struct mips_huge_tlb_info { 1063 1063 int huge_pte; 1064 1064 int restore_scratch; 1065 + bool need_reload_pte; 1065 1066 }; 1066 1067 1067 1068 static struct mips_huge_tlb_info ··· 1077 1076 1078 1077 rv.huge_pte = scratch; 1079 1078 rv.restore_scratch = 0; 1079 + rv.need_reload_pte = false; 1080 1080 1081 1081 if (check_for_high_segbits) { 1082 1082 UASM_i_MFC0(p, tmp, C0_BADVADDR); ··· 1266 1264 } else { 1267 1265 htlb_info.huge_pte = K0; 1268 1266 htlb_info.restore_scratch = 0; 1267 + htlb_info.need_reload_pte = true; 1269 1268 vmalloc_mode = refill_noscratch; 1270 1269 /* 1271 1270 * create the plain linear handler ··· 1303 1300 } 1304 1301 #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT 1305 1302 uasm_l_tlb_huge_update(&l, p); 1306 - UASM_i_LW(&p, K0, 0, K1); 1303 + if (htlb_info.need_reload_pte) 1304 + UASM_i_LW(&p, htlb_info.huge_pte, 0, K1); 1307 1305 build_huge_update_entries(&p, htlb_info.huge_pte, K1); 1308 1306 build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random, 1309 1307 htlb_info.restore_scratch);