[PATCH v2] ARM: Fix Keystone 2 kernel mapping regression
Robin Murphy
robin.murphy at arm.com
Thu Aug 5 05:25:33 PDT 2021
On 2021-08-04 20:27, Linus Walleij wrote:
> This fixes a Keystone 2 regression discovered as a side effect of
> defining an passing the physical start/end sections of the kernel
> to the MMU remapping code.
>
> As the Keystone applies an offset to all physical addresses,
> including those identified and patches by phys2virt, we fail to
> account for this offset in the kernel_sec_start and kernel_sec_end
> variables.
>
> Further these offsets can extend into the 64bit range on LPAE
> systems such as the Keystone 2.
>
> Fix it like this:
> - Extend kernel_sec_start and kernel_sec_end to be 64bit
> - Add the offset also to kernel_sec_start and kernel_sec_end
>
> As passing kernel_sec_start and kernel_sec_end as 64bit invariably
> incurs BE8 endianness issues I have attempted to dry-code around
> these.
>
> Tested on the Vexpress QEMU model both with and without LPAE
> enabled.
>
> Fixes: 6e121df14ccd ("ARM: 9090/1: Map the lowmem and kernel separately")
> Reported-by: Nishanth Menon <nmenon at kernel.org>
> Suggested-by: Russell King <linux at armlinux.org.uk>
> Tested-by: Grygorii Strashko <grygorii.strashko at ti.com>
> Tested-by: Nishanth Menon <nmenon at kernel.org>
> Signed-off-by: Linus Walleij <linus.walleij at linaro.org>
> ---
> ChangeLog v1->v2:
> - Better assembly, pass the #4 addition along in the str instruction
> str r8, [r5, #4]
> - Collect Tested-by tags from successful boot tests on Keystone 2.
> - I will put this into Russell's patch tracker immediately.
> ---
> arch/arm/include/asm/memory.h | 7 ++++---
> arch/arm/kernel/head.S | 17 ++++++++++++++---
> arch/arm/mm/mmu.c | 9 ++++++++-
> arch/arm/mm/pv-fixup-asm.S | 2 +-
> 4 files changed, 27 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index cfc9dfd70aad..f673e13e0f94 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -160,10 +160,11 @@ extern unsigned long vectors_base;
>
> /*
> * Physical start and end address of the kernel sections. These addresses are
> - * 2MB-aligned to match the section mappings placed over the kernel.
> + * 2MB-aligned to match the section mappings placed over the kernel. We use
> + * u64 so that LPAE mappings beyond the 32bit limit will work out as well.
> */
> -extern u32 kernel_sec_start;
> -extern u32 kernel_sec_end;
> +extern u64 kernel_sec_start;
> +extern u64 kernel_sec_end;
>
> /*
> * Physical vs virtual RAM address space conversion. These are
> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
> index 9eb0b4dbcc12..b6fc92d4cf23 100644
> --- a/arch/arm/kernel/head.S
> +++ b/arch/arm/kernel/head.S
> @@ -49,7 +49,8 @@
>
> /*
> * This needs to be assigned at runtime when the linker symbols are
> - * resolved.
> + * resolved. These are unsigned 64bit really, but in this assembly code
> + * We store them as 32bit.
> */
> .pushsection .data
> .align 2
> @@ -57,7 +58,9 @@
> .globl kernel_sec_end
> kernel_sec_start:
> .long 0
> + .long 0
> kernel_sec_end:
> + .long 0
> .long 0
> .popsection
>
> @@ -250,7 +253,11 @@ __create_page_tables:
> add r0, r4, #KERNEL_OFFSET >> (SECTION_SHIFT - PMD_ORDER)
> ldr r6, =(_end - 1)
> adr_l r5, kernel_sec_start @ _pa(kernel_sec_start)
> - str r8, [r5] @ Save physical start of kernel
> +#ifdef CONFIG_CPU_ENDIAN_BE8
> + str r8, [r5, #4] @ Save physical start of kernel (BE)
> +#else
> + str r8, [r5] @ Save physical start of kernel (LE)
> +#endif
> orr r3, r8, r7 @ Add the MMU flags
> add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
> 1: str r3, [r0], #1 << PMD_ORDER
> @@ -259,7 +266,11 @@ __create_page_tables:
> bls 1b
> eor r3, r3, r7 @ Remove the MMU flags
> adr_l r5, kernel_sec_end @ _pa(kernel_sec_end)
> - str r3, [r5] @ Save physical end of kernel
> +#ifdef CONFIG_CPU_ENDIAN_BE8
> + str r8, [r5, #4] @ Save physical end of kernel (BE)
For the benefit of the one person who tries running a BE kernel about 3
years from now, that probably wants to be r3 ;)
Robin.
> +#else
> + str r3, [r5] @ Save physical end of kernel (LE)
> +#endif
>
> #ifdef CONFIG_XIP_KERNEL
> /*
> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> index 7583bda5ea7d..a4e006005107 100644
> --- a/arch/arm/mm/mmu.c
> +++ b/arch/arm/mm/mmu.c
> @@ -1608,6 +1608,13 @@ static void __init early_paging_init(const struct machine_desc *mdesc)
> if (offset == 0)
> return;
>
> + /*
> + * Offset the kernel section physical offsets so that the kernel
> + * mapping will work out later on.
> + */
> + kernel_sec_start += offset;
> + kernel_sec_end += offset;
> +
> /*
> * Get the address of the remap function in the 1:1 identity
> * mapping setup by the early page table assembly code. We
> @@ -1716,7 +1723,7 @@ void __init paging_init(const struct machine_desc *mdesc)
> {
> void *zero_page;
>
> - pr_debug("physical kernel sections: 0x%08x-0x%08x\n",
> + pr_debug("physical kernel sections: 0x%08llx-0x%08llx\n",
> kernel_sec_start, kernel_sec_end);
>
> prepare_page_table();
> diff --git a/arch/arm/mm/pv-fixup-asm.S b/arch/arm/mm/pv-fixup-asm.S
> index 5c5e1952000a..f8e11f7c7880 100644
> --- a/arch/arm/mm/pv-fixup-asm.S
> +++ b/arch/arm/mm/pv-fixup-asm.S
> @@ -29,7 +29,7 @@ ENTRY(lpae_pgtables_remap_asm)
> ldr r6, =(_end - 1)
> add r7, r2, #0x1000
> add r6, r7, r6, lsr #SECTION_SHIFT - L2_ORDER
> - add r7, r7, #PAGE_OFFSET >> (SECTION_SHIFT - L2_ORDER)
> + add r7, r7, #KERNEL_OFFSET >> (SECTION_SHIFT - L2_ORDER)
> 1: ldrd r4, r5, [r7]
> adds r4, r4, r0
> adc r5, r5, r1
>
More information about the linux-arm-kernel
mailing list