Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 771dd6d6 authored by Will Deacon's avatar Will Deacon Committed by Greg Kroah-Hartman
Browse files

FROMLIST: arm64: mm: Map entry trampoline into trampoline and kernel page tables



The exception entry trampoline needs to be mapped at the same virtual
address in both the trampoline page table (which maps nothing else)
and also the kernel page table, so that we can swizzle TTBR1_EL1 on
exceptions from and return to EL0.

This patch maps the trampoline at a fixed virtual address in the fixmap
area of the kernel virtual address space, which allows the kernel proper
to be randomized with respect to the trampoline when KASLR is enabled.

Reviewed-by: default avatarMark Rutland <mark.rutland@arm.com>
Tested-by: default avatarLaura Abbott <labbott@redhat.com>
Tested-by: default avatarShanker Donthineni <shankerd@codeaurora.org>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
(cherry picked from git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git


 commit 51a0048beb449682d632d0af52a515adb9f9882e)

Change-Id: I31b2dcdf4db36c3e31181fe43ccb984f9efb6ac6
[ghackmann@google.com:
 - adjust context
 - tweak __create_pgd_mapping() call to match 3.18 APIs
 - expand definition of PGD_SIZE, which is private to pgd.c in 3.18]
 - open-code pgd_pgtable_alloc(), based on version in 4.9]
Signed-off-by: default avatarGreg Hackmann <ghackmann@google.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 6415b1f8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -33,6 +33,10 @@
enum fixed_addresses {
	FIX_HOLE,
	FIX_EARLYCON_MEM_BASE,
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
	FIX_ENTRY_TRAMP_TEXT,
#define TRAMP_VALIAS		(__fix_to_virt(FIX_ENTRY_TRAMP_TEXT))
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
	__end_of_permanent_fixed_addresses,

	/*
+1 −0
Original line number Diff line number Diff line
@@ -479,6 +479,7 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)

extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
extern pgd_t tramp_pg_dir[PTRS_PER_PGD];

/*
 * Encode and decode a swap entry:
+5 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/kvm_host.h>
#include <asm/fixmap.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/smp_plat.h>
@@ -164,6 +165,10 @@ int main(void)
  DEFINE(SLEEP_SAVE_SP_SZ,	sizeof(struct sleep_save_sp));
  DEFINE(SLEEP_SAVE_SP_PHYS,	offsetof(struct sleep_save_sp, save_ptr_stash_phys));
  DEFINE(SLEEP_SAVE_SP_VIRT,	offsetof(struct sleep_save_sp, save_ptr_stash));
#endif
  BLANK();
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
  DEFINE(TRAMP_VALIAS,		TRAMP_VALIAS);
#endif
  return 0;
}
+37 −0
Original line number Diff line number Diff line
@@ -428,6 +428,43 @@ void fixup_init(void)
			PAGE_KERNEL);
}

#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
static void __init *pgd_pgtable_alloc(unsigned long size)
{
	void *ptr;
	BUG_ON(size != PAGE_SIZE);

	ptr = (void *)__get_free_page(PGALLOC_GFP);
	if (!ptr || !pgtable_page_ctor(virt_to_page(ptr)))
		BUG();

	/* Ensure the zeroed page is visible to the page table walker */
	dsb(ishst);
	return ptr;
}

static int __init map_entry_trampoline(void)
{
	extern char __entry_tramp_text_start[];

	pgprot_t prot = PAGE_KERNEL_EXEC;
	phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);

	/* The trampoline is always mapped and can therefore be global */
	pgprot_val(prot) &= ~PTE_NG;

	/* Map only the text into the trampoline page table */
	memset(tramp_pg_dir, 0, PTRS_PER_PGD * sizeof(pgd_t));
	__create_mapping(NULL, tramp_pg_dir + pgd_index(TRAMP_VALIAS), pa_start,
			 TRAMP_VALIAS, PAGE_SIZE, prot, pgd_pgtable_alloc);

	/* ...as well as the kernel page table */
	__set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
	return 0;
}
core_initcall(map_entry_trampoline);
#endif

/*
 * paging_init() sets up the page tables, initialises the zone memory
 * maps and sets up the zero page.