All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andre Przywara <andre.przywara@arm.com>
To: Alexandru Elisei <alexandru.elisei@arm.com>
Cc: kvm@vger.kernel.org, pbonzini@redhat.com, drjones@redhat.com,
	maz@kernel.org, vladimir.murzin@arm.com, mark.rutland@arm.com
Subject: Re: [kvm-unit-tests PATCH v3 04/18] lib: arm/arm64: Use WRITE_ONCE to update the translation tables
Date: Thu, 2 Jan 2020 18:06:22 +0000	[thread overview]
Message-ID: <20200102180622.383b7395@donnerap.cambridge.arm.com> (raw)
In-Reply-To: <1577808589-31892-5-git-send-email-alexandru.elisei@arm.com>

On Tue, 31 Dec 2019 16:09:35 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi,

> Use WRITE_ONCE to prevent store tearing when updating an entry in the
> translation tables. Without WRITE_ONCE, the compiler, even though it is
> unlikely, can emit several stores when changing the table, and we might
> end up with bogus TLB entries.
> 
> It's worth noting that the existing code is mostly fine without any
> changes because the translation tables are updated in one of the
> following situations:
> 
> - When the tables are being created with the MMU off, which means no TLB
>   caching is being performed.
> 
> - When new page table entries are added as a result of vmalloc'ing a
>   stack for a secondary CPU, which doesn't happen very often.
> 
> - When clearing the PTE_USER bit for the cache test, and store tearing
>   has no effect on the table walker because there are no intermediate
>   values between bit values 0 and 1. We still use WRITE_ONCE in this case
>   for consistency.
> 
> However, the functions are global and there is nothing preventing someone
> from writing a test that uses them in a different scenario. Let's make
> sure that when that happens, there will be no breakage once in a blue
> moon.

I haven't checked whether there are more places where this would be needed, but it seems the right thing to do, also the changes below look valid.
 
> Reported-by: Mark Rutland <mark.rutland@arm.com>
> Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre.

