Subject: [PATCH 2/4] arm64: place initial page tables above the kernel

From: [email-masked] (Laura Abbott)
Date: Tue, 20 May 2014 09:21:59 -0700

On 5/16/2014 2:50 AM, Mark Rutland wrote:
> Currently we place swapper_pg_dir and idmap_pg_dir below the kernel
> image, between PHYS_OFFSET and (PHYS_OFFSET + TEXT_OFFSET). However,
> bootloaders may use portions of this memory below the kernel and we do
> not parse the memory reservation list until after the MMU has been
> enabled. As such we may clobber some memory a bootloader wishes to have
> preserved.
> 
> To enable the use of all of this memory by bootloaders (when the
> required memory reservations are communicated to the kernel) it is
> necessary to move our initial page tables elsewhere. As we currently
> have an effectively unbound requirement for memory at the end of the
> kernel image for .bss, we can place the page tables here.
> 
> This patch moves the initial page table to the end of the kernel image,
> after the BSS. As they do not consist of any initialised data they will
> be stripped from the kernel Image as with the BSS. The BSS clearing
> routine is updated to stop at __bss_stop rather than _end so as to not
> clobber the page tables, and memory reservations made redundant by the
> new organisation are removed.
> 
> Signed-off-by: Mark Rutland <[email-masked]>
> ---
>  arch/arm64/include/asm/page.h   |  9 +++++++++
>  arch/arm64/kernel/head.S        | 28 ++++++++--------------------
>  arch/arm64/kernel/vmlinux.lds.S |  7 +++++++
>  arch/arm64/mm/init.c            | 12 ++++--------
>  4 files changed, 28 insertions(+), 28 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h
> index 46bf666..a6331e6 100644
> --- a/arch/arm64/include/asm/page.h
> +++ b/arch/arm64/include/asm/page.h
> @@ -31,6 +31,15 @@
>  /* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
>  #define __HAVE_ARCH_GATE_AREA		1
>  
> +/*
> + * The idmap and swapper page tables need some space reserved in the kernel
> + * image. The idmap only requires a pgd and a next level table to (section) map
> + * the kernel, while the swapper also maps the FDT and requires an additional
> + * table to map an early UART. See __create_page_tables for more information.
> + */
> +#define SWAPPER_DIR_SIZE	(3 * PAGE_SIZE)
> +#define IDMAP_DIR_SIZE		(2 * PAGE_SIZE)
> +
>  #ifndef __ASSEMBLY__
>  
>  #ifdef CONFIG_ARM64_64K_PAGES
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index e8e9883..5dd8127 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -35,29 +35,17 @@
>  #include <asm/page.h>
>  #include <asm/virt.h>
>  
> -/*
> - * swapper_pg_dir is the virtual address of the initial page table. We place
> - * the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has
> - * 2 pages and is placed below swapper_pg_dir.
> - */
>  #define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
>  
>  #if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000
>  #error KERNEL_RAM_VADDR must start at 0xXXX80000
>  #endif
>  
> -#define SWAPPER_DIR_SIZE	(3 * PAGE_SIZE)
> -#define IDMAP_DIR_SIZE		(2 * PAGE_SIZE)
> -
> -	.globl	swapper_pg_dir
> -	.equ	swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE
> -
> -	.globl	idmap_pg_dir
> -	.equ	idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE
> -
> -	.macro	pgtbl, ttb0, ttb1, phys
> -	add	\ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE
> -	sub	\ttb0, \ttb1, #IDMAP_DIR_SIZE
> +	.macro	pgtbl, ttb0, ttb1, virt_to_phys
> +	ldr	\ttb1, =swapper_pg_dir
> +	ldr	\ttb0, =idmap_pg_dir
> +	add	\ttb1, \ttb1, \virt_to_phys
> +	add	\ttb0, \ttb0, \virt_to_phys
>  	.endm
>  
>  #ifdef CONFIG_ARM64_64K_PAGES
> @@ -304,7 +292,7 @@ ENTRY(secondary_startup)
>  	mov	x23, x0				// x23=current cpu_table
>  	cbz	x23, __error_p			// invalid processor (x23=0)?
>  
> -	pgtbl	x25, x26, x24			// x25=TTBR0, x26=TTBR1
> +	pgtbl	x25, x26, x28			// x25=TTBR0, x26=TTBR1
>  	ldr	x12, [x23, #CPU_INFO_SETUP]
>  	add	x12, x12, x28			// __virt_to_phys
>  	blr	x12				// initialise processor
> @@ -418,7 +406,7 @@ ENDPROC(__calc_phys_offset)
>   *   - pgd entry for fixed mappings (TTBR1)
>   */
>  __create_page_tables:
> -	pgtbl	x25, x26, x24			// idmap_pg_dir and swapper_pg_dir addresses
> +	pgtbl	x25, x26, x28			// idmap_pg_dir and swapper_pg_dir addresses
>  	mov	x27, lr
>  
>  	/*
> @@ -507,7 +495,7 @@ ENDPROC(__create_page_tables)
>  __switch_data:
>  	.quad	__mmap_switched
>  	.quad	__bss_start			// x6
> -	.quad	_end				// x7
> +	.quad	__bss_stop			// x7
>  	.quad	processor_id			// x4
>  	.quad	__fdt_pointer			// x5
>  	.quad	memstart_addr			// x6
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index 4ba7a55..51258bc 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -104,6 +104,13 @@ SECTIONS
>  	_edata = .;
>  
>  	BSS_SECTION(0, 0, 0)
> +
> +	. = ALIGN(PAGE_SIZE);
> +	idmap_pg_dir = .;
> +	. += IDMAP_DIR_SIZE;
> +	swapper_pg_dir = .;
> +	. += SWAPPER_DIR_SIZE;
> +
>  	_end = .;
>  
>  	STABS_DEBUG
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 51d5352..cc3339d 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -128,20 +128,16 @@ void __init arm64_memblock_init(void)
>  {
>  	u64 *reserve_map, base, size;
>  
> -	/* Register the kernel text, kernel data and initrd with memblock */
> +	/*
> +	 * Register the kernel text, kernel data, initrd, and initial
> +	 * pagetables with memblock.
> +	 */
>  	memblock_reserve(__pa(_text), _end - _text);
>  #ifdef CONFIG_BLK_DEV_INITRD
>  	if (initrd_start)
>  		memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
>  #endif
>  
> -	/*
> -	 * Reserve the page tables.  These are already in use,
> -	 * and can only be in node 0.
> -	 */
> -	memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE);
> -	memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE);
> -
>  	/* Reserve the dtb region */
>  	memblock_reserve(virt_to_phys(initial_boot_params),
>  			 be32_to_cpu(initial_boot_params->totalsize));
> 

Tested-by: Laura Abbott <[email-masked]>

Both 4K and 64K pages

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation