powerpc fixes for 5.4 #4
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. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEJFGtCPCthwEv2Y/bUevqPMjhpYAFAl29N34THG1wZUBlbGxl cm1hbi5pZC5hdQAKCRBR6+o8yOGlgBVfEAC/zus1Klhx1iHInj9gF8XnehrD21OM zo2XRKFs1v7xhk3PiYqUJDXKNvq7Bi8IDQZ1luJZbZ1vbJs/zHXg4CbqHT+tCrPP AQwCl3tzgEYxr5bXt2GdmfMhGP2Vkt2l71oIwqbGBI205466ys6OpM2yVws5pR+N a4O5L1xhZQphXXu4XsfM8tVoHhgPkVkDcjaqwTKjTyLV5nDwQPlhaUFYxf1Q16YI PumHWUuT84CXGq8f1vM6mBGLvQW3JXuCzIw6JAN1kukwEKa7ugmjesBiS7OUc6IU yyMdiHFX94S/YySdm8LwIHLWttbMfv2bPzDZIZerAQU5UM3TddBjd6TDyJqVA79S nsfgkNzQCYXhUOOM94WtE+cUZ9G2VoxS84qFTLrj0Y/nhMV7uGUG+YlTrkNL4DN5 GqWdBv1lYHYbjh9GZh5YVmewK0cF6o05daspEKFyHcxucMWXhqlPHSjL0gVIpQMO czfhlF3D2jyWCO0BDNHwDa6x7BUBuKGIvm0IYhs9nPkr9WtGHEJrgwcRxc8N3Pcp rUQEj+V8CDebV6r2EsW6SIS68UpAjihp1EleiQ+1GoU2P1rHtmioPluqmA302cDy 76bAFC38pG1q3ELhEeZS7LDDR8+N2SwvaklXVCRMyEhWoRaxY2noa5ZUnO6d5vUS 0gzoth1ve2/gNA== =W7+c -----END PGP SIGNATURE----- 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.
This commit is contained in:
commit
8194c28efd
|
@ -91,6 +91,7 @@
|
||||||
|
|
||||||
static inline void kuap_update_sr(u32 sr, u32 addr, u32 end)
|
static inline void kuap_update_sr(u32 sr, u32 addr, u32 end)
|
||||||
{
|
{
|
||||||
|
addr &= 0xf0000000; /* align addr to start of segment */
|
||||||
barrier(); /* make sure thread.kuap is updated before playing with SRs */
|
barrier(); /* make sure thread.kuap is updated before playing with SRs */
|
||||||
while (addr < end) {
|
while (addr < end) {
|
||||||
mtsrin(sr, addr);
|
mtsrin(sr, addr);
|
||||||
|
|
|
@ -175,4 +175,7 @@ do { \
|
||||||
ARCH_DLINFO_CACHE_GEOMETRY; \
|
ARCH_DLINFO_CACHE_GEOMETRY; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/* Relocate the kernel image to @final_address */
|
||||||
|
void relocate(unsigned long final_address);
|
||||||
|
|
||||||
#endif /* _ASM_POWERPC_ELF_H */
|
#endif /* _ASM_POWERPC_ELF_H */
|
||||||
|
|
|
@ -3249,7 +3249,20 @@ static void setup_secure_guest(unsigned long kbase, unsigned long fdt)
|
||||||
/* Switch to secure mode. */
|
/* Switch to secure mode. */
|
||||||
prom_printf("Switching to secure mode.\n");
|
prom_printf("Switching to secure mode.\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ultravisor will do an integrity check of the kernel image but we
|
||||||
|
* relocated it so the check will fail. Restore the original image by
|
||||||
|
* relocating it back to the kernel virtual base address.
|
||||||
|
*/
|
||||||
|
if (IS_ENABLED(CONFIG_RELOCATABLE))
|
||||||
|
relocate(KERNELBASE);
|
||||||
|
|
||||||
ret = enter_secure_mode(kbase, fdt);
|
ret = enter_secure_mode(kbase, fdt);
|
||||||
|
|
||||||
|
/* Relocate the kernel again. */
|
||||||
|
if (IS_ENABLED(CONFIG_RELOCATABLE))
|
||||||
|
relocate(kbase);
|
||||||
|
|
||||||
if (ret != U_SUCCESS) {
|
if (ret != U_SUCCESS) {
|
||||||
prom_printf("Returned %d from switching to secure mode.\n", ret);
|
prom_printf("Returned %d from switching to secure mode.\n", ret);
|
||||||
prom_rtas_os_term("Switch to secure mode failed.\n");
|
prom_rtas_os_term("Switch to secure mode failed.\n");
|
||||||
|
|
|
@ -26,7 +26,8 @@ _end enter_prom $MEM_FUNCS reloc_offset __secondary_hold
|
||||||
__secondary_hold_acknowledge __secondary_hold_spinloop __start
|
__secondary_hold_acknowledge __secondary_hold_spinloop __start
|
||||||
logo_linux_clut224 btext_prepare_BAT
|
logo_linux_clut224 btext_prepare_BAT
|
||||||
reloc_got2 kernstart_addr memstart_addr linux_banner _stext
|
reloc_got2 kernstart_addr memstart_addr linux_banner _stext
|
||||||
__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC."
|
__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC.
|
||||||
|
relocate"
|
||||||
|
|
||||||
NM="$1"
|
NM="$1"
|
||||||
OBJ="$2"
|
OBJ="$2"
|
||||||
|
|
|
@ -42,7 +42,7 @@ void pnv_pcibios_bus_add_device(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct pci_dn *pdn = pci_get_pdn(pdev);
|
struct pci_dn *pdn = pci_get_pdn(pdev);
|
||||||
|
|
||||||
if (eeh_has_flag(EEH_FORCE_DISABLED))
|
if (!pdn || eeh_has_flag(EEH_FORCE_DISABLED))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "EEH: Setting up device\n");
|
dev_dbg(&pdev->dev, "EEH: Setting up device\n");
|
||||||
|
|
|
@ -146,20 +146,25 @@ static int pnv_smp_cpu_disable(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pnv_flush_interrupts(void)
|
||||||
|
{
|
||||||
|
if (cpu_has_feature(CPU_FTR_ARCH_300)) {
|
||||||
|
if (xive_enabled())
|
||||||
|
xive_flush_interrupt();
|
||||||
|
else
|
||||||
|
icp_opal_flush_interrupt();
|
||||||
|
} else {
|
||||||
|
icp_native_flush_interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void pnv_smp_cpu_kill_self(void)
|
static void pnv_smp_cpu_kill_self(void)
|
||||||
{
|
{
|
||||||
|
unsigned long srr1, unexpected_mask, wmask;
|
||||||
unsigned int cpu;
|
unsigned int cpu;
|
||||||
unsigned long srr1, wmask;
|
|
||||||
u64 lpcr_val;
|
u64 lpcr_val;
|
||||||
|
|
||||||
/* Standard hot unplug procedure */
|
/* Standard hot unplug procedure */
|
||||||
/*
|
|
||||||
* This hard disables local interurpts, ensuring we have no lazy
|
|
||||||
* irqs pending.
|
|
||||||
*/
|
|
||||||
WARN_ON(irqs_disabled());
|
|
||||||
hard_irq_disable();
|
|
||||||
WARN_ON(lazy_irq_pending());
|
|
||||||
|
|
||||||
idle_task_exit();
|
idle_task_exit();
|
||||||
current->active_mm = NULL; /* for sanity */
|
current->active_mm = NULL; /* for sanity */
|
||||||
|
@ -172,6 +177,27 @@ static void pnv_smp_cpu_kill_self(void)
|
||||||
if (cpu_has_feature(CPU_FTR_ARCH_207S))
|
if (cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||||
wmask = SRR1_WAKEMASK_P8;
|
wmask = SRR1_WAKEMASK_P8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This turns the irq soft-disabled state we're called with, into a
|
||||||
|
* hard-disabled state with pending irq_happened interrupts cleared.
|
||||||
|
*
|
||||||
|
* PACA_IRQ_DEC - Decrementer should be ignored.
|
||||||
|
* PACA_IRQ_HMI - Can be ignored, processing is done in real mode.
|
||||||
|
* PACA_IRQ_DBELL, EE, PMI - Unexpected.
|
||||||
|
*/
|
||||||
|
hard_irq_disable();
|
||||||
|
if (generic_check_cpu_restart(cpu))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
unexpected_mask = ~(PACA_IRQ_DEC | PACA_IRQ_HMI | PACA_IRQ_HARD_DIS);
|
||||||
|
if (local_paca->irq_happened & unexpected_mask) {
|
||||||
|
if (local_paca->irq_happened & PACA_IRQ_EE)
|
||||||
|
pnv_flush_interrupts();
|
||||||
|
DBG("CPU%d Unexpected exit while offline irq_happened=%lx!\n",
|
||||||
|
cpu, local_paca->irq_happened);
|
||||||
|
}
|
||||||
|
local_paca->irq_happened = PACA_IRQ_HARD_DIS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't want to take decrementer interrupts while we are
|
* We don't want to take decrementer interrupts while we are
|
||||||
* offline, so clear LPCR:PECE1. We keep PECE2 (and
|
* offline, so clear LPCR:PECE1. We keep PECE2 (and
|
||||||
|
@ -197,6 +223,7 @@ static void pnv_smp_cpu_kill_self(void)
|
||||||
|
|
||||||
srr1 = pnv_cpu_offline(cpu);
|
srr1 = pnv_cpu_offline(cpu);
|
||||||
|
|
||||||
|
WARN_ON_ONCE(!irqs_disabled());
|
||||||
WARN_ON(lazy_irq_pending());
|
WARN_ON(lazy_irq_pending());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -212,13 +239,7 @@ static void pnv_smp_cpu_kill_self(void)
|
||||||
*/
|
*/
|
||||||
if (((srr1 & wmask) == SRR1_WAKEEE) ||
|
if (((srr1 & wmask) == SRR1_WAKEEE) ||
|
||||||
((srr1 & wmask) == SRR1_WAKEHVI)) {
|
((srr1 & wmask) == SRR1_WAKEHVI)) {
|
||||||
if (cpu_has_feature(CPU_FTR_ARCH_300)) {
|
pnv_flush_interrupts();
|
||||||
if (xive_enabled())
|
|
||||||
xive_flush_interrupt();
|
|
||||||
else
|
|
||||||
icp_opal_flush_interrupt();
|
|
||||||
} else
|
|
||||||
icp_native_flush_interrupt();
|
|
||||||
} else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
|
} else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
|
||||||
unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
|
unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
|
||||||
asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
|
asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
|
||||||
|
@ -266,7 +287,7 @@ static void pnv_smp_cpu_kill_self(void)
|
||||||
*/
|
*/
|
||||||
lpcr_val = mfspr(SPRN_LPCR) | (u64)LPCR_PECE1;
|
lpcr_val = mfspr(SPRN_LPCR) | (u64)LPCR_PECE1;
|
||||||
pnv_program_cpu_hotplug_lpcr(cpu, lpcr_val);
|
pnv_program_cpu_hotplug_lpcr(cpu, lpcr_val);
|
||||||
|
out:
|
||||||
DBG("CPU%d coming online...\n", cpu);
|
DBG("CPU%d coming online...\n", cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue