[PATCH RFC] ARM: early fixmap support for earlycon

Rob Herring robh at kernel.org
Sat Dec 27 19:24:30 PST 2014


On Sat, Dec 27, 2014 at 3:08 PM, Stefan Agner <stefan at agner.ch> 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 at redhat.com>
> Cc: Russell King <linux at arm.linux.org.uk>
> Cc: Rob Herring <robh at kernel.org>
> Cc: Kees Cook <keescook at chromium.org>
> Cc: Laura Abbott <lauraa at codeaurora.org>
> Cc: Arnd Bergmann <arnd at arndb.de>
> Signed-off-by: Stefan Agner <stefan at agner.ch>
> ---
> 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 at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-arm-kernel mailing list