Re: [PATCH v4 RESEND] MIPS: tlbex: Avoid access invalid address when pmd is modifying

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, Rui Wang,

On Fri, Feb 12, 2021 at 4:21 PM Rui Wang <wangrui@xxxxxxxxxxx> wrote:
>
> From: wangrui <wangrui@xxxxxxxxxxx>
>
> When user-space program accessing a virtual address and falls into TLB invalid
> exception handling. at almost the same time, if the pmd which that contains this
> virtual address is hit by THP scanning, and then a invalid address access may
> occurs in the tlb handler:
>
>    CPU 0: (userspace)                 | CPU 1: (khugepaged)
> 1:                                    | scan hit: set pmde to invalid_pmd_table
>                                       |  (by pmd_clear)
> 2: handle_tlbl(tlb invalid):          |
>     load pmde for huge page testing,  |
>     pmde doesn't contains _PAGE_HUGE  |
>     bit                               |
> 3:                                    | collapsed: set pmde to huge page format
> 4: handle_tlbl(normal page case):     |
>     load pmde again as base address,  |
>     pmde doesn't contains an address, |
>     access invalid address            |
>
> This patch avoids the inconsistency of two memory loads by reusing the result
> of one load.
>
You can CC stable@xxxxxxxxxxxxxxx here.

> Signed-off-by: wangrui <wangrui@xxxxxxxxxxx>
> ---
>  arch/mips/mm/tlbex.c | 27 ++++++++++++---------------
>  1 file changed, 12 insertions(+), 15 deletions(-)
>
> diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
> index a7521b8f7658..2295f1e2db81 100644
> --- a/arch/mips/mm/tlbex.c
> +++ b/arch/mips/mm/tlbex.c
> @@ -721,13 +721,12 @@ static void build_huge_tlb_write_entry(u32 **p, struct uasm_label **l,
>   */
>  static void
>  build_is_huge_pte(u32 **p, struct uasm_reloc **r, unsigned int tmp,
> -                 unsigned int pmd, int lid)
> +                 unsigned int pmde, int lid)
>  {
> -       UASM_i_LW(p, tmp, 0, pmd);
>         if (use_bbit_insns()) {
> -               uasm_il_bbit1(p, r, tmp, ilog2(_PAGE_HUGE), lid);
> +               uasm_il_bbit1(p, r, pmde, ilog2(_PAGE_HUGE), lid);
>         } else {
> -               uasm_i_andi(p, tmp, tmp, _PAGE_HUGE);
> +               uasm_i_andi(p, tmp, pmde, _PAGE_HUGE);
>                 uasm_il_bnez(p, r, tmp, lid);
>         }
>  }
> @@ -1103,7 +1102,6 @@ EXPORT_SYMBOL_GPL(build_update_entries);
>  struct mips_huge_tlb_info {
>         int huge_pte;
>         int restore_scratch;
> -       bool need_reload_pte;
>  };
>
>  static struct mips_huge_tlb_info
> @@ -1118,7 +1116,6 @@ build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
>
>         rv.huge_pte = scratch;
>         rv.restore_scratch = 0;
> -       rv.need_reload_pte = false;
>
>         if (check_for_high_segbits) {
>                 UASM_i_MFC0(p, tmp, C0_BADVADDR);
> @@ -1323,7 +1320,6 @@ static void build_r4000_tlb_refill_handler(void)
>         } else {
>                 htlb_info.huge_pte = K0;
>                 htlb_info.restore_scratch = 0;
> -               htlb_info.need_reload_pte = true;
>                 vmalloc_mode = refill_noscratch;
>                 /*
>                  * create the plain linear handler
> @@ -1348,11 +1344,14 @@ static void build_r4000_tlb_refill_handler(void)
>                 build_get_pgde32(&p, K0, K1); /* get pgd in K1 */
>  #endif
>
> +               UASM_i_LW(&p, K0, 0, K1); /* get pmd entry in K0 */
>  #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
> -               build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update);
> +               build_is_huge_pte(&p, &r, K1, K0, label_tlb_huge_update);
>  #endif
>
> -               build_get_ptep(&p, K0, K1);
You remove the build_get_ptep here, but this may be wrong for NEVADA.

Huacai
> +               GET_CONTEXT(&p, K1); /* get context reg */
> +               build_adjust_context(&p, K1);
> +               UASM_i_ADDU(&p, K1, K0, K1); /* add in offset */
>                 build_update_entries(&p, K0, K1);
>                 build_tlb_write_entry(&p, &l, &r, tlb_random);
>                 uasm_l_leave(&l, p);
> @@ -1360,8 +1359,6 @@ static void build_r4000_tlb_refill_handler(void)
>         }
>  #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
>         uasm_l_tlb_huge_update(&l, p);
> -       if (htlb_info.need_reload_pte)
> -               UASM_i_LW(&p, htlb_info.huge_pte, 0, K1);
>         build_huge_update_entries(&p, htlb_info.huge_pte, K1);
>         build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random,
>                                    htlb_info.restore_scratch);
> @@ -2059,20 +2056,20 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
>         build_get_pgde32(p, wr.r1, wr.r2); /* get pgd in ptr */
>  #endif
>
> +       UASM_i_LW(p, wr.r3, 0, wr.r2); /* get pmd entry in wr.r3 */
>  #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
>         /*
> -        * For huge tlb entries, pmd doesn't contain an address but
> +        * For huge tlb entries, pmde doesn't contain an address but
>          * instead contains the tlb pte. Check the PAGE_HUGE bit and
>          * see if we need to jump to huge tlb processing.
>          */
> -       build_is_huge_pte(p, r, wr.r1, wr.r2, label_tlb_huge_update);
> +       build_is_huge_pte(p, r, wr.r1, wr.r3, label_tlb_huge_update);
>  #endif
>
>         UASM_i_MFC0(p, wr.r1, C0_BADVADDR);
> -       UASM_i_LW(p, wr.r2, 0, wr.r2);
>         UASM_i_SRL(p, wr.r1, wr.r1, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
>         uasm_i_andi(p, wr.r1, wr.r1, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
> -       UASM_i_ADDU(p, wr.r2, wr.r2, wr.r1);
> +       UASM_i_ADDU(p, wr.r2, wr.r3, wr.r1);
>
>  #ifdef CONFIG_SMP
>         uasm_l_smp_pgtable_change(l, *p);
> --
> 2.30.1
>



[Index of Archives]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux