[PATCH 2/5] arm64: use fixmap region for permanent FDT mapping

Ard Biesheuvel ard.biesheuvel at linaro.org
Wed Mar 11 00:05:58 PDT 2015


On 10 March 2015 at 22:37, Rob Herring <robh at kernel.org> wrote:
> On Tue, Mar 3, 2015 at 5:03 AM, Ard Biesheuvel
> <ard.biesheuvel at linaro.org> wrote:
>> Currently, the FDT blob needs to be in the same naturally aligned
>> 512 MB region as the kernel, so that it can be mapped into the
>> kernel virtual memory space very early on using a minimal set of
>> statically allocated translation tables.
>>
>> Now that we have early fixmap support, we can relax this restriction,
>> by moving the permanent FDT mapping to the fixmap region instead.
>> This way, the FDT blob may be anywhere in memory.
>>
>> This also moves the vetting of the FDT to setup.c, since the early
>> init code in head.S does not handle mapping of the FDT anymore.
>> At the same time, fix up some comments in head.S that have gone stale.
>>
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
>> ---
>>  Documentation/arm64/booting.txt |  7 ++---
>>  arch/arm64/include/asm/fixmap.h |  9 ++++++
>>  arch/arm64/kernel/Makefile      |  1 +
>>  arch/arm64/kernel/head.S        | 38 +------------------------
>>  arch/arm64/kernel/setup.c       | 62 +++++++++++++++++++++++++++++++++++++----
>>  5 files changed, 70 insertions(+), 47 deletions(-)
>>
>> diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
>> index f3c05b5f9f08..bdc35fc97ac8 100644
>> --- a/Documentation/arm64/booting.txt
>> +++ b/Documentation/arm64/booting.txt
>> @@ -45,10 +45,9 @@ sees fit.)
>>
>>  Requirement: MANDATORY
>>
>> -The device tree blob (dtb) must be placed on an 8-byte boundary within
>> -the first 512 megabytes from the start of the kernel image and must not
>> -cross a 2-megabyte boundary. This is to allow the kernel to map the
>> -blob using a single section mapping in the initial page tables.
>> +The device tree blob (dtb) must be placed on an 8-byte boundary and must
>> +not cross a 2-megabyte boundary. This is to allow the kernel to map the
>> +blob using a single section mapping in the fixmap region.
>>
>>
>>  3. Decompress the kernel image
>> diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
>> index defa0ff98250..4ad240a60898 100644
>> --- a/arch/arm64/include/asm/fixmap.h
>> +++ b/arch/arm64/include/asm/fixmap.h
>> @@ -32,6 +32,15 @@
>>   */
>>  enum fixed_addresses {
>>         FIX_HOLE,
>> +
>> +       /*
>> +        * Reserve 2 MB of virtual space for the FDT at the top of the fixmap
>> +        * region. Keep this at the top so it remains 2 MB aligned.
>> +        */
>
> We should not fix a location restriction by creating a size
> restriction. You could embed firmware images within a DTB (which I
> think PPC does).
>

The size restriction existed on arm64 before this patch, so I didn't
think twice about it.
So what would be a reasonable upper bound? We could go up to ~256 MB
without much trouble, but I guess that's a bit excessive, no?


>> +#define FIX_FDT_SIZE           SZ_2M
>> +       FIX_FDT_END,
>> +       FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,
>> +
>>         FIX_EARLYCON_MEM_BASE,
>>         __end_of_permanent_fixed_addresses,
>>
>> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
>> index 5ee07eee80c2..e60885766936 100644
>> --- a/arch/arm64/kernel/Makefile
>> +++ b/arch/arm64/kernel/Makefile
>> @@ -6,6 +6,7 @@ CPPFLAGS_vmlinux.lds    := -DTEXT_OFFSET=$(TEXT_OFFSET)
>>  AFLAGS_head.o          := -DTEXT_OFFSET=$(TEXT_OFFSET)
>>  CFLAGS_efi-stub.o      := -DTEXT_OFFSET=$(TEXT_OFFSET)
>>  CFLAGS_armv8_deprecated.o := -I$(src)
>> +CFLAGS_setup.o         := -I$(srctree)/scripts/dtc/libfdt/
>>
>>  CFLAGS_REMOVE_ftrace.o = -pg
>>  CFLAGS_REMOVE_insn.o = -pg
>> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
>> index 8ce88e08c030..66675d27fea3 100644
>> --- a/arch/arm64/kernel/head.S
>> +++ b/arch/arm64/kernel/head.S
>> @@ -255,7 +255,6 @@ ENTRY(stext)
>>         cbnz    x23, 1f                         // invalid processor (x23=0)?
>>         b       __error_p
>>  1:
>> -       bl      __vet_fdt
>>         bl      __create_page_tables            // x25=TTBR0, x26=TTBR1
>>         /*
>>          * The following calls CPU specific code in a position independent
>> @@ -274,24 +273,6 @@ ENTRY(stext)
>>  ENDPROC(stext)
>>
>>  /*
>> - * Determine validity of the x21 FDT pointer.
>> - * The dtb must be 8-byte aligned and live in the first 512M of memory.
>> - */
>> -__vet_fdt:
>> -       tst     x21, #0x7
>> -       b.ne    1f
>> -       cmp     x21, x24
>> -       b.lt    1f
>> -       mov     x0, #(1 << 29)
>> -       add     x0, x0, x24
>> -       cmp     x21, x0
>> -       b.ge    1f
>> -       ret
>> -1:
>> -       mov     x21, #0
>> -       ret
>> -ENDPROC(__vet_fdt)
>> -/*
>>   * Macro to create a table entry to the next page.
>>   *
>>   *     tbl:    page table address
>> @@ -352,8 +333,7 @@ ENDPROC(__vet_fdt)
>>   * required to get the kernel running. The following sections are required:
>>   *   - identity mapping to enable the MMU (low address, TTBR0)
>>   *   - first few MB of the kernel linear mapping to jump to once the MMU has
>> - *     been enabled, including the FDT blob (TTBR1)
>> - *   - pgd entry for fixed mappings (TTBR1)
>> + *     been enabled
>>   */
>>  __create_page_tables:
>>         pgtbl   x25, x26, x28                   // idmap_pg_dir and swapper_pg_dir addresses
>> @@ -404,22 +384,6 @@ __create_page_tables:
>>         create_block_map x0, x7, x3, x5, x6
>>
>>         /*
>> -        * Map the FDT blob (maximum 2MB; must be within 512MB of
>> -        * PHYS_OFFSET).
>> -        */
>> -       mov     x3, x21                         // FDT phys address
>> -       and     x3, x3, #~((1 << 21) - 1)       // 2MB aligned
>> -       mov     x6, #PAGE_OFFSET
>> -       sub     x5, x3, x24                     // subtract PHYS_OFFSET
>> -       tst     x5, #~((1 << 29) - 1)           // within 512MB?
>> -       csel    x21, xzr, x21, ne               // zero the FDT pointer
>> -       b.ne    1f
>> -       add     x5, x5, x6                      // __va(FDT blob)
>> -       add     x6, x5, #1 << 21                // 2MB for the FDT blob
>> -       sub     x6, x6, #1                      // inclusive range
>> -       create_block_map x0, x7, x3, x5, x6
>> -1:
>> -       /*
>>          * Since the page tables have been populated with non-cacheable
>>          * accesses (MMU disabled), invalidate the idmap and swapper page
>>          * tables again to remove any speculatively loaded cache lines.
>> diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
>> index e8420f635bd4..5c675a09116e 100644
>> --- a/arch/arm64/kernel/setup.c
>> +++ b/arch/arm64/kernel/setup.c
>> @@ -45,6 +45,7 @@
>>  #include <linux/of_platform.h>
>>  #include <linux/efi.h>
>>  #include <linux/personality.h>
>> +#include <linux/libfdt.h>
>>
>>  #include <asm/fixmap.h>
>>  #include <asm/cpu.h>
>> @@ -307,14 +308,63 @@ static void __init setup_processor(void)
>>  #endif
>>  }
>>
>> +static unsigned long const dt_virt_base = __fix_to_virt(FIX_FDT);
>> +static phys_addr_t dt_phys_base;
>> +
>> +phys_addr_t __init fdt_virt_to_phys(void *virt)
>> +{
>> +       return (phys_addr_t)virt - dt_virt_base + dt_phys_base;
>> +}
>> +
>> +static void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
>> +{
>> +       dt_phys_base = dt_phys & ~(FIX_FDT_SIZE - 1);
>> +
>> +       /*
>> +        * Make sure that the FDT region can be mapped without the need to
>> +        * allocate additional translation table pages, so that it is safe
>> +        * to call create_pgd_mapping() this early.
>> +        * On 4k pages, we'll use a section mapping for the 2 MB region so we
>> +        * only have to be in the same PUD as the rest of the fixmap.
>> +        * On 64k pages, we need to be in the same PMD as well, as the region
>> +        * will be mapped using PTEs.
>> +        */
>> +       BUILD_BUG_ON(dt_virt_base & (FIX_FDT_SIZE - 1));
>> +
>> +       if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
>> +               BUILD_BUG_ON(dt_virt_base >> PMD_SHIFT !=
>> +                            __fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT);
>> +       else
>> +               BUILD_BUG_ON(dt_virt_base >> PUD_SHIFT !=
>> +                            __fix_to_virt(FIX_BTMAP_BEGIN) >> PUD_SHIFT);
>> +
>> +       create_pgd_mapping(&init_mm, dt_phys_base, dt_virt_base, FIX_FDT_SIZE,
>> +                          PAGE_KERNEL);
>> +
>> +       return (void *)(dt_virt_base + dt_phys - dt_phys_base);
>> +}
>> +
>>  static void __init setup_machine_fdt(phys_addr_t dt_phys)
>>  {
>> -       if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys))) {
>> +       void *dt_virt = NULL;
>> +
>> +       if (dt_phys && (dt_phys & 7) == 0)
>> +               dt_virt = fixmap_remap_fdt(dt_phys);
>> +
>> +       /*
>> +        * Before passing the dt_virt pointer to early_init_dt_scan(), we have
>> +        * to ensure that the FDT size as reported in the FDT itself does not
>> +        * exceed the 2 MB window we just mapped for it.
>> +        */
>> +       if (!dt_virt ||
>> +           fdt_check_header(dt_virt) != 0 ||
>> +           (dt_phys & (SZ_2M - 1)) + fdt_totalsize(dt_virt) > SZ_2M ||
>> +           !early_init_dt_scan(dt_virt)) {
>>                 early_print("\n"
>>                         "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n"
>> -                       "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n"
>> +                       "The dtb must be 8-byte aligned and must not cross a 2 MB alignment boundary\n"
>>                         "\nPlease check your bootloader.\n",
>> -                       dt_phys, phys_to_virt(dt_phys));
>> +                       dt_phys, dt_virt);
>>
>>                 while (true)
>>                         cpu_relax();
>> @@ -357,6 +407,9 @@ void __init setup_arch(char **cmdline_p)
>>  {
>>         setup_processor();
>>
>> +       early_fixmap_init();
>> +       early_ioremap_init();
>> +
>>         setup_machine_fdt(__fdt_pointer);
>>
>>         init_mm.start_code = (unsigned long) _text;
>> @@ -366,9 +419,6 @@ void __init setup_arch(char **cmdline_p)
>>
>>         *cmdline_p = boot_command_line;
>>
>> -       early_fixmap_init();
>> -       early_ioremap_init();
>> -
>>         parse_early_param();
>>
>>         /*
>> --
>> 1.8.3.2
>>



More information about the linux-arm-kernel mailing list