[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