Commit 3e957020 authored by Jon Medhurst's avatar Jon Medhurst Committed by Greg Kroah-Hartman

ARM: 8667/3: Fix memory attribute inconsistencies when using fixmap

commit b089c31c upstream.

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
a5f4c561) 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().

[ardb: keep early_fixmap_init() before param parsing, for earlycon]

Fixes: a5f4c561 ("ARM: 8415/1: early fixmap support for earlycon")
Tested-by: default avatarafzal mohammed <afzal.mohd.ma@gmail.com>
Signed-off-by: default avatarJon Medhurst <tixy@linaro.org>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7e2aa72f
...@@ -41,7 +41,7 @@ static const enum fixed_addresses __end_of_fixed_addresses = ...@@ -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_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) #define FIXMAP_PAGE_RO (FIXMAP_PAGE_NORMAL | L_PTE_RDONLY)
/* Used by set_fixmap_(io|nocache), both meant for mapping a device */ /* Used by set_fixmap_(io|nocache), both meant for mapping a device */
......
...@@ -80,7 +80,7 @@ __setup("fpe=", fpe_setup); ...@@ -80,7 +80,7 @@ __setup("fpe=", fpe_setup);
extern void init_default_cache_policy(unsigned long); extern void init_default_cache_policy(unsigned long);
extern void paging_init(const struct machine_desc *desc); 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 void adjust_lowmem_bounds(void);
extern enum reboot_mode reboot_mode; extern enum reboot_mode reboot_mode;
extern void setup_dma_zone(const struct machine_desc *desc); extern void setup_dma_zone(const struct machine_desc *desc);
...@@ -1088,7 +1088,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -1088,7 +1088,7 @@ void __init setup_arch(char **cmdline_p)
parse_early_param(); parse_early_param();
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
early_paging_init(mdesc); early_mm_init(mdesc);
#endif #endif
setup_dma_zone(mdesc); setup_dma_zone(mdesc);
xen_early_init(); xen_early_init();
......
...@@ -414,6 +414,11 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot) ...@@ -414,6 +414,11 @@ void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
FIXADDR_END); FIXADDR_END);
BUG_ON(idx >= __end_of_fixed_addresses); 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)) if (pgprot_val(prot))
set_pte_at(NULL, vaddr, pte, set_pte_at(NULL, vaddr, pte,
pfn_pte(phys >> PAGE_SHIFT, prot)); pfn_pte(phys >> PAGE_SHIFT, prot));
...@@ -1492,7 +1497,7 @@ pgtables_remap lpae_pgtables_remap_asm; ...@@ -1492,7 +1497,7 @@ pgtables_remap lpae_pgtables_remap_asm;
* early_paging_init() recreates boot time page table setup, allowing machines * early_paging_init() recreates boot time page table setup, allowing machines
* to switch over to a high (>4G) address space on LPAE systems * 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; pgtables_remap *lpae_pgtables_remap;
unsigned long pa_pgd; unsigned long pa_pgd;
...@@ -1560,7 +1565,7 @@ void __init early_paging_init(const struct machine_desc *mdesc) ...@@ -1560,7 +1565,7 @@ void __init early_paging_init(const struct machine_desc *mdesc)
#else #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; long long offset;
...@@ -1616,7 +1621,6 @@ void __init paging_init(const struct machine_desc *mdesc) ...@@ -1616,7 +1621,6 @@ void __init paging_init(const struct machine_desc *mdesc)
{ {
void *zero_page; void *zero_page;
build_mem_type_table();
prepare_page_table(); prepare_page_table();
map_lowmem(); map_lowmem();
memblock_set_current_limit(arm_lowmem_limit); memblock_set_current_limit(arm_lowmem_limit);
...@@ -1636,3 +1640,9 @@ void __init paging_init(const struct machine_desc *mdesc) ...@@ -1636,3 +1640,9 @@ void __init paging_init(const struct machine_desc *mdesc)
empty_zero_page = virt_to_page(zero_page); empty_zero_page = virt_to_page(zero_page);
__flush_dcache_page(NULL, empty_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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment