| From foo@baz Thu Apr 5 21:39:27 CEST 2018 |
| From: Mark Rutland <mark.rutland@arm.com> |
| Date: Tue, 3 Apr 2018 12:09:04 +0100 |
| Subject: arm64: entry: Add exception trampoline page for exceptions from EL0 |
| To: stable@vger.kernel.org |
| Cc: mark.brown@linaro.org, ard.biesheuvel@linaro.org, marc.zyngier@arm.com, will.deacon@arm.com |
| Message-ID: <20180403110923.43575-9-mark.rutland@arm.com> |
| |
| From: Will Deacon <will.deacon@arm.com> |
| |
| commit c7b9adaf85f8 upstream. |
| |
| To allow unmapping of the kernel whilst running at EL0, we need to |
| point the exception vectors at an entry trampoline that can map/unmap |
| the kernel on entry/exit respectively. |
| |
| This patch adds the trampoline page, although it is not yet plugged |
| into the vector table and is therefore unused. |
| |
| Reviewed-by: Mark Rutland <mark.rutland@arm.com> |
| Tested-by: Laura Abbott <labbott@redhat.com> |
| Tested-by: Shanker Donthineni <shankerd@codeaurora.org> |
| Signed-off-by: Will Deacon <will.deacon@arm.com> |
| [Alex: avoid dependency on SW PAN patches] |
| Signed-off-by: Alex Shi <alex.shi@linaro.org> [v4.9 backport] |
| [Mark: remove dummy SW PAN definitions] |
| Signed-off-by: Mark Rutland <mark.rutland@arm.com> [v4.9 backport] |
| Tested-by: Will Deacon <will.deacon@arm.com> |
| Tested-by: Greg Hackmann <ghackmann@google.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/arm64/kernel/entry.S | 86 ++++++++++++++++++++++++++++++++++++++++ |
| arch/arm64/kernel/vmlinux.lds.S | 17 +++++++ |
| 2 files changed, 103 insertions(+) |
| |
| --- a/arch/arm64/kernel/entry.S |
| +++ b/arch/arm64/kernel/entry.S |
| @@ -29,9 +29,11 @@ |
| #include <asm/esr.h> |
| #include <asm/irq.h> |
| #include <asm/memory.h> |
| +#include <asm/mmu.h> |
| #include <asm/thread_info.h> |
| #include <asm/asm-uaccess.h> |
| #include <asm/unistd.h> |
| +#include <asm/kernel-pgtable.h> |
| |
| /* |
| * Context tracking subsystem. Used to instrument transitions |
| @@ -806,6 +808,90 @@ __ni_sys_trace: |
| |
| .popsection // .entry.text |
| |
| +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 |
| +/* |
| + * Exception vectors trampoline. |
| + */ |
| + .pushsection ".entry.tramp.text", "ax" |
| + |
| + .macro tramp_map_kernel, tmp |
| + mrs \tmp, ttbr1_el1 |
| + sub \tmp, \tmp, #SWAPPER_DIR_SIZE |
| + bic \tmp, \tmp, #USER_ASID_FLAG |
| + msr ttbr1_el1, \tmp |
| + .endm |
| + |
| + .macro tramp_unmap_kernel, tmp |
| + mrs \tmp, ttbr1_el1 |
| + add \tmp, \tmp, #SWAPPER_DIR_SIZE |
| + orr \tmp, \tmp, #USER_ASID_FLAG |
| + msr ttbr1_el1, \tmp |
| + /* |
| + * We avoid running the post_ttbr_update_workaround here because the |
| + * user and kernel ASIDs don't have conflicting mappings, so any |
| + * "blessing" as described in: |
| + * |
| + * http://lkml.kernel.org/r/56BB848A.6060603@caviumnetworks.com |
| + * |
| + * will not hurt correctness. Whilst this may partially defeat the |
| + * point of using split ASIDs in the first place, it avoids |
| + * the hit of invalidating the entire I-cache on every return to |
| + * userspace. |
| + */ |
| + .endm |
| + |
| + .macro tramp_ventry, regsize = 64 |
| + .align 7 |
| +1: |
| + .if \regsize == 64 |
| + msr tpidrro_el0, x30 // Restored in kernel_ventry |
| + .endif |
| + tramp_map_kernel x30 |
| + ldr x30, =vectors |
| + prfm plil1strm, [x30, #(1b - tramp_vectors)] |
| + msr vbar_el1, x30 |
| + add x30, x30, #(1b - tramp_vectors) |
| + isb |
| + br x30 |
| + .endm |
| + |
| + .macro tramp_exit, regsize = 64 |
| + adr x30, tramp_vectors |
| + msr vbar_el1, x30 |
| + tramp_unmap_kernel x30 |
| + .if \regsize == 64 |
| + mrs x30, far_el1 |
| + .endif |
| + eret |
| + .endm |
| + |
| + .align 11 |
| +ENTRY(tramp_vectors) |
| + .space 0x400 |
| + |
| + tramp_ventry |
| + tramp_ventry |
| + tramp_ventry |
| + tramp_ventry |
| + |
| + tramp_ventry 32 |
| + tramp_ventry 32 |
| + tramp_ventry 32 |
| + tramp_ventry 32 |
| +END(tramp_vectors) |
| + |
| +ENTRY(tramp_exit_native) |
| + tramp_exit |
| +END(tramp_exit_native) |
| + |
| +ENTRY(tramp_exit_compat) |
| + tramp_exit 32 |
| +END(tramp_exit_compat) |
| + |
| + .ltorg |
| + .popsection // .entry.tramp.text |
| +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ |
| + |
| /* |
| * Special system call wrappers. |
| */ |
| --- a/arch/arm64/kernel/vmlinux.lds.S |
| +++ b/arch/arm64/kernel/vmlinux.lds.S |
| @@ -56,6 +56,17 @@ jiffies = jiffies_64; |
| #define HIBERNATE_TEXT |
| #endif |
| |
| +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 |
| +#define TRAMP_TEXT \ |
| + . = ALIGN(PAGE_SIZE); \ |
| + VMLINUX_SYMBOL(__entry_tramp_text_start) = .; \ |
| + *(.entry.tramp.text) \ |
| + . = ALIGN(PAGE_SIZE); \ |
| + VMLINUX_SYMBOL(__entry_tramp_text_end) = .; |
| +#else |
| +#define TRAMP_TEXT |
| +#endif |
| + |
| /* |
| * The size of the PE/COFF section that covers the kernel image, which |
| * runs from stext to _edata, must be a round multiple of the PE/COFF |
| @@ -128,6 +139,7 @@ SECTIONS |
| HYPERVISOR_TEXT |
| IDMAP_TEXT |
| HIBERNATE_TEXT |
| + TRAMP_TEXT |
| *(.fixup) |
| *(.gnu.warning) |
| . = ALIGN(16); |
| @@ -216,6 +228,11 @@ SECTIONS |
| swapper_pg_dir = .; |
| . += SWAPPER_DIR_SIZE; |
| |
| +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 |
| + tramp_pg_dir = .; |
| + . += PAGE_SIZE; |
| +#endif |
| + |
| _end = .; |
| |
| STABS_DEBUG |