[PATCH v4 09/13] arm64: mm: explicitly bootstrap the linear mapping

Catalin Marinas catalin.marinas at arm.com
Thu May 7 09:54:16 PDT 2015


On Wed, Apr 15, 2015 at 05:34:20PM +0200, Ard Biesheuvel wrote:
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index ceec4def354b..338eaa7bcbfd 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -68,6 +68,17 @@ PECOFF_FILE_ALIGNMENT = 0x200;
>  #define ALIGN_DEBUG_RO_MIN(min)		. = ALIGN(min);
>  #endif
>  
> +/*
> + * The pgdir region needs to be mappable using a single PMD or PUD sized region,
> + * so it should not cross a 512 MB or 1 GB alignment boundary, respectively
> + * (depending on page size). So align to an upper bound of its size.
> + */
> +#if CONFIG_ARM64_PGTABLE_LEVELS == 2
> +#define PGDIR_ALIGN	(8 * PAGE_SIZE)
> +#else
> +#define PGDIR_ALIGN	(16 * PAGE_SIZE)
> +#endif

Isn't 8 pages sufficient in both cases? Unless some other patch changes
the idmap and swapper, I can count maximum 7 pages in total.

> +
>  SECTIONS
>  {
>  	/*
> @@ -160,7 +171,7 @@ SECTIONS
>  
>  	BSS_SECTION(0, 0, 0)
>  
> -	.pgdir (NOLOAD) : ALIGN(PAGE_SIZE) {
> +	.pgdir (NOLOAD) : ALIGN(PGDIR_ALIGN) {
>  		idmap_pg_dir = .;
>  		. += IDMAP_DIR_SIZE;
>  		swapper_pg_dir = .;
> @@ -185,6 +196,11 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
>  	"ID map text too big or misaligned")
>  
>  /*
> + * Check that the chosen PGDIR_ALIGN value if sufficient.
> + */
> +ASSERT(SIZEOF(.pgdir) < ALIGNOF(.pgdir), ".pgdir size exceeds its alignment")
> +
> +/*
>   * If padding is applied before .head.text, virt<->phys conversions will fail.
>   */
>  ASSERT(_text == (PAGE_OFFSET + TEXT_OFFSET), "HEAD is misaligned")
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index c27ab20a5ba9..93e5a2497f01 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -380,26 +380,68 @@ static void __init bootstrap_early_mapping(unsigned long addr,
>  	}
>  }
>  
> +static void __init bootstrap_linear_mapping(unsigned long va_offset)
> +{
> +	/*
> +	 * Bootstrap the linear range that covers swapper_pg_dir so that the
> +	 * statically allocated page tables as well as newly allocated ones
> +	 * are accessible via the linear mapping.
> +	 */

Just move the comment outside the function.

> +	static struct bootstrap_pgtables linear_bs_pgtables __pgdir;
> +	const phys_addr_t swapper_phys = __pa(swapper_pg_dir);
> +	unsigned long swapper_virt = __phys_to_virt(swapper_phys) + va_offset;
> +	struct memblock_region *reg;
> +
> +	bootstrap_early_mapping(swapper_virt, &linear_bs_pgtables,
> +				IS_ENABLED(CONFIG_ARM64_64K_PAGES));
> +
> +	/* now find the memblock that covers swapper_pg_dir, and clip */
> +	for_each_memblock(memory, reg) {
> +		phys_addr_t start = reg->base;
> +		phys_addr_t end = start + reg->size;
> +		unsigned long vstart, vend;
> +
> +		if (start > swapper_phys || end <= swapper_phys)
> +			continue;
> +
> +#ifdef CONFIG_ARM64_64K_PAGES
> +		/* clip the region to PMD size */
> +		vstart = max(swapper_virt & PMD_MASK,
> +			     round_up(__phys_to_virt(start + va_offset),
> +				      PAGE_SIZE));
> +		vend = min(round_up(swapper_virt, PMD_SIZE),
> +			   round_down(__phys_to_virt(end + va_offset),
> +				      PAGE_SIZE));
> +#else
> +		/* clip the region to PUD size */
> +		vstart = max(swapper_virt & PUD_MASK,
> +			     round_up(__phys_to_virt(start + va_offset),
> +				      PMD_SIZE));
> +		vend = min(round_up(swapper_virt, PUD_SIZE),
> +			   round_down(__phys_to_virt(end + va_offset),
> +				      PMD_SIZE));
> +#endif
> +
> +		create_mapping(__pa(vstart - va_offset), vstart, vend - vstart,
> +			       PAGE_KERNEL_EXEC);
> +
> +		/*
> +		 * Temporarily limit the memblock range. We need to do this as
> +		 * create_mapping requires puds, pmds and ptes to be allocated
> +		 * from memory addressable from the early linear mapping.
> +		 */
> +		memblock_set_current_limit(__pa(vend - va_offset));
> +
> +		return;
> +	}
> +	BUG();
> +}

I'll probably revisit this function after I see the whole series. But in
the meantime, if the kernel is not loaded in the first memblock (in
address order), isn't there a risk that we allocate memory from the
first memblock which is not mapped yet?

-- 
Catalin



More information about the linux-arm-kernel mailing list