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