aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-11-02 14:08:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-11-02 14:08:19 -0400
commit8194c28efd96127cd1948ca48f3fe374e04cbf46 (patch)
tree17a8b1585d99724808358819d17d90c148e291aa
parent969a5197da89454c41d95e2404e2e9d91ad73ba6 (diff)
parent7d6475051fb3d9339c5c760ed9883bc0a9048b21 (diff)
Merge tag 'powerpc-5.4-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc fixes from Michael Ellerman: "Our recent cleanup of EEH led to an oops on bare metal machines when the cxl (CAPI) driver creates virtual devices for an attached FPGA accelerator. The "secure virtual machine" support we added in v5.4 had a bug if the kernel was relocated (moved during boot), in those cases the signature of the kernel text wouldn't verify and the Ultravisor would refuse to run the VM. A recent change to disable interrupts before calling arch_cpu_idle_dead() caused a WARN_ON() in our bare metal CPU offline code to always trigger. The KUAP (SMAP) support we added for 32-bit Book3S had a bug if the address range crossed a segment (256MB) boundary which could lead to spurious faults. Thanks to: Christophe Leroy, Frederic Barrat, Michael Anderson, Nicholas Piggin, Sam Bobroff, Thiago Jung Bauermann" * tag 'powerpc-5.4-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: powerpc/powernv: Fix CPU idle to be called with IRQs disabled powerpc/prom_init: Undo relocation before entering secure mode powerpc/powernv/eeh: Fix oops when probing cxl devices powerpc/32s: fix allow/prevent_user_access() when crossing segment boundaries.
-rw-r--r--arch/powerpc/include/asm/book3s/32/kup.h1
-rw-r--r--arch/powerpc/include/asm/elf.h3
-rw-r--r--arch/powerpc/kernel/prom_init.c13
-rw-r--r--arch/powerpc/kernel/prom_init_check.sh3
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c2
-rw-r--r--arch/powerpc/platforms/powernv/smp.c53
6 files changed, 57 insertions, 18 deletions
diff --git a/arch/powerpc/include/asm/book3s/32/kup.h b/arch/powerpc/include/asm/book3s/32/kup.h
index 677e9babef80..f9dc597b0b86 100644
--- a/arch/powerpc/include/asm/book3s/32/kup.h
+++ b/arch/powerpc/include/asm/book3s/32/kup.h
@@ -91,6 +91,7 @@
91 91
92static inline void kuap_update_sr(u32 sr, u32 addr, u32 end) 92static inline void kuap_update_sr(u32 sr, u32 addr, u32 end)
93{ 93{
94 addr &= 0xf0000000; /* align addr to start of segment */
94 barrier(); /* make sure thread.kuap is updated before playing with SRs */ 95 barrier(); /* make sure thread.kuap is updated before playing with SRs */
95 while (addr < end) { 96 while (addr < end) {
96 mtsrin(sr, addr); 97 mtsrin(sr, addr);
diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h
index 409c9bfb43d9..57c229a86f08 100644
--- a/arch/powerpc/include/asm/elf.h
+++ b/arch/powerpc/include/asm/elf.h
@@ -175,4 +175,7 @@ do { \
175 ARCH_DLINFO_CACHE_GEOMETRY; \ 175 ARCH_DLINFO_CACHE_GEOMETRY; \
176} while (0) 176} while (0)
177 177
178/* Relocate the kernel image to @final_address */
179void relocate(unsigned long final_address);
180
178#endif /* _ASM_POWERPC_ELF_H */ 181#endif /* _ASM_POWERPC_ELF_H */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index a4e7762dd286..100f1b57ec2f 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -3249,7 +3249,20 @@ static void setup_secure_guest(unsigned long kbase, unsigned long fdt)
3249 /* Switch to secure mode. */ 3249 /* Switch to secure mode. */
3250 prom_printf("Switching to secure mode.\n"); 3250 prom_printf("Switching to secure mode.\n");
3251 3251
3252 /*
3253 * The ultravisor will do an integrity check of the kernel image but we
3254 * relocated it so the check will fail. Restore the original image by
3255 * relocating it back to the kernel virtual base address.
3256 */
3257 if (IS_ENABLED(CONFIG_RELOCATABLE))
3258 relocate(KERNELBASE);
3259
3252 ret = enter_secure_mode(kbase, fdt); 3260 ret = enter_secure_mode(kbase, fdt);
3261
3262 /* Relocate the kernel again. */
3263 if (IS_ENABLED(CONFIG_RELOCATABLE))
3264 relocate(kbase);
3265
3253 if (ret != U_SUCCESS) { 3266 if (ret != U_SUCCESS) {
3254 prom_printf("Returned %d from switching to secure mode.\n", ret); 3267 prom_printf("Returned %d from switching to secure mode.\n", ret);
3255 prom_rtas_os_term("Switch to secure mode failed.\n"); 3268 prom_rtas_os_term("Switch to secure mode failed.\n");
diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh
index 78bab17b1396..b183ab9c5107 100644
--- a/arch/powerpc/kernel/prom_init_check.sh
+++ b/arch/powerpc/kernel/prom_init_check.sh
@@ -26,7 +26,8 @@ _end enter_prom $MEM_FUNCS reloc_offset __secondary_hold
26__secondary_hold_acknowledge __secondary_hold_spinloop __start 26__secondary_hold_acknowledge __secondary_hold_spinloop __start
27logo_linux_clut224 btext_prepare_BAT 27logo_linux_clut224 btext_prepare_BAT
28reloc_got2 kernstart_addr memstart_addr linux_banner _stext 28reloc_got2 kernstart_addr memstart_addr linux_banner _stext
29__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC." 29__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC.
30relocate"
30 31
31NM="$1" 32NM="$1"
32OBJ="$2" 33OBJ="$2"
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
index 6bc24a47e9ef..6f300ab7f0e9 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -42,7 +42,7 @@ void pnv_pcibios_bus_add_device(struct pci_dev *pdev)
42{ 42{
43 struct pci_dn *pdn = pci_get_pdn(pdev); 43 struct pci_dn *pdn = pci_get_pdn(pdev);
44 44
45 if (eeh_has_flag(EEH_FORCE_DISABLED)) 45 if (!pdn || eeh_has_flag(EEH_FORCE_DISABLED))
46 return; 46 return;
47 47
48 dev_dbg(&pdev->dev, "EEH: Setting up device\n"); 48 dev_dbg(&pdev->dev, "EEH: Setting up device\n");
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index fbd6e6b7bbf2..13e251699346 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -146,20 +146,25 @@ static int pnv_smp_cpu_disable(void)
146 return 0; 146 return 0;
147} 147}
148 148
149static void pnv_flush_interrupts(void)
150{
151 if (cpu_has_feature(CPU_FTR_ARCH_300)) {
152 if (xive_enabled())
153 xive_flush_interrupt();
154 else
155 icp_opal_flush_interrupt();
156 } else {
157 icp_native_flush_interrupt();
158 }
159}
160
149static void pnv_smp_cpu_kill_self(void) 161static void pnv_smp_cpu_kill_self(void)
150{ 162{
163 unsigned long srr1, unexpected_mask, wmask;
151 unsigned int cpu; 164 unsigned int cpu;
152 unsigned long srr1, wmask;
153 u64 lpcr_val; 165 u64 lpcr_val;
154 166
155 /* Standard hot unplug procedure */ 167 /* Standard hot unplug procedure */
156 /*
157 * This hard disables local interurpts, ensuring we have no lazy
158 * irqs pending.
159 */
160 WARN_ON(irqs_disabled());
161 hard_irq_disable();
162 WARN_ON(lazy_irq_pending());
163 168
164 idle_task_exit(); 169 idle_task_exit();
165 current->active_mm = NULL; /* for sanity */ 170 current->active_mm = NULL; /* for sanity */
@@ -173,6 +178,27 @@ static void pnv_smp_cpu_kill_self(void)
173 wmask = SRR1_WAKEMASK_P8; 178 wmask = SRR1_WAKEMASK_P8;
174 179
175 /* 180 /*
181 * This turns the irq soft-disabled state we're called with, into a
182 * hard-disabled state with pending irq_happened interrupts cleared.
183 *
184 * PACA_IRQ_DEC - Decrementer should be ignored.
185 * PACA_IRQ_HMI - Can be ignored, processing is done in real mode.
186 * PACA_IRQ_DBELL, EE, PMI - Unexpected.
187 */
188 hard_irq_disable();
189 if (generic_check_cpu_restart(cpu))
190 goto out;
191
192 unexpected_mask = ~(PACA_IRQ_DEC | PACA_IRQ_HMI | PACA_IRQ_HARD_DIS);
193 if (local_paca->irq_happened & unexpected_mask) {
194 if (local_paca->irq_happened & PACA_IRQ_EE)
195 pnv_flush_interrupts();
196 DBG("CPU%d Unexpected exit while offline irq_happened=%lx!\n",
197 cpu, local_paca->irq_happened);
198 }
199 local_paca->irq_happened = PACA_IRQ_HARD_DIS;
200
201 /*
176 * We don't want to take decrementer interrupts while we are 202 * We don't want to take decrementer interrupts while we are
177 * offline, so clear LPCR:PECE1. We keep PECE2 (and 203 * offline, so clear LPCR:PECE1. We keep PECE2 (and
178 * LPCR_PECE_HVEE on P9) enabled so as to let IPIs in. 204 * LPCR_PECE_HVEE on P9) enabled so as to let IPIs in.
@@ -197,6 +223,7 @@ static void pnv_smp_cpu_kill_self(void)
197 223
198 srr1 = pnv_cpu_offline(cpu); 224 srr1 = pnv_cpu_offline(cpu);
199 225
226 WARN_ON_ONCE(!irqs_disabled());
200 WARN_ON(lazy_irq_pending()); 227 WARN_ON(lazy_irq_pending());
201 228
202 /* 229 /*
@@ -212,13 +239,7 @@ static void pnv_smp_cpu_kill_self(void)
212 */ 239 */
213 if (((srr1 & wmask) == SRR1_WAKEEE) || 240 if (((srr1 & wmask) == SRR1_WAKEEE) ||
214 ((srr1 & wmask) == SRR1_WAKEHVI)) { 241 ((srr1 & wmask) == SRR1_WAKEHVI)) {
215 if (cpu_has_feature(CPU_FTR_ARCH_300)) { 242 pnv_flush_interrupts();
216 if (xive_enabled())
217 xive_flush_interrupt();
218 else
219 icp_opal_flush_interrupt();
220 } else
221 icp_native_flush_interrupt();
222 } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) { 243 } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
223 unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); 244 unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
224 asm volatile(PPC_MSGCLR(%0) : : "r" (msg)); 245 asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
@@ -266,7 +287,7 @@ static void pnv_smp_cpu_kill_self(void)
266 */ 287 */
267 lpcr_val = mfspr(SPRN_LPCR) | (u64)LPCR_PECE1; 288 lpcr_val = mfspr(SPRN_LPCR) | (u64)LPCR_PECE1;
268 pnv_program_cpu_hotplug_lpcr(cpu, lpcr_val); 289 pnv_program_cpu_hotplug_lpcr(cpu, lpcr_val);
269 290out:
270 DBG("CPU%d coming online...\n", cpu); 291 DBG("CPU%d coming online...\n", cpu);
271} 292}
272 293