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/arch_gicv3.h> 11 #include <asm/cpufeature.h> 12 13 #define DAIF_PROCCTX 0 14 #define DAIF_PROCCTX_NOIRQ PSR_I_BIT 15 #define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT) 16 17 /* mask/save/unmask/restore all exceptions, including interrupts. */ 18 static inline void local_daif_mask(void) 19 { 20 WARN_ON(system_has_prio_mask_debugging() && 21 (read_sysreg_s(SYS_ICC_PMR_EL1) == (GIC_PRIO_IRQOFF | 22 GIC_PRIO_PSR_I_SET))); 23 24 asm volatile( 25 "msr daifset, #0xf // local_daif_mask\n" 26 : 27 : 28 : "memory"); 29 30 /* Don't really care for a dsb here, we don't intend to enable IRQs */ 31 if (system_uses_irq_prio_masking()) 32 gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET); 33 34 trace_hardirqs_off(); 35 } 36 37 static inline unsigned long local_daif_save(void) 38 { 39 unsigned long flags; 40 41 flags = read_sysreg(daif); 42 43 if (system_uses_irq_prio_masking()) { 44 /* If IRQs are masked with PMR, reflect it in the flags */ 45 if (read_sysreg_s(SYS_ICC_PMR_EL1) != GIC_PRIO_IRQON) 46 flags |= PSR_I_BIT; 47 } 48 49 local_daif_mask(); 50 51 return flags; 52 } 53 54 static inline void local_daif_restore(unsigned long flags) 55 { 56 bool irq_disabled = flags & PSR_I_BIT; 57 58 WARN_ON(system_has_prio_mask_debugging() && 59 !(read_sysreg(daif) & PSR_I_BIT)); 60 61 if (!irq_disabled) { 62 trace_hardirqs_on(); 63 64 if (system_uses_irq_prio_masking()) { 65 gic_write_pmr(GIC_PRIO_IRQON); 66 dsb(sy); 67 } 68 } else if (system_uses_irq_prio_masking()) { 69 u64 pmr; 70 71 if (!(flags & PSR_A_BIT)) { 72 /* 73 * If interrupts are disabled but we can take 74 * asynchronous errors, we can take NMIs 75 */ 76 flags &= ~PSR_I_BIT; 77 pmr = GIC_PRIO_IRQOFF; 78 } else { 79 pmr = GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET; 80 } 81 82 /* 83 * There has been concern that the write to daif 84 * might be reordered before this write to PMR. 85 * From the ARM ARM DDI 0487D.a, section D1.7.1 86 * "Accessing PSTATE fields": 87 * Writes to the PSTATE fields have side-effects on 88 * various aspects of the PE operation. All of these 89 * side-effects are guaranteed: 90 * - Not to be visible to earlier instructions in 91 * the execution stream. 92 * - To be visible to later instructions in the 93 * execution stream 94 * 95 * Also, writes to PMR are self-synchronizing, so no 96 * interrupts with a lower priority than PMR is signaled 97 * to the PE after the write. 98 * 99 * So we don't need additional synchronization here. 100 */ 101 gic_write_pmr(pmr); 102 } 103 104 write_sysreg(flags, daif); 105 106 if (irq_disabled) 107 trace_hardirqs_off(); 108 } 109 110 #endif 111