1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright (C) 2017 ARM Ltd. 4 */ 5 #ifndef __ASM_DAIFFLAGS_H 6 #define __ASM_DAIFFLAGS_H 7 8 #include <linux/irqflags.h> 9 10 #include <asm/cpufeature.h> 11 12 #define DAIF_PROCCTX 0 13 #define DAIF_PROCCTX_NOIRQ PSR_I_BIT 14 #define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT) 15 16 /* mask/save/unmask/restore all exceptions, including interrupts. */ 17 static inline void local_daif_mask(void) 18 { 19 asm volatile( 20 "msr daifset, #0xf // local_daif_mask\n" 21 : 22 : 23 : "memory"); 24 trace_hardirqs_off(); 25 } 26 27 static inline unsigned long local_daif_save(void) 28 { 29 unsigned long flags; 30 31 flags = read_sysreg(daif); 32 33 if (system_uses_irq_prio_masking()) { 34 /* If IRQs are masked with PMR, reflect it in the flags */ 35 if (read_sysreg_s(SYS_ICC_PMR_EL1) <= GIC_PRIO_IRQOFF) 36 flags |= PSR_I_BIT; 37 } 38 39 local_daif_mask(); 40 41 return flags; 42 } 43 44 static inline void local_daif_restore(unsigned long flags) 45 { 46 bool irq_disabled = flags & PSR_I_BIT; 47 48 if (!irq_disabled) { 49 trace_hardirqs_on(); 50 51 if (system_uses_irq_prio_masking()) 52 arch_local_irq_enable(); 53 } else if (!(flags & PSR_A_BIT)) { 54 /* 55 * If interrupts are disabled but we can take 56 * asynchronous errors, we can take NMIs 57 */ 58 if (system_uses_irq_prio_masking()) { 59 flags &= ~PSR_I_BIT; 60 /* 61 * There has been concern that the write to daif 62 * might be reordered before this write to PMR. 63 * From the ARM ARM DDI 0487D.a, section D1.7.1 64 * "Accessing PSTATE fields": 65 * Writes to the PSTATE fields have side-effects on 66 * various aspects of the PE operation. All of these 67 * side-effects are guaranteed: 68 * - Not to be visible to earlier instructions in 69 * the execution stream. 70 * - To be visible to later instructions in the 71 * execution stream 72 * 73 * Also, writes to PMR are self-synchronizing, so no 74 * interrupts with a lower priority than PMR is signaled 75 * to the PE after the write. 76 * 77 * So we don't need additional synchronization here. 78 */ 79 arch_local_irq_disable(); 80 } 81 } 82 83 write_sysreg(flags, daif); 84 85 if (irq_disabled) 86 trace_hardirqs_off(); 87 } 88 89 #endif 90