FAILED: patch "[PATCH] arm64: Fix incorrect irqflag restore for priority masking" failed to apply to 5.1-stable tree
Subsystems (5)
[email protected]
maintainerThe patch below does not apply to the 5.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From bd82d4bd21880b7c4d5f5756be435095d6ae07b5 Mon Sep 17 00:00:00 2001
From: Julien Thierry <[email protected]>
Date: Tue, 11 Jun 2019 10:38:10 +0100
Subject: [PATCH] arm64: Fix incorrect irqflag restore for priority masking
When using IRQ priority masking to disable interrupts, in order to deal with the PSR.I state, local_irq_save() would convert the I bit into a PMR value (GIC_PRIO_IRQOFF). This resulted in local_irq_restore() potentially modifying the value of PMR in undesired location due to the state of PSR.I upon flag saving [1].
In an attempt to solve this issue in a less hackish manner, introduce a bit (GIC_PRIO_IGNORE_PMR) for the PMR values that can represent whether PSR.I is being used to disable interrupts, in which case it takes precedence of the status of interrupt masking via PMR.
GIC_PRIO_PSR_I_SET is chosen such that (<pmr_value> | GIC_PRIO_PSR_I_SET) does not mask more interrupts than <pmr_value> as some sections (e.g. arch_cpu_idle(), interrupt acknowledge path) requires PMR not to mask interrupts that could be signaled to the CPU when using only PSR.I.
[1] https://www.spinics.net/lists/arm-kernel/msg716956.html
arch/arm64/include/asm/arch_gicv3.h +3 -1
@@ -163,7 +163,9 @@ static inline bool gic_prio_masking_enabled(void)static inline void gic_pmr_mask_irqs (void ) { -BUILD_BUG_ON (GICD_INT_DEF_PRI <=GIC_PRIO_IRQOFF ); +BUILD_BUG_ON (GICD_INT_DEF_PRI < (GIC_PRIO_IRQOFF | +GIC_PRIO_PSR_I_SET )); +BUILD_BUG_ON (GICD_INT_DEF_PRI >=GIC_PRIO_IRQON );gic_write_pmr (GIC_PRIO_IRQOFF ); }
arch/arm64/include/asm/daifflags.h +41 -27
96 lines not on this page · raw message
arch/arm64/include/asm/irqflags.h +27 -40
91 lines not on this page · raw message
arch/arm64/include/asm/kvm_host.h +4 -3
@@ -608,11 +608,12 @@ static inline void kvm_arm_vhe_guest_enter(void)* will not signal the CPU of interrupts of lower priority, and the * only way to get out will be via guest exceptions. * Naturally, we want to avoid this. +* +* local_daif_mask() already sets GIC_PRIO_PSR_I_SET, we just need a +* dsb to ensure the redistributor is forwards EL2 IRQs to the CPU. */ -if (system_uses_irq_prio_masking ()) { -gic_write_pmr (GIC_PRIO_IRQON ); +if (system_uses_irq_prio_masking ())dsb (sy); - } }static inline void kvm_arm_vhe_guest_exit (void )
arch/arm64/include/asm/ptrace.h +8 -2
@@ -35,9 +35,15 @@* means masking more IRQs (or at least that the same IRQs remain masked). * * To mask interrupts, we clear the most significant bit of PMR. +* +* Some code sections either automatically switch back to PSR.I or explicitly +* require to not use priority masking. If bit GIC_PRIO_PSR_I_SET is included +* in the the priority mask, it indicates that PSR.I should be set and +* interrupt disabling temporarily does not rely on IRQ priorities. */ -#define GIC_PRIO_IRQON 0xf0 -#define GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80) +#define GIC_PRIO_IRQON 0xc0 +#define GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80) +#define GIC_PRIO_PSR_I_SET (1 << 4)/* Additional SPSR bits not exposed in the UABI */ #define PSR_IL_BIT (1 << 20)
arch/arm64/kernel/entry.S +33 -5
@@ -258,6 +258,7 @@ alternative_else_nop_endif /* * Registers that may be useful after this macro is invoked: * + * x20 - ICC_PMR_EL1 * x21 - aborted SP * x22 - aborted PC * x23 - aborted PSTATE
@@ -449,6 +450,24 @@ alternative_endif .endm #endif + .macro gic_prio_kentry_setup, tmp:req +#ifdef CONFIG_ARM64_PSEUDO_NMI + alternative_if ARM64_HAS_IRQ_PRIO_MASKING + mov \tmp, #(GIC_PRIO_PSR_I_SET | GIC_PRIO_IRQON) + msr_s SYS_ICC_PMR_EL1, \tmp + alternative_else_nop_endif +#endif + .endm + + .macro gic_prio_irq_setup, pmr:req, tmp:req +#ifdef CONFIG_ARM64_PSEUDO_NMI + alternative_if ARM64_HAS_IRQ_PRIO_MASKING + orr \tmp, \pmr, #GIC_PRIO_PSR_I_SET + msr_s SYS_ICC_PMR_EL1, \tmp + alternative_else_nop_endif +#endif + .endm + .text /*
@@ -627,6 +646,7 @@ el1_dbg: cmp x24, #ESR_ELx_EC_BRK64 // if BRK64 cinc x24, x24, eq // set bit '0' tbz x24, #0, el1_inv // EL1 only + gic_prio_kentry_setup tmp=x3 mrs x0, far_el1 mov x2, sp // struct pt_regs bl do_debug_exception
@@ -644,12 +664,10 @@ ENDPROC(el1_sync) .align 6 el1_irq: kernel_entry 1 + gic_prio_irq_setup pmr=x20, tmp=x1 enable_da_f #ifdef CONFIG_ARM64_PSEUDO_NMI -alternative_if ARM64_HAS_IRQ_PRIO_MASKING - ldr x20, [sp, #S_PMR_SAVE] -alternative_else_nop_endif test_irqs_unmasked res=x0, pmr=x20 cbz x0, 1f bl asm_nmi_enter
@@ -679,8 +697,9 @@ alternative_else_nop_endif #ifdef CONFIG_ARM64_PSEUDO_NMI /* - * if IRQs were disabled when we received the interrupt, we have an NMI - * and we are not re-enabling interrupt upon eret. Skip tracing. + * When using IRQ priority masking, we can get spurious interrupts while + * PMR is set to GIC_PRIO_IRQOFF. An NMI might also have occurred in a + * section with interrupts disabled. Skip tracing in those cases. */ test_irqs_unmasked res=x0, pmr=x20 cbz x0, 1f
@@ -809,6 +828,7 @@ el0_ia: * Instruction abort handling */ mrs x26, far_el1 + gic_prio_kentry_setup tmp=x0 enable_da_f #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off
@@ -854,6 +874,7 @@ el0_sp_pc: * Stack or PC alignment exception handling */ mrs x26, far_el1 + gic_prio_kentry_setup tmp=x0 enable_da_f #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off
@@ -888,6 +909,7 @@ el0_dbg: * Debug exception handling */ tbnz x24, #0, el0_inv // EL0 only + gic_prio_kentry_setup tmp=x3 mrs x0, far_el1 mov x1, x25 mov x2, sp
@@ -909,7 +931,9 @@ ENDPROC(el0_sync) el0_irq: kernel_entry 0 el0_irq_naked: + gic_prio_irq_setup pmr=x20, tmp=x0 enable_da_f + #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif
@@ -931,6 +955,7 @@ ENDPROC(el0_irq) el1_error: kernel_entry 1 mrs x1, esr_el1 + gic_prio_kentry_setup tmp=x2 enable_dbg mov x0, sp bl do_serror
@@ -941,6 +966,7 @@ el0_error: kernel_entry 0 el0_error_naked: mrs x1, esr_el1 + gic_prio_kentry_setup tmp=x2 enable_dbg mov x0, sp bl do_serror
@@ -965,6 +991,7 @@ work_pending: */ ret_to_user: disable_daif + gic_prio_kentry_setup tmp=x3 ldr x1, [tsk, #TSK_TI_FLAGS] and x2, x1, #_TIF_WORK_MASK cbnz x2, work_pending
@@ -981,6 +1008,7 @@ ENDPROC(ret_to_user) */ .align 6 el0_svc: + gic_prio_kentry_setup tmp=x1 mov x0, sp bl el0_svc_handler b ret_to_user
arch/arm64/kernel/process.c +1 -1
@@ -94,7 +94,7 @@ static void __cpu_do_idle_irqprio(void)* be raised. */ pmr =gic_read_pmr (); -gic_write_pmr (GIC_PRIO_IRQON ); +gic_write_pmr (GIC_PRIO_IRQON |GIC_PRIO_PSR_I_SET );__cpu_do_idle ();
arch/arm64/kernel/smp.c +5 -3
@@ -192,11 +192,13 @@ static void init_gic_priority_masking(void)WARN_ON (!(cpuflags &PSR_I_BIT )); -gic_write_pmr (GIC_PRIO_IRQOFF ); -/* We can only unmask PSR.I if we can take aborts */ -if (!(cpuflags &PSR_A_BIT )) +if (!(cpuflags &PSR_A_BIT )) { +gic_write_pmr (GIC_PRIO_IRQOFF );write_sysreg (cpuflags & ~PSR_I_BIT , daif); + }else { +gic_write_pmr (GIC_PRIO_IRQON |GIC_PRIO_PSR_I_SET ); + } }/*
arch/arm64/kvm/hyp/switch.c +1 -1
@@ -615,7 +615,7 @@ int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)* Naturally, we want to avoid this. */ if (system_uses_irq_prio_masking ()) { -gic_write_pmr (GIC_PRIO_IRQON ); +gic_write_pmr (GIC_PRIO_IRQON |GIC_PRIO_PSR_I_SET );dsb (sy); }