arm64: entry: Add exception trampoline page for exceptions from EL0
authorWill Deacon <will.deacon@arm.com>
Tue, 3 Apr 2018 11:09:04 +0000 (12:09 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 8 Apr 2018 10:12:52 +0000 (12:12 +0200)
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
arch/arm64/kernel/vmlinux.lds.S

index f5aa8f010254c758ab1f6c7e116952239e3fd1cf..08f6f059e96060ceee0375b80bb09e4c5e0e6702 100644 (file)
 #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.
  */
index 1105aab1e6d6af4be3f88c0ee22d4cfafd5c5ce6..466a43adec9f27dc2202354b2820b073878658af 100644 (file)
@@ -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