All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap
@ 2017-04-04  7:31 Ard Biesheuvel
  2017-04-04  8:48 ` Jon Medhurst (Tixy)
  2017-04-05 22:42 ` Russell King - ARM Linux
  0 siblings, 2 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2017-04-04  7:31 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jon Medhurst <tixy@linaro.org>

To cope with the variety in ARM architectures and configurations, the
pagetable attributes for kernel memory are generated at runtime to match
the system the kernel finds itself on. This calculated value is stored
in pgprot_kernel.

However, when early fixmap support was added for ARM (commit
a5f4c561b3b1) the attributes used for mappings were hard coded because
pgprot_kernel is not set up early enough. Unfortunately, when fixmap is
used after early boot this means the memory being mapped can have
different attributes to existing mappings, potentially leading to
unpredictable behaviour. A specific problem also exists due to the hard
coded values not include the 'shareable' attribute which means on
systems where this matters (e.g. those with multiple CPU clusters) the
cache contents for a memory location can become inconsistent between
CPUs.

To resolve these issues we change fixmap to use the same memory
attributes (from pgprot_kernel) that the rest of the kernel uses. To
enable this we need to refactor the initialisation code so
build_mem_type_table() is called early enough. Note, that relies on early
param parsing for memory type overrides passed via the kernel command
line, so we need to make sure this call is still after
parse_early_params().

Fixes: a5f4c561b3b1 ("ARM: 8415/1: early fixmap support for earlycon")
Cc: <stable@vger.kernel.org> # v4.3+
Signed-off-by: Jon Medhurst <tixy@linaro.org>
[ardb: keep early_fixmap_init() before param parsing, for earlycon]
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
v3: - Unfortunately, I failed to spot an issue with earlycon when testing
      Tixy's v2. Earlycon depends on fixmap, but only for device mappings,
      which are not affected by this change. So instead, preserve the calls
      to early_fixmap_init() and early_ioremap_init() in their original
      locations, and only move build_mem_type_table() to the earliest
      possible moment in boot, which is right after early param parsing
      (which may set cachepolicy/nocache/nowb variables)

 arch/arm/include/asm/fixmap.h |  2 +-
 arch/arm/include/asm/mmu.h    |  6 ++++++
 arch/arm/kernel/setup.c       |  5 ++---
 arch/arm/mm/mmu.c             | 12 +++++++++++-
 4 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h
index 5c17d2dec777..8f967d1373f6 100644
--- a/arch/arm/include/asm/fixmap.h
+++ b/arch/arm/include/asm/fixmap.h
@@ -41,7 +41,7 @@ static const enum fixed_addresses __end_of_fixed_addresses =
 
 #define FIXMAP_PAGE_COMMON	(L_PTE_YOUNG | L_PTE_PRESENT | L_PTE_XN | L_PTE_DIRTY)
 
-#define FIXMAP_PAGE_NORMAL	(FIXMAP_PAGE_COMMON | L_PTE_MT_WRITEBACK)
+#define FIXMAP_PAGE_NORMAL	(pgprot_kernel | L_PTE_XN)
 #define FIXMAP_PAGE_RO		(FIXMAP_PAGE_NORMAL | L_PTE_RDONLY)
 
 /* Used by set_fixmap_(io|nocache), both meant for mapping a device */
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index a5b47421059d..80dfeb8ce8f2 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -1,6 +1,8 @@
 #ifndef __ARM_MMU_H
 #define __ARM_MMU_H
 
+struct machine_desc;
+
 #ifdef CONFIG_MMU
 
 typedef struct {
@@ -24,6 +26,8 @@ typedef struct {
 #define ASID(mm)	(0)
 #endif
 
+void early_mm_init(const struct machine_desc *mdesc);
+
 #else
 
 /*
@@ -35,6 +39,8 @@ typedef struct {
 	unsigned long	end_brk;
 } mm_context_t;
 
+static inline void early_mm_init(const struct machine_desc *mdesc) { }
+
 #endif
 
 #endif
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index f4e54503afa9..f5db5548ad42 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -1087,9 +1087,8 @@ void __init setup_arch(char **cmdline_p)
 
 	parse_early_param();
 
-#ifdef CONFIG_MMU
-	early_paging_init(mdesc);
-#endif
+	early_mm_init(mdesc);
+
 	setup_dma_zone(mdesc);
 	xen_early_init();
 	efi_init();
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4e016d7f37b3..ec81a30479aa 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -414,6 +414,11 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
 		     FIXADDR_END);
 	BUG_ON(idx >= __end_of_fixed_addresses);
 
+	/* we only support device mappings until pgprot_kernel has been set */
+	if (WARN_ON(pgprot_val(prot) != pgprot_val(FIXMAP_PAGE_IO) &&
+		    pgprot_val(pgprot_kernel) == 0))
+		return;
+
 	if (pgprot_val(prot))
 		set_pte_at(NULL, vaddr, pte,
 			pfn_pte(phys >> PAGE_SHIFT, prot));
@@ -1616,7 +1621,6 @@ void __init paging_init(const struct machine_desc *mdesc)
 {
 	void *zero_page;
 
-	build_mem_type_table();
 	prepare_page_table();
 	map_lowmem();
 	memblock_set_current_limit(arm_lowmem_limit);
@@ -1636,3 +1640,9 @@ void __init paging_init(const struct machine_desc *mdesc)
 	empty_zero_page = virt_to_page(zero_page);
 	__flush_dcache_page(NULL, empty_zero_page);
 }
+
+void __init early_mm_init(const struct machine_desc *mdesc)
+{
+	build_mem_type_table();
+	early_paging_init(mdesc);
+}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-04  7:31 [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap Ard Biesheuvel
@ 2017-04-04  8:48 ` Jon Medhurst (Tixy)
  2017-04-04  9:10   ` Ard Biesheuvel
  2017-04-05 22:42 ` Russell King - ARM Linux
  1 sibling, 1 reply; 10+ messages in thread
From: Jon Medhurst (Tixy) @ 2017-04-04  8:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2017-04-04 at 08:31 +0100, Ard Biesheuvel wrote:
> From: Jon Medhurst <tixy@linaro.org>
> 
> To cope with the variety in ARM architectures and configurations, the
> pagetable attributes for kernel memory are generated at runtime to match
> the system the kernel finds itself on. This calculated value is stored
> in pgprot_kernel.
> 
> However, when early fixmap support was added for ARM (commit
> a5f4c561b3b1) the attributes used for mappings were hard coded because
> pgprot_kernel is not set up early enough. Unfortunately, when fixmap is
> used after early boot this means the memory being mapped can have
> different attributes to existing mappings, potentially leading to
> unpredictable behaviour. A specific problem also exists due to the hard
> coded values not include the 'shareable' attribute which means on
> systems where this matters (e.g. those with multiple CPU clusters) the
> cache contents for a memory location can become inconsistent between
> CPUs.
> 
> To resolve these issues we change fixmap to use the same memory
> attributes (from pgprot_kernel) that the rest of the kernel uses. To
> enable this we need to refactor the initialisation code so
> build_mem_type_table() is called early enough. Note, that relies on early
> param parsing for memory type overrides passed via the kernel command
> line, so we need to make sure this call is still after
> parse_early_params().
> 
> Fixes: a5f4c561b3b1 ("ARM: 8415/1: early fixmap support for earlycon")
> Cc: <stable@vger.kernel.org> # v4.3+
> Signed-off-by: Jon Medhurst <tixy@linaro.org>
> [ardb: keep early_fixmap_init() before param parsing, for earlycon]
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
[...]
> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> index 4e016d7f37b3..ec81a30479aa 100644
> --- a/arch/arm/mm/mmu.c
> +++ b/arch/arm/mm/mmu.c
> @@ -414,6 +414,11 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
>  		     FIXADDR_END);
>  	BUG_ON(idx >= __end_of_fixed_addresses);
>  
> +	/* we only support device mappings until pgprot_kernel has been set */
> +	if (WARN_ON(pgprot_val(prot) != pgprot_val(FIXMAP_PAGE_IO) &&
> +		    pgprot_val(pgprot_kernel) == 0))
> +		return;
> +

Hmm, on return from this function, isn't the caller then going to try
and access the memory at the fixmap address we didn't map, and so get a
page fault? If so, would a BUG_ON here be better?

>  	if (pgprot_val(prot))
>  		set_pte_at(NULL, vaddr, pte,
>  			pfn_pte(phys >> PAGE_SHIFT, prot));
> @@ -1616,7 +1621,6 @@ void __init paging_init(const struct machine_desc *mdesc)
>  {
>  	void *zero_page;
>  
> -	build_mem_type_table();
>  	prepare_page_table();
>  	map_lowmem();
>  	memblock_set_current_limit(arm_lowmem_limit);
> @@ -1636,3 +1640,9 @@ void __init paging_init(const struct machine_desc *mdesc)
>  	empty_zero_page = virt_to_page(zero_page);
>  	__flush_dcache_page(NULL, empty_zero_page);
>  }
> +
> +void __init early_mm_init(const struct machine_desc *mdesc)
> +{
> +	build_mem_type_table();
> +	early_paging_init(mdesc);
> +}

I tested this change with kprobes tests on TC2 (the setup that showed
the original bug) and compile tested for a nommu device (I will boot
test that in a bit as that's not quick to setup).

Also, with this patch we can now make?early_paging_init() static now,
and remove the extern... 

diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index f5db5548ad42..8ad1e4414024 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -80,7 +80,6 @@ __setup("fpe=", fpe_setup);
 
 extern void init_default_cache_policy(unsigned long);
 extern void paging_init(const struct machine_desc *desc);
-extern void early_paging_init(const struct machine_desc *);
 extern void adjust_lowmem_bounds(void);
 extern enum reboot_mode reboot_mode;
 extern void setup_dma_zone(const struct machine_desc *desc);
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index ec81a30479aa..347cca965783 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1497,7 +1497,7 @@ pgtables_remap lpae_pgtables_remap_asm;
  * early_paging_init() recreates boot time page table setup, allowing machines
  * to switch over to a high (>4G) address space on LPAE systems
  */
-void __init early_paging_init(const struct machine_desc *mdesc)
+static void __init early_paging_init(const struct machine_desc *mdesc)
 {
 	pgtables_remap *lpae_pgtables_remap;
 	unsigned long pa_pgd;
@@ -1565,7 +1565,7 @@ void __init early_paging_init(const struct machine_desc *mdesc)
 
 #else
 
-void __init early_paging_init(const struct machine_desc *mdesc)
+static void __init early_paging_init(const struct machine_desc *mdesc)
 {
 	long long offset;
 

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-04  8:48 ` Jon Medhurst (Tixy)
@ 2017-04-04  9:10   ` Ard Biesheuvel
  2017-04-04 16:01     ` Jon Medhurst (Tixy)
  0 siblings, 1 reply; 10+ messages in thread
From: Ard Biesheuvel @ 2017-04-04  9:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 4 April 2017 at 09:48, Jon Medhurst (Tixy) <tixy@linaro.org> wrote:
> On Tue, 2017-04-04 at 08:31 +0100, Ard Biesheuvel wrote:
>> From: Jon Medhurst <tixy@linaro.org>
>>
>> To cope with the variety in ARM architectures and configurations, the
>> pagetable attributes for kernel memory are generated at runtime to match
>> the system the kernel finds itself on. This calculated value is stored
>> in pgprot_kernel.
>>
>> However, when early fixmap support was added for ARM (commit
>> a5f4c561b3b1) the attributes used for mappings were hard coded because
>> pgprot_kernel is not set up early enough. Unfortunately, when fixmap is
>> used after early boot this means the memory being mapped can have
>> different attributes to existing mappings, potentially leading to
>> unpredictable behaviour. A specific problem also exists due to the hard
>> coded values not include the 'shareable' attribute which means on
>> systems where this matters (e.g. those with multiple CPU clusters) the
>> cache contents for a memory location can become inconsistent between
>> CPUs.
>>
>> To resolve these issues we change fixmap to use the same memory
>> attributes (from pgprot_kernel) that the rest of the kernel uses. To
>> enable this we need to refactor the initialisation code so
>> build_mem_type_table() is called early enough. Note, that relies on early
>> param parsing for memory type overrides passed via the kernel command
>> line, so we need to make sure this call is still after
>> parse_early_params().
>>
>> Fixes: a5f4c561b3b1 ("ARM: 8415/1: early fixmap support for earlycon")
>> Cc: <stable@vger.kernel.org> # v4.3+
>> Signed-off-by: Jon Medhurst <tixy@linaro.org>
>> [ardb: keep early_fixmap_init() before param parsing, for earlycon]
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
> [...]
>> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
>> index 4e016d7f37b3..ec81a30479aa 100644
>> --- a/arch/arm/mm/mmu.c
>> +++ b/arch/arm/mm/mmu.c
>> @@ -414,6 +414,11 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
>>                    FIXADDR_END);
>>       BUG_ON(idx >= __end_of_fixed_addresses);
>>
>> +     /* we only support device mappings until pgprot_kernel has been set */
>> +     if (WARN_ON(pgprot_val(prot) != pgprot_val(FIXMAP_PAGE_IO) &&
>> +                 pgprot_val(pgprot_kernel) == 0))
>> +             return;
>> +
>
> Hmm, on return from this function, isn't the caller then going to try
> and access the memory at the fixmap address we didn't map, and so get a
> page fault? If so, would a BUG_ON here be better?
>

Yes, and no. BUG_ON guarantees a crash, while without it, it's only
highly likely. Since this will occur very early during boot, it is
better to limp on if we can than crash unconditionally.


>>       if (pgprot_val(prot))
>>               set_pte_at(NULL, vaddr, pte,
>>                       pfn_pte(phys >> PAGE_SHIFT, prot));
>> @@ -1616,7 +1621,6 @@ void __init paging_init(const struct machine_desc *mdesc)
>>  {
>>       void *zero_page;
>>
>> -     build_mem_type_table();
>>       prepare_page_table();
>>       map_lowmem();
>>       memblock_set_current_limit(arm_lowmem_limit);
>> @@ -1636,3 +1640,9 @@ void __init paging_init(const struct machine_desc *mdesc)
>>       empty_zero_page = virt_to_page(zero_page);
>>       __flush_dcache_page(NULL, empty_zero_page);
>>  }
>> +
>> +void __init early_mm_init(const struct machine_desc *mdesc)
>> +{
>> +     build_mem_type_table();
>> +     early_paging_init(mdesc);
>> +}
>
> I tested this change with kprobes tests on TC2 (the setup that showed
> the original bug) and compile tested for a nommu device (I will boot
> test that in a bit as that's not quick to setup).
>
> Also, with this patch we can now make early_paging_init() static now,
> and remove the extern...
>
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index f5db5548ad42..8ad1e4414024 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -80,7 +80,6 @@ __setup("fpe=", fpe_setup);
>
>  extern void init_default_cache_policy(unsigned long);
>  extern void paging_init(const struct machine_desc *desc);
> -extern void early_paging_init(const struct machine_desc *);
>  extern void adjust_lowmem_bounds(void);
>  extern enum reboot_mode reboot_mode;
>  extern void setup_dma_zone(const struct machine_desc *desc);
> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> index ec81a30479aa..347cca965783 100644
> --- a/arch/arm/mm/mmu.c
> +++ b/arch/arm/mm/mmu.c
> @@ -1497,7 +1497,7 @@ pgtables_remap lpae_pgtables_remap_asm;
>   * early_paging_init() recreates boot time page table setup, allowing machines
>   * to switch over to a high (>4G) address space on LPAE systems
>   */
> -void __init early_paging_init(const struct machine_desc *mdesc)
> +static void __init early_paging_init(const struct machine_desc *mdesc)
>  {
>         pgtables_remap *lpae_pgtables_remap;
>         unsigned long pa_pgd;
> @@ -1565,7 +1565,7 @@ void __init early_paging_init(const struct machine_desc *mdesc)
>
>  #else
>
> -void __init early_paging_init(const struct machine_desc *mdesc)
> +static void __init early_paging_init(const struct machine_desc *mdesc)
>  {
>         long long offset;
>

Good point. If everything checks out, we should fold that in when
submitting it to the patch tracker.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-04  9:10   ` Ard Biesheuvel
@ 2017-04-04 16:01     ` Jon Medhurst (Tixy)
  0 siblings, 0 replies; 10+ messages in thread
From: Jon Medhurst (Tixy) @ 2017-04-04 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 2017-04-04 at 10:10 +0100, Ard Biesheuvel wrote:
> On 4 April 2017 at 09:48, Jon Medhurst (Tixy) <tixy@linaro.org> wrote:
[...]
> > I tested this change with kprobes tests on TC2 (the setup that showed
> > the original bug) and compile tested for a nommu device (I will boot
> > test that in a bit as that's not quick to setup).

The nommu device (ARM MPS2) boots OK

> > 
> > Also, with this patch we can now make early_paging_init() static now,
> > and remove the extern...

[...]

> Good point. If everything checks out, we should fold that in when
> submitting it to the patch tracker.

I delayed a little in case Russell had comments about the changes, but
I've now submitted the patch...
http://www.armlinux.org.uk/developer/patches/viewpatch.php?id=8667/2

-- 
Tixy

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-04  7:31 [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap Ard Biesheuvel
  2017-04-04  8:48 ` Jon Medhurst (Tixy)
@ 2017-04-05 22:42 ` Russell King - ARM Linux
  2017-04-06 13:46   ` Jon Medhurst (Tixy)
  1 sibling, 1 reply; 10+ messages in thread
From: Russell King - ARM Linux @ 2017-04-05 22:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 04, 2017 at 08:31:27AM +0100, Ard Biesheuvel wrote:
> diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
> index a5b47421059d..80dfeb8ce8f2 100644
> --- a/arch/arm/include/asm/mmu.h
> +++ b/arch/arm/include/asm/mmu.h
> @@ -1,6 +1,8 @@
>  #ifndef __ARM_MMU_H
>  #define __ARM_MMU_H
>  
> +struct machine_desc;
> +
>  #ifdef CONFIG_MMU
>  
>  typedef struct {
> @@ -24,6 +26,8 @@ typedef struct {
>  #define ASID(mm)	(0)
>  #endif
>  
> +void early_mm_init(const struct machine_desc *mdesc);
> +
>  #else
>  
>  /*
> @@ -35,6 +39,8 @@ typedef struct {
>  	unsigned long	end_brk;
>  } mm_context_t;
>  
> +static inline void early_mm_init(const struct machine_desc *mdesc) { }
> +

Why are we stuffing this into mmu.h?  mmu.h is not the header file for
arch/arm/mm/mmu.c - although they have the same base filename, they are
not really related.

asm/mmu.h is supposed to be a kernel-wide include file for the mm_context_t
thing, and should not be filled with arch-private stuff.

Please find a better location for this.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-05 22:42 ` Russell King - ARM Linux
@ 2017-04-06 13:46   ` Jon Medhurst (Tixy)
  2017-04-06 13:49     ` Ard Biesheuvel
  0 siblings, 1 reply; 10+ messages in thread
From: Jon Medhurst (Tixy) @ 2017-04-06 13:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 2017-04-05 at 23:42 +0100, Russell King - ARM Linux wrote:
> On Tue, Apr 04, 2017 at 08:31:27AM +0100, Ard Biesheuvel wrote:
> > diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
> > index a5b47421059d..80dfeb8ce8f2 100644
> > --- a/arch/arm/include/asm/mmu.h
> > +++ b/arch/arm/include/asm/mmu.h
> > @@ -1,6 +1,8 @@
> >  #ifndef __ARM_MMU_H
> >  #define __ARM_MMU_H
> >  
> > +struct machine_desc;
> > +
> >  #ifdef CONFIG_MMU
> >  
> >  typedef struct {
> > @@ -24,6 +26,8 @@ typedef struct {
> >  #define ASID(mm)	(0)
> >  #endif
> >  
> > +void early_mm_init(const struct machine_desc *mdesc);
> > +
> >  #else
> >  
> >  /*
> > @@ -35,6 +39,8 @@ typedef struct {
> >  	unsigned long	end_brk;
> >  } mm_context_t;
> >  
> > +static inline void early_mm_init(const struct machine_desc *mdesc) { }
> > +
> 
> Why are we stuffing this into mmu.h?  mmu.h is not the header file for
> arch/arm/mm/mmu.c - although they have the same base filename, they are
> not really related.
> 
> asm/mmu.h is supposed to be a kernel-wide include file for the mm_context_t
> thing, and should not be filled with arch-private stuff.
> 
> Please find a better location for this.

In arch/arm/mm/mm.h ?

Or as early_mm_init() is replacing early_paging_init()?in setup.c, and
that is currently handled by a local extern statement, keeping doing the
same? That keeps the diff neater which is a plus for a patch that should
be backported to stable kernels.

-- 
Tixy

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-06 13:46   ` Jon Medhurst (Tixy)
@ 2017-04-06 13:49     ` Ard Biesheuvel
  2017-04-06 16:03       ` [PATCH v4] " Jon Medhurst (Tixy)
  0 siblings, 1 reply; 10+ messages in thread
From: Ard Biesheuvel @ 2017-04-06 13:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 6 April 2017 at 14:46, Jon Medhurst (Tixy) <tixy@linaro.org> wrote:
> On Wed, 2017-04-05 at 23:42 +0100, Russell King - ARM Linux wrote:
>> On Tue, Apr 04, 2017 at 08:31:27AM +0100, Ard Biesheuvel wrote:
>> > diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
>> > index a5b47421059d..80dfeb8ce8f2 100644
>> > --- a/arch/arm/include/asm/mmu.h
>> > +++ b/arch/arm/include/asm/mmu.h
>> > @@ -1,6 +1,8 @@
>> >  #ifndef __ARM_MMU_H
>> >  #define __ARM_MMU_H
>> >
>> > +struct machine_desc;
>> > +
>> >  #ifdef CONFIG_MMU
>> >
>> >  typedef struct {
>> > @@ -24,6 +26,8 @@ typedef struct {
>> >  #define ASID(mm)   (0)
>> >  #endif
>> >
>> > +void early_mm_init(const struct machine_desc *mdesc);
>> > +
>> >  #else
>> >
>> >  /*
>> > @@ -35,6 +39,8 @@ typedef struct {
>> >     unsigned long   end_brk;
>> >  } mm_context_t;
>> >
>> > +static inline void early_mm_init(const struct machine_desc *mdesc) { }
>> > +
>>
>> Why are we stuffing this into mmu.h?  mmu.h is not the header file for
>> arch/arm/mm/mmu.c - although they have the same base filename, they are
>> not really related.
>>
>> asm/mmu.h is supposed to be a kernel-wide include file for the mm_context_t
>> thing, and should not be filled with arch-private stuff.
>>
>> Please find a better location for this.
>
> In arch/arm/mm/mm.h ?
>
> Or as early_mm_init() is replacing early_paging_init() in setup.c, and
> that is currently handled by a local extern statement, keeping doing the
> same? That keeps the diff neater which is a plus for a patch that should
> be backported to stable kernels.
>

Yes, the latter sounds like the least intrusive approach.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v4] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-06 13:49     ` Ard Biesheuvel
@ 2017-04-06 16:03       ` Jon Medhurst (Tixy)
  2017-04-08 16:51         ` afzal mohammed
  0 siblings, 1 reply; 10+ messages in thread
From: Jon Medhurst (Tixy) @ 2017-04-06 16:03 UTC (permalink / raw)
  To: linux-arm-kernel

To cope with the variety in ARM architectures and configurations, the
pagetable attributes for kernel memory are generated at runtime to match
the system the kernel finds itself on. This calculated value is stored
in pgprot_kernel.

However, when early fixmap support was added for ARM (commit
a5f4c561b3b1) the attributes used for mappings were hard coded because
pgprot_kernel is not set up early enough. Unfortunately, when fixmap is
used after early boot this means the memory being mapped can have
different attributes to existing mappings, potentially leading to
unpredictable behaviour. A specific problem also exists due to the hard
coded values not include the 'shareable' attribute which means on
systems where this matters (e.g. those with multiple CPU clusters) the
cache contents for a memory location can become inconsistent between
CPUs.

To resolve these issues we change fixmap to use the same memory
attributes (from pgprot_kernel) that the rest of the kernel uses. To
enable this we need to refactor the initialisation code so
build_mem_type_table() is called early enough. Note, that relies on early
param parsing for memory type overrides passed via the kernel command
line, so we need to make sure this call is still after
parse_early_params().

Fixes: a5f4c561b3b1 ("ARM: 8415/1: early fixmap support for earlycon")
Cc: <stable@vger.kernel.org> # v4.3+
Signed-off-by: Jon Medhurst <tixy@linaro.org>
[ardb: keep early_fixmap_init() before param parsing, for earlycon]
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---

v4: - Drop declaration of early_mm_init() from arch/arm/include/asm/mmu.h
      and make early_paging_init() static.

Ard's v3:
    - Unfortunately, I failed to spot an issue with earlycon when testing
      Tixy's v2. Earlycon depends on fixmap, but only for device mappings,
      which are not affected by this change. So instead, preserve the calls
      to early_fixmap_init() and early_ioremap_init() in their original
      locations, and only move build_mem_type_table() to the earliest
      possible moment in boot, which is right after early param parsing
      (which may set cachepolicy/nocache/nowb variables)

 arch/arm/include/asm/fixmap.h |  2 +-
 arch/arm/kernel/setup.c       |  4 ++--
 arch/arm/mm/mmu.c             | 16 +++++++++++++---
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h
index 5c17d2dec777..8f967d1373f6 100644
--- a/arch/arm/include/asm/fixmap.h
+++ b/arch/arm/include/asm/fixmap.h
@@ -41,7 +41,7 @@ static const enum fixed_addresses __end_of_fixed_addresses =
 
 #define FIXMAP_PAGE_COMMON	(L_PTE_YOUNG | L_PTE_PRESENT | L_PTE_XN | L_PTE_DIRTY)
 
-#define FIXMAP_PAGE_NORMAL	(FIXMAP_PAGE_COMMON | L_PTE_MT_WRITEBACK)
+#define FIXMAP_PAGE_NORMAL	(pgprot_kernel | L_PTE_XN)
 #define FIXMAP_PAGE_RO		(FIXMAP_PAGE_NORMAL | L_PTE_RDONLY)
 
 /* Used by set_fixmap_(io|nocache), both meant for mapping a device */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index f4e54503afa9..32e1a9513dc7 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -80,7 +80,7 @@ __setup("fpe=", fpe_setup);
 
 extern void init_default_cache_policy(unsigned long);
 extern void paging_init(const struct machine_desc *desc);
-extern void early_paging_init(const struct machine_desc *);
+extern void early_mm_init(const struct machine_desc *);
 extern void adjust_lowmem_bounds(void);
 extern enum reboot_mode reboot_mode;
 extern void setup_dma_zone(const struct machine_desc *desc);
@@ -1088,7 +1088,7 @@ void __init setup_arch(char **cmdline_p)
 	parse_early_param();
 
 #ifdef CONFIG_MMU
-	early_paging_init(mdesc);
+	early_mm_init(mdesc);
 #endif
 	setup_dma_zone(mdesc);
 	xen_early_init();
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4e016d7f37b3..347cca965783 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -414,6 +414,11 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
 		     FIXADDR_END);
 	BUG_ON(idx >= __end_of_fixed_addresses);
 
+	/* we only support device mappings until pgprot_kernel has been set */
+	if (WARN_ON(pgprot_val(prot) != pgprot_val(FIXMAP_PAGE_IO) &&
+		    pgprot_val(pgprot_kernel) == 0))
+		return;
+
 	if (pgprot_val(prot))
 		set_pte_at(NULL, vaddr, pte,
 			pfn_pte(phys >> PAGE_SHIFT, prot));
@@ -1492,7 +1497,7 @@ pgtables_remap lpae_pgtables_remap_asm;
  * early_paging_init() recreates boot time page table setup, allowing machines
  * to switch over to a high (>4G) address space on LPAE systems
  */
-void __init early_paging_init(const struct machine_desc *mdesc)
+static void __init early_paging_init(const struct machine_desc *mdesc)
 {
 	pgtables_remap *lpae_pgtables_remap;
 	unsigned long pa_pgd;
@@ -1560,7 +1565,7 @@ void __init early_paging_init(const struct machine_desc *mdesc)
 
 #else
 
-void __init early_paging_init(const struct machine_desc *mdesc)
+static void __init early_paging_init(const struct machine_desc *mdesc)
 {
 	long long offset;
 
@@ -1616,7 +1621,6 @@ void __init paging_init(const struct machine_desc *mdesc)
 {
 	void *zero_page;
 
-	build_mem_type_table();
 	prepare_page_table();
 	map_lowmem();
 	memblock_set_current_limit(arm_lowmem_limit);
@@ -1636,3 +1640,9 @@ void __init paging_init(const struct machine_desc *mdesc)
 	empty_zero_page = virt_to_page(zero_page);
 	__flush_dcache_page(NULL, empty_zero_page);
 }
+
+void __init early_mm_init(const struct machine_desc *mdesc)
+{
+	build_mem_type_table();
+	early_paging_init(mdesc);
+}

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-06 16:03       ` [PATCH v4] " Jon Medhurst (Tixy)
@ 2017-04-08 16:51         ` afzal mohammed
  2017-04-10 10:16           ` Jon Medhurst (Tixy)
  0 siblings, 1 reply; 10+ messages in thread
From: afzal mohammed @ 2017-04-08 16:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Thu, Apr 06, 2017 at 05:03:14PM +0100, Jon Medhurst (Tixy) wrote:
> To cope with the variety in ARM architectures and configurations, the
> pagetable attributes for kernel memory are generated at runtime to match
> the system the kernel finds itself on. This calculated value is stored
> in pgprot_kernel.
> 
> However, when early fixmap support was added for ARM (commit
> a5f4c561b3b1) the attributes used for mappings were hard coded because
> pgprot_kernel is not set up early enough. Unfortunately, when fixmap is
> used after early boot this means the memory being mapped can have
> different attributes to existing mappings, potentially leading to
> unpredictable behaviour. A specific problem also exists due to the hard
> coded values not include the 'shareable' attribute which means on
> systems where this matters (e.g. those with multiple CPU clusters) the
> cache contents for a memory location can become inconsistent between
> CPUs.
> 
> To resolve these issues we change fixmap to use the same memory
> attributes (from pgprot_kernel) that the rest of the kernel uses. To
> enable this we need to refactor the initialisation code so
> build_mem_type_table() is called early enough. Note, that relies on early
> param parsing for memory type overrides passed via the kernel command
> line, so we need to make sure this call is still after
> parse_early_params().

Tested-by: afzal mohammed <afzal.mohd.ma@gmail.com>

with an emphasis on no-MMU's

Regards
afzal

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v4] arm: Fix memory attribute inconsistencies when using fixmap
  2017-04-08 16:51         ` afzal mohammed
@ 2017-04-10 10:16           ` Jon Medhurst (Tixy)
  0 siblings, 0 replies; 10+ messages in thread
From: Jon Medhurst (Tixy) @ 2017-04-10 10:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, 2017-04-08 at 22:21 +0530, afzal mohammed wrote:
> Hi,
> 
> On Thu, Apr 06, 2017 at 05:03:14PM +0100, Jon Medhurst (Tixy) wrote:
> > To cope with the variety in ARM architectures and configurations, the
> > pagetable attributes for kernel memory are generated at runtime to match
> > the system the kernel finds itself on. This calculated value is stored
> > in pgprot_kernel.
> > 
> > However, when early fixmap support was added for ARM (commit
> > a5f4c561b3b1) the attributes used for mappings were hard coded because
> > pgprot_kernel is not set up early enough. Unfortunately, when fixmap is
> > used after early boot this means the memory being mapped can have
> > different attributes to existing mappings, potentially leading to
> > unpredictable behaviour. A specific problem also exists due to the hard
> > coded values not include the 'shareable' attribute which means on
> > systems where this matters (e.g. those with multiple CPU clusters) the
> > cache contents for a memory location can become inconsistent between
> > CPUs.
> > 
> > To resolve these issues we change fixmap to use the same memory
> > attributes (from pgprot_kernel) that the rest of the kernel uses. To
> > enable this we need to refactor the initialisation code so
> > build_mem_type_table() is called early enough. Note, that relies on early
> > param parsing for memory type overrides passed via the kernel command
> > line, so we need to make sure this call is still after
> > parse_early_params().
> 
> Tested-by: afzal mohammed <afzal.mohd.ma@gmail.com>
> 
> with an emphasis on no-MMU's

Thanks. I've now submitted this new version to the patch tracker...
http://www.armlinux.org.uk/developer/patches/viewpatch.php?id=8667/3

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-04-10 10:16 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-04  7:31 [PATCH v3] arm: Fix memory attribute inconsistencies when using fixmap Ard Biesheuvel
2017-04-04  8:48 ` Jon Medhurst (Tixy)
2017-04-04  9:10   ` Ard Biesheuvel
2017-04-04 16:01     ` Jon Medhurst (Tixy)
2017-04-05 22:42 ` Russell King - ARM Linux
2017-04-06 13:46   ` Jon Medhurst (Tixy)
2017-04-06 13:49     ` Ard Biesheuvel
2017-04-06 16:03       ` [PATCH v4] " Jon Medhurst (Tixy)
2017-04-08 16:51         ` afzal mohammed
2017-04-10 10:16           ` Jon Medhurst (Tixy)

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.