[PATCH v2] arm: Fix memory attribute inconsistencies when using fixmap
Ard Biesheuvel
ard.biesheuvel at linaro.org
Tue Mar 21 12:00:37 PDT 2017
On 21 March 2017 at 17:36, Jon Medhurst (Tixy) <tixy at linaro.org> wrote:
> On Tue, 2017-03-21 at 17:30 +0000, Jon Medhurst 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().
>>
>> Fixes: a5f4c561b3b1 ("ARM: 8415/1: early fixmap support for earlycon")
>> Cc: stable at vger.kernel.org # v4.3+
>
> Sorry, this should have...
> Signed-off-by: Jon Medhurst <tixy at linaro.org>
>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
UEFI boot and earlycon both still work for me, so
Tested-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
It looks like nommu should be unaffected, but it is worth giving it a
spin as well
Thanks,
Ard.
>> ---
>>
>> Changes since v1:
>> - Completely rewritten based on Russell's and Ard's sugestions
>> - Subject changed from "arm: Fix cache inconsistency when using fixmap"
>>
>>
>> arch/arm/include/asm/fixmap.h | 7 +------
>> arch/arm/include/asm/mmu.h | 2 ++
>> arch/arm/kernel/setup.c | 5 +----
>> arch/arm/mm/mmu.c | 12 ++++++++++--
>> 4 files changed, 14 insertions(+), 12 deletions(-)
>>
>> diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h
>> index 5c17d2dec777..c54f06ace2a1 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 */
>> @@ -53,13 +53,8 @@ static const enum fixed_addresses __end_of_fixed_addresses =
>> #ifdef CONFIG_MMU
>>
>> void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
>> -void __init early_fixmap_init(void);
>>
>> #include <asm-generic/fixmap.h>
>>
>> -#else
>> -
>> -static inline void early_fixmap_init(void) { }
>> -
>> #endif
>> #endif
>> diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
>> index a5b47421059d..920d29ca5c3b 100644
>> --- a/arch/arm/include/asm/mmu.h
>> +++ b/arch/arm/include/asm/mmu.h
>> @@ -24,6 +24,8 @@ typedef struct {
>> #define ASID(mm) (0)
>> #endif
>>
>> +void early_mm_init(void);
>> +
>> #else
>>
>> /*
>> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
>> index f4e54503afa9..37c59589aac3 100644
>> --- a/arch/arm/kernel/setup.c
>> +++ b/arch/arm/kernel/setup.c
>> @@ -40,7 +40,6 @@
>> #include <asm/efi.h>
>> #include <asm/elf.h>
>> #include <asm/early_ioremap.h>
>> -#include <asm/fixmap.h>
>> #include <asm/procinfo.h>
>> #include <asm/psci.h>
>> #include <asm/sections.h>
>> @@ -1082,12 +1081,10 @@ void __init setup_arch(char **cmdline_p)
>> strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
>> *cmdline_p = cmd_line;
>>
>> - early_fixmap_init();
>> - early_ioremap_init();
>> -
>> parse_early_param();
>>
>> #ifdef CONFIG_MMU
>> + early_mm_init();
>> early_paging_init(mdesc);
>> #endif
>> setup_dma_zone(mdesc);
>> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
>> index 4e016d7f37b3..f81809e6bd10 100644
>> --- a/arch/arm/mm/mmu.c
>> +++ b/arch/arm/mm/mmu.c
>> @@ -22,6 +22,7 @@
>> #include <asm/cputype.h>
>> #include <asm/sections.h>
>> #include <asm/cachetype.h>
>> +#include <asm/early_ioremap.h>
>> #include <asm/fixmap.h>
>> #include <asm/sections.h>
>> #include <asm/setup.h>
>> @@ -382,7 +383,7 @@ static inline pmd_t * __init fixmap_pmd(unsigned long addr)
>> return pmd;
>> }
>>
>> -void __init early_fixmap_init(void)
>> +static void __init early_fixmap_init(void)
>> {
>> pmd_t *pmd;
>>
>> @@ -1616,7 +1617,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 +1636,11 @@ 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(void)
>> +{
>> + build_mem_type_table();
>> +
>> + early_fixmap_init();
>> + early_ioremap_init();
>> +}
More information about the linux-arm-kernel
mailing list