]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.19/arm64-fix-hcr.tge-status-for-nmi-contexts.patch
Linux 4.14.108
[thirdparty/kernel/stable-queue.git] / queue-4.19 / arm64-fix-hcr.tge-status-for-nmi-contexts.patch
1 From 5870970b9a828d8693aa6d15742573289d7dbcd0 Mon Sep 17 00:00:00 2001
2 From: Julien Thierry <julien.thierry@arm.com>
3 Date: Thu, 31 Jan 2019 14:58:39 +0000
4 Subject: arm64: Fix HCR.TGE status for NMI contexts
5
6 From: Julien Thierry <julien.thierry@arm.com>
7
8 commit 5870970b9a828d8693aa6d15742573289d7dbcd0 upstream.
9
10 When using VHE, the host needs to clear HCR_EL2.TGE bit in order
11 to interact with guest TLBs, switching from EL2&0 translation regime
12 to EL1&0.
13
14 However, some non-maskable asynchronous event could happen while TGE is
15 cleared like SDEI. Because of this address translation operations
16 relying on EL2&0 translation regime could fail (tlb invalidation,
17 userspace access, ...).
18
19 Fix this by properly setting HCR_EL2.TGE when entering NMI context and
20 clear it if necessary when returning to the interrupted context.
21
22 Signed-off-by: Julien Thierry <julien.thierry@arm.com>
23 Suggested-by: Marc Zyngier <marc.zyngier@arm.com>
24 Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
25 Reviewed-by: James Morse <james.morse@arm.com>
26 Cc: Arnd Bergmann <arnd@arndb.de>
27 Cc: Will Deacon <will.deacon@arm.com>
28 Cc: Marc Zyngier <marc.zyngier@arm.com>
29 Cc: James Morse <james.morse@arm.com>
30 Cc: linux-arch@vger.kernel.org
31 Cc: stable@vger.kernel.org
32 Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
33 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
34
35 ---
36 arch/arm64/include/asm/hardirq.h | 31 +++++++++++++++++++++++++++++++
37 arch/arm64/kernel/irq.c | 3 +++
38 include/linux/hardirq.h | 7 +++++++
39 3 files changed, 41 insertions(+)
40
41 --- a/arch/arm64/include/asm/hardirq.h
42 +++ b/arch/arm64/include/asm/hardirq.h
43 @@ -17,8 +17,12 @@
44 #define __ASM_HARDIRQ_H
45
46 #include <linux/cache.h>
47 +#include <linux/percpu.h>
48 #include <linux/threads.h>
49 +#include <asm/barrier.h>
50 #include <asm/irq.h>
51 +#include <asm/kvm_arm.h>
52 +#include <asm/sysreg.h>
53
54 #define NR_IPI 7
55
56 @@ -37,6 +41,33 @@ u64 smp_irq_stat_cpu(unsigned int cpu);
57
58 #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1
59
60 +struct nmi_ctx {
61 + u64 hcr;
62 +};
63 +
64 +DECLARE_PER_CPU(struct nmi_ctx, nmi_contexts);
65 +
66 +#define arch_nmi_enter() \
67 + do { \
68 + if (is_kernel_in_hyp_mode()) { \
69 + struct nmi_ctx *nmi_ctx = this_cpu_ptr(&nmi_contexts); \
70 + nmi_ctx->hcr = read_sysreg(hcr_el2); \
71 + if (!(nmi_ctx->hcr & HCR_TGE)) { \
72 + write_sysreg(nmi_ctx->hcr | HCR_TGE, hcr_el2); \
73 + isb(); \
74 + } \
75 + } \
76 + } while (0)
77 +
78 +#define arch_nmi_exit() \
79 + do { \
80 + if (is_kernel_in_hyp_mode()) { \
81 + struct nmi_ctx *nmi_ctx = this_cpu_ptr(&nmi_contexts); \
82 + if (!(nmi_ctx->hcr & HCR_TGE)) \
83 + write_sysreg(nmi_ctx->hcr, hcr_el2); \
84 + } \
85 + } while (0)
86 +
87 static inline void ack_bad_irq(unsigned int irq)
88 {
89 extern unsigned long irq_err_count;
90 --- a/arch/arm64/kernel/irq.c
91 +++ b/arch/arm64/kernel/irq.c
92 @@ -33,6 +33,9 @@
93
94 unsigned long irq_err_count;
95
96 +/* Only access this in an NMI enter/exit */
97 +DEFINE_PER_CPU(struct nmi_ctx, nmi_contexts);
98 +
99 DEFINE_PER_CPU(unsigned long *, irq_stack_ptr);
100
101 int arch_show_interrupts(struct seq_file *p, int prec)
102 --- a/include/linux/hardirq.h
103 +++ b/include/linux/hardirq.h
104 @@ -60,8 +60,14 @@ extern void irq_enter(void);
105 */
106 extern void irq_exit(void);
107
108 +#ifndef arch_nmi_enter
109 +#define arch_nmi_enter() do { } while (0)
110 +#define arch_nmi_exit() do { } while (0)
111 +#endif
112 +
113 #define nmi_enter() \
114 do { \
115 + arch_nmi_enter(); \
116 printk_nmi_enter(); \
117 lockdep_off(); \
118 ftrace_nmi_enter(); \
119 @@ -80,6 +86,7 @@ extern void irq_exit(void);
120 ftrace_nmi_exit(); \
121 lockdep_on(); \
122 printk_nmi_exit(); \
123 + arch_nmi_exit(); \
124 } while (0)
125
126 #endif /* LINUX_HARDIRQ_H */