Re: [PATCH RFC] ARM: early fixmap support for earlycon

From: Rob Herring
Date: Sat Dec 27 2014 - 22:25:05 EST


On Sat, Dec 27, 2014 at 3:08 PM, Stefan Agner <stefan@xxxxxxxx> wrote:

Thanks for picking this up.

> Add early fixmap support, initially to support permanent, fixed
> mapping support for early console. A temporary, early pte is
> created which is migrated to a permanent mapping in paging_init.
> This is also needed since the attributs may change as the memory

s/attributs/attributes/

I would like to fix this problem. I think it can be if we setup
memtype table earlier. The complication is some of it is dependent on
cache_policy. The device memory types don't depend on cache_policy, so
they could be setup early and used. I think that can all be done after
this patch.

> types are initialized. The 3MiB range of fixmap spans two pte
> tables, but currently only one pte is created for early fixmap
> support.
>
> Readd FIX_KMAP_BEGIN to the index calculation in highmem.c since

s/Readd/Re-add/

> the index for kmap does not start at zero anymore. This reverts
> 4221e2e6b316 ("ARM: 8031/1: fixmap: remove FIX_KMAP_BEGIN and
> FIX_KMAP_END") to some extends.

s/extends/extent/

>
> Cc: Mark Salter <msalter@xxxxxxxxxx>
> Cc: Russell King <linux@xxxxxxxxxxxxxxxx>
> Cc: Rob Herring <robh@xxxxxxxxxx>
> Cc: Kees Cook <keescook@xxxxxxxxxxxx>
> Cc: Laura Abbott <lauraa@xxxxxxxxxxxxxx>
> Cc: Arnd Bergmann <arnd@xxxxxxxx>
> Signed-off-by: Stefan Agner <stefan@xxxxxxxx>
> ---
> While trying to implement earlycon support on Vybrid SoC, it
> turned out that set_fixmap does not support calls at that early
> stage. This patch picks up code/ideas from Rob's and Mark's
> patches supporting early_ioremap and fixmap support from Rob's
> git tree. This patch only adds the necessary bits to extend
> fixmap API for earlycon.
> https://git.kernel.org/cgit/linux/kernel/git/robh/linux.git/log/?h=arm-fixmap

Given, I wrote some of this, feel free to add my SOB. It all looks
good to me. One minor spelling error below though.

It would be nice if you could re-factor the early_ioremap support on
top of this, too.

> Also aligned the implementation somewhat how it is done for arm64
> in Laura's patch af86e5974d30 ("arm64: Factor out fixmap
> initialization from ioremap").
>
> Tested with CONFIG_DEBUG_SET_MODULE_RONX which makes use of fixmap
> support too.
>
> arch/arm/Kconfig | 3 ++
> arch/arm/include/asm/fixmap.h | 13 +++++++-
> arch/arm/kernel/setup.c | 3 ++
> arch/arm/mm/highmem.c | 6 ++--
> arch/arm/mm/mmu.c | 76 +++++++++++++++++++++++++++++++++++++++++--
> 5 files changed, 94 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 97d07ed..3a73cca 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -183,6 +183,9 @@ config ARCH_HAS_ILOG2_U64
> config ARCH_HAS_BANDGAP
> bool
>
> +config FIX_EARLYCON_MEM
> + def_bool y
> +
> config GENERIC_HWEIGHT
> bool
> default y
> diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h
> index 0415eae..2d8b12b 100644
> --- a/arch/arm/include/asm/fixmap.h
> +++ b/arch/arm/include/asm/fixmap.h
> @@ -6,9 +6,13 @@
> #define FIXADDR_TOP (FIXADDR_END - PAGE_SIZE)
>
> #include <asm/kmap_types.h>
> +#include <asm/pgtable.h>
>
> enum fixed_addresses {
> - FIX_KMAP_BEGIN,
> + FIX_EARLYCON_MEM_BASE,
> + __end_of_permanent_fixed_addresses,
> +
> + FIX_KMAP_BEGIN = __end_of_permanent_fixed_addresses,
> FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
>
> /* Support writing RO kernel text via kprobes, jump labels, etc. */
> @@ -18,7 +22,14 @@ 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_IO (FIXMAP_PAGE_COMMON | L_PTE_MT_DEV_SHARED | L_PTE_SHARED)
> +#define FIXMAP_PAGE_NOCACHE FIXMAP_PAGE_IO
> +
> 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>
>
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index f9c8639..015eade 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -37,6 +37,7 @@
> #include <asm/cpu.h>
> #include <asm/cputype.h>
> #include <asm/elf.h>
> +#include <asm/fixmap.h>
> #include <asm/procinfo.h>
> #include <asm/psci.h>
> #include <asm/sections.h>
> @@ -916,6 +917,8 @@ void __init setup_arch(char **cmdline_p)
> strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
> *cmdline_p = cmd_line;
>
> + early_fixmap_init();
> +
> parse_early_param();
>
> early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
> diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
> index b98895d..c7097f9 100644
> --- a/arch/arm/mm/highmem.c
> +++ b/arch/arm/mm/highmem.c
> @@ -78,7 +78,7 @@ void *kmap_atomic(struct page *page)
>
> type = kmap_atomic_idx_push();
>
> - idx = type + KM_TYPE_NR * smp_processor_id();
> + idx = FIX_KMAP_BEGIN + type + KM_TYPE_NR * smp_processor_id();
> vaddr = __fix_to_virt(idx);
> #ifdef CONFIG_DEBUG_HIGHMEM
> /*
> @@ -105,7 +105,7 @@ void __kunmap_atomic(void *kvaddr)
>
> if (kvaddr >= (void *)FIXADDR_START) {
> type = kmap_atomic_idx();
> - idx = type + KM_TYPE_NR * smp_processor_id();
> + idx = FIX_KMAP_BEGIN + type + KM_TYPE_NR * smp_processor_id();
>
> if (cache_is_vivt())
> __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
> @@ -135,7 +135,7 @@ void *kmap_atomic_pfn(unsigned long pfn)
> return page_address(page);
>
> type = kmap_atomic_idx_push();
> - idx = type + KM_TYPE_NR * smp_processor_id();
> + idx = FIX_KMAP_BEGIN + type + KM_TYPE_NR * smp_processor_id();
> vaddr = __fix_to_virt(idx);
> #ifdef CONFIG_DEBUG_HIGHMEM
> BUG_ON(!pte_none(get_fixmap_pte(vaddr)));
> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> index cda7c40..d1f70dd 100644
> --- a/arch/arm/mm/mmu.c
> +++ b/arch/arm/mm/mmu.c
> @@ -357,6 +357,47 @@ const struct mem_type *get_mem_type(unsigned int type)
> }
> EXPORT_SYMBOL(get_mem_type);
>
> +static pte_t *(*pte_offset_fixmap)(pmd_t *dir, unsigned long addr);
> +
> +static pte_t bm_pte[PTRS_PER_PTE + PTE_HWTABLE_PTRS]
> + __aligned(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE) __initdata;
> +
> +static pte_t * __init pte_offset_early_fixmap(pmd_t *dir, unsigned long addr)
> +{
> + return &bm_pte[pte_index(addr)];
> +}
> +
> +static pte_t *pte_offset_late_fixmap(pmd_t *dir, unsigned long addr)
> +{
> + return pte_offset_kernel(dir, addr);
> +}
> +
> +static inline pmd_t * __init fixmap_pmd(unsigned long addr)
> +{
> + pgd_t *pgd = pgd_offset_k(addr);
> + pud_t *pud = pud_offset(pgd, addr);
> + pmd_t *pmd = pmd_offset(pud, addr);
> +
> + return pmd;
> +}
> +
> +void __init early_fixmap_init(void)
> +{
> + pmd_t *pmd;
> +
> + /*
> + * The early fixmap range spans multiple pmds, for which
> + * we are not preparted:

s/preparted/prepared/

> + */
> + BUILD_BUG_ON((__fix_to_virt(__end_of_permanent_fixed_addresses) >> PMD_SHIFT)
> + != FIXADDR_TOP >> PMD_SHIFT);
> +
> + pmd = fixmap_pmd(FIXADDR_TOP);
> + pmd_populate_kernel(&init_mm, pmd, bm_pte);
> +
> + pte_offset_fixmap = &pte_offset_early_fixmap;
> +}
> +
> /*
> * To avoid TLB flush broadcasts, this uses local_flush_tlb_kernel_range().
> * As a result, this can only be called with preemption disabled, as under
> @@ -365,7 +406,7 @@ EXPORT_SYMBOL(get_mem_type);
> void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
> {
> unsigned long vaddr = __fix_to_virt(idx);
> - pte_t *pte = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
> + pte_t *pte = pte_offset_fixmap(pmd_off_k(vaddr), vaddr);
>
> /* Make sure fixmap region does not exceed available allocation. */
> BUILD_BUG_ON(FIXADDR_START + (__end_of_fixed_addresses * PAGE_SIZE) >
> @@ -855,7 +896,7 @@ static void __init create_mapping(struct map_desc *md)
> }
>
> if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
> - md->virtual >= PAGE_OFFSET &&
> + md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
> (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
> pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
> (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
> @@ -1231,7 +1272,7 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
>
> early_trap_init(vectors);
>
> - for (addr = VMALLOC_START; addr; addr += PMD_SIZE)
> + for (addr = VMALLOC_START; addr < FIXADDR_START; addr += PMD_SIZE)
> pmd_clear(pmd_off_k(addr));
>
> /*
> @@ -1508,6 +1549,34 @@ void __init early_paging_init(const struct machine_desc *mdesc,
>
> #endif
>
> +static void __init early_fixmap_shutdown(void)
> +{
> + int i;
> +
> + pte_offset_fixmap = &pte_offset_late_fixmap;
> + pmd_clear(fixmap_pmd(fix_to_virt(__end_of_permanent_fixed_addresses - 1)));
> +
> + for (i = 0; i < __end_of_permanent_fixed_addresses; i++) {
> + pte_t *pte;
> + struct map_desc map;
> +
> + map.virtual = fix_to_virt(i);
> + pte = pte_offset_early_fixmap(pmd_off_k(map.virtual), map.virtual);
> +
> + /* Only i/o device mappings are supported ATM */
> + if (pte_none(*pte) ||
> + (pte_val(*pte) & L_PTE_MT_MASK) != L_PTE_MT_DEV_SHARED)
> + continue;
> +
> + map.pfn = pte_pfn(*pte);
> + map.type = MT_DEVICE;
> + map.length = PAGE_SIZE;
> +
> + create_mapping(&map);
> + }
> +}
> +
> +
> /*
> * paging_init() sets up the page tables, initialises the zone memory
> * maps, and sets up the zero page, bad page and bad page tables.
> @@ -1520,6 +1589,7 @@ void __init paging_init(const struct machine_desc *mdesc)
> prepare_page_table();
> map_lowmem();
> dma_contiguous_remap();
> + early_fixmap_shutdown();
> devicemaps_init(mdesc);
> kmap_init();
> tcm_init();
> --
> 2.2.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/