> ---
>  lib/arm/asm/pgtable.h   | 12 ++++++++----
>  lib/arm64/asm/pgtable.h |  7 +++++--
>  lib/arm/mmu.c           | 19 +++++++++++++------
>  3 files changed, 26 insertions(+), 12 deletions(-)
> 
> diff --git a/lib/arm/asm/pgtable.h b/lib/arm/asm/pgtable.h
> index 241dff69b38a..794514b8c927 100644
> --- a/lib/arm/asm/pgtable.h
> +++ b/lib/arm/asm/pgtable.h
> @@ -19,6 +19,8 @@
>   * because we always allocate their pages with alloc_page(), and
>   * alloc_page() always returns identity mapped pages.
>   */
> +#include <linux/compiler.h>
> +
>  #define pgtable_va(x)		((void *)(unsigned long)(x))
>  #define pgtable_pa(x)		((unsigned long)(x))
>  
> @@ -58,8 +60,9 @@ static inline pmd_t *pmd_alloc_one(void)
>  static inline pmd_t *pmd_alloc(pgd_t *pgd, unsigned long addr)
>  {
>  	if (pgd_none(*pgd)) {
> -		pmd_t *pmd = pmd_alloc_one();
> -		pgd_val(*pgd) = pgtable_pa(pmd) | PMD_TYPE_TABLE;
> +		pgd_t entry;
> +		pgd_val(entry) = pgtable_pa(pmd_alloc_one()) | PMD_TYPE_TABLE;
> +		WRITE_ONCE(*pgd, entry);
>  	}
>  	return pmd_offset(pgd, addr);
>  }
> @@ -84,8 +87,9 @@ static inline pte_t *pte_alloc_one(void)
>  static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr)
>  {
>  	if (pmd_none(*pmd)) {
> -		pte_t *pte = pte_alloc_one();
> -		pmd_val(*pmd) = pgtable_pa(pte) | PMD_TYPE_TABLE;
> +		pmd_t entry;
> +		pmd_val(entry) = pgtable_pa(pte_alloc_one()) | PMD_TYPE_TABLE;
> +		WRITE_ONCE(*pmd, entry);
>  	}
>  	return pte_offset(pmd, addr);
>  }
> diff --git a/lib/arm64/asm/pgtable.h b/lib/arm64/asm/pgtable.h
> index ee0a2c88cc18..dbf9e7253b71 100644
> --- a/lib/arm64/asm/pgtable.h
> +++ b/lib/arm64/asm/pgtable.h
> @@ -18,6 +18,8 @@
>  #include <asm/page.h>
>  #include <asm/pgtable-hwdef.h>
>  
> +#include <linux/compiler.h>
> +
>  /*
>   * We can convert va <=> pa page table addresses with simple casts
>   * because we always allocate their pages with alloc_page(), and
> @@ -66,8 +68,9 @@ static inline pte_t *pte_alloc_one(void)
>  static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr)
>  {
>  	if (pmd_none(*pmd)) {
> -		pte_t *pte = pte_alloc_one();
> -		pmd_val(*pmd) = pgtable_pa(pte) | PMD_TYPE_TABLE;
> +		pmd_t entry;
> +		pmd_val(entry) = pgtable_pa(pte_alloc_one()) | PMD_TYPE_TABLE;
> +		WRITE_ONCE(*pmd, entry);
>  	}
>  	return pte_offset(pmd, addr);
>  }
> diff --git a/lib/arm/mmu.c b/lib/arm/mmu.c
> index 5c31c00ccb31..86a829966a3c 100644
> --- a/lib/arm/mmu.c
> +++ b/lib/arm/mmu.c
> @@ -17,6 +17,8 @@
>  #include <asm/pgtable-hwdef.h>
>  #include <asm/pgtable.h>
>  
> +#include <linux/compiler.h>
> +
>  extern unsigned long etext;
>  
>  pgd_t *mmu_idmap;
> @@ -86,7 +88,7 @@ static pteval_t *install_pte(pgd_t *pgtable, uintptr_t vaddr, pteval_t pte)
>  {
>  	pteval_t *p_pte = get_pte(pgtable, vaddr);
>  
> -	*p_pte = pte;
> +	WRITE_ONCE(*p_pte, pte);
>  	flush_tlb_page(vaddr);
>  	return p_pte;
>  }
> @@ -131,12 +133,15 @@ void mmu_set_range_sect(pgd_t *pgtable, uintptr_t virt_offset,
>  	phys_addr_t paddr = phys_start & PGDIR_MASK;
>  	uintptr_t vaddr = virt_offset & PGDIR_MASK;
>  	uintptr_t virt_end = phys_end - paddr + vaddr;
> +	pgd_t *pgd;
> +	pgd_t entry;
>  
>  	for (; vaddr < virt_end; vaddr += PGDIR_SIZE, paddr += PGDIR_SIZE) {
> -		pgd_t *pgd = pgd_offset(pgtable, vaddr);
> -		pgd_val(*pgd) = paddr;
> -		pgd_val(*pgd) |= PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S;
> -		pgd_val(*pgd) |= pgprot_val(prot);
> +		pgd_val(entry) = paddr;
> +		pgd_val(entry) |= PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S;
> +		pgd_val(entry) |= pgprot_val(prot);
> +		pgd = pgd_offset(pgtable, vaddr);
> +		WRITE_ONCE(*pgd, entry);
>  		flush_tlb_page(vaddr);
>  	}
>  }
> @@ -210,6 +215,7 @@ void mmu_clear_user(unsigned long vaddr)
>  {
>  	pgd_t *pgtable;
>  	pteval_t *pte;
> +	pteval_t entry;
>  
>  	if (!mmu_enabled())
>  		return;
> @@ -217,6 +223,7 @@ void mmu_clear_user(unsigned long vaddr)
>  	pgtable = current_thread_info()->pgtable;
>  	pte = get_pte(pgtable, vaddr);
>  
> -	*pte &= ~PTE_USER;
> +	entry = *pte & ~PTE_USER;
> +	WRITE_ONCE(*pte, entry);
>  	flush_tlb_page(vaddr);
>  }


  reply	other threads:[~2020-01-02 18:06 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-31 16:09 [kvm-unit-tests PATCH v3 00/18] arm/arm64: Various fixes Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 01/18] lib: arm/arm64: Remove unnecessary dcache maintenance operations Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 02/18] lib: arm: Add proper data synchronization barriers for TLBIs Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 03/18] lib: Add WRITE_ONCE and READ_ONCE implementations in compiler.h Alexandru Elisei
2020-01-02 18:03   ` Andre Przywara
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 04/18] lib: arm/arm64: Use WRITE_ONCE to update the translation tables Alexandru Elisei
2020-01-02 18:06   ` Andre Przywara [this message]
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 05/18] lib: arm/arm64: Remove unused CPU_OFF parameter Alexandru Elisei
2020-01-02 18:11   ` Andre Przywara
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 06/18] arm/arm64: psci: Don't run C code without stack or vectors Alexandru Elisei
2020-01-02 18:11   ` Andre Przywara
2020-01-03 15:31     ` Andrew Jones
2020-01-06 11:02       ` Alexandru Elisei
2020-01-06 13:03         ` Andrew Jones
2020-01-06 14:03           ` Alexandru Elisei
2020-01-06 10:41     ` Alexandru Elisei
2020-01-06 11:17       ` Andre Przywara
2020-01-06 11:28         ` Alexandru Elisei
2020-01-06 11:36         ` Mark Rutland
2020-01-06 11:41       ` Mark Rutland
2020-01-06 13:17         ` Andrew Jones
2020-01-06 14:12           ` Alexandru Elisei
2020-01-06 15:20             ` Andrew Jones
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 07/18] lib: arm/arm64: Add missing include for alloc_page.h in pgtable.h Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 08/18] lib: arm: Implement flush_tlb_all Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 09/18] lib: arm/arm64: Teach mmu_clear_user about block mappings Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 10/18] arm/arm64: selftest: Add prefetch abort test Alexandru Elisei
2020-01-06  9:24   ` Andrew Jones
2020-01-06 11:03     ` Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 11/18] arm64: timer: Write to ICENABLER to disable timer IRQ Alexandru Elisei
2020-01-03 13:36   ` Andre Przywara
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 12/18] arm64: timer: EOIR the interrupt after masking the timer Alexandru Elisei
2020-01-03 13:36   ` Andre Przywara
2020-01-06 11:35     ` Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 13/18] arm64: timer: Test behavior when timer disabled or masked Alexandru Elisei
2020-01-03 13:37   ` Andre Przywara
2020-01-06 13:22     ` Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 14/18] lib: arm/arm64: Refuse to disable the MMU with non-identity stack pointer Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 15/18] arm/arm64: Perform dcache clean + invalidate after turning MMU off Alexandru Elisei
2020-01-03 16:49   ` Andre Przywara
2020-01-06 14:27     ` Alexandru Elisei
2020-01-06 16:28       ` Andrew Jones
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 16/18] arm: cstart64.S: Downgrade TLBI to non-shareable in asm_mmu_enable Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 17/18] arm/arm64: Invalidate TLB before enabling MMU Alexandru Elisei
2019-12-31 16:09 ` [kvm-unit-tests PATCH v3 18/18] arm: cstart64.S: Remove icache invalidation from asm_mmu_enable Alexandru Elisei
2020-01-06  9:28 ` [kvm-unit-tests PATCH v3 00/18] arm/arm64: Various fixes Andrew Jones
2020-01-09 10:01   ` Alexandru Elisei

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200102180622.383b7395@donnerap.cambridge.arm.com \
    --to=andre.przywara@arm.com \
    --cc=alexandru.elisei@arm.com \
    --cc=drjones@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=maz@kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=vladimir.murzin@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.