1 /* $NetBSD: fiq.c,v 1.10 2020/02/24 12:08:08 rin Exp $ */ 2 3 /* 4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: fiq.c,v 1.10 2020/02/24 12:08:08 rin Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 44 #include <arm/cpufunc.h> 45 #include <arm/fiq.h> 46 47 #include <uvm/uvm_extern.h> 48 49 TAILQ_HEAD(, fiqhandler) fiqhandler_stack = 50 TAILQ_HEAD_INITIALIZER(fiqhandler_stack); 51 52 extern char fiqvector[]; 53 extern char fiq_nullhandler[], fiq_nullhandler_end[]; 54 55 #define IRQ_BIT I32_bit 56 #define FIQ_BIT F32_bit 57 58 #ifndef ARM_HAS_VBAR 59 /* 60 * fiq_installhandler: 61 * 62 * Actually install the FIQ handler down at the FIQ vector. 63 * 64 * Note: If the FIQ is invoked via an extra layer of 65 * indirection, the actual FIQ code store lives in the 66 * data segment, so there is no need to manipulate 67 * the vector page's protection. 68 */ 69 static void 70 fiq_installhandler(void *func, size_t size) 71 { 72 #if !defined(__ARM_FIQ_INDIRECT) 73 vector_page_setprot(VM_PROT_READ|VM_PROT_WRITE); 74 #endif 75 76 memcpy(fiqvector, func, size); 77 78 #if !defined(__ARM_FIQ_INDIRECT) 79 vector_page_setprot(VM_PROT_READ); 80 #endif 81 cpu_icache_sync_range((vaddr_t) fiqvector, size); 82 } 83 84 /* 85 * fiq_claim: 86 * 87 * Claim the FIQ vector. 88 */ 89 int 90 fiq_claim(struct fiqhandler *fh) 91 { 92 struct fiqhandler *ofh; 93 u_int oldirqstate; 94 int error = 0; 95 96 if (fh->fh_size > 0x100) 97 return (EFBIG); 98 99 oldirqstate = disable_interrupts(FIQ_BIT); 100 101 if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 102 if ((ofh->fh_flags & FH_CANPUSH) == 0) { 103 error = EBUSY; 104 goto out; 105 } 106 107 /* Save the previous FIQ handler's registers. */ 108 if (ofh->fh_regs != NULL) 109 fiq_getregs(ofh->fh_regs); 110 } 111 112 /* Set FIQ mode registers to ours. */ 113 if (fh->fh_regs != NULL) 114 fiq_setregs(fh->fh_regs); 115 116 TAILQ_INSERT_HEAD(&fiqhandler_stack, fh, fh_list); 117 118 /* Now copy the actual handler into place. */ 119 fiq_installhandler(fh->fh_func, fh->fh_size); 120 121 /* Make sure FIQs are enabled when we return. */ 122 oldirqstate &= ~FIQ_BIT; 123 124 out: 125 restore_interrupts(oldirqstate); 126 return (error); 127 } 128 129 /* 130 * fiq_release: 131 * 132 * Release the FIQ vector. 133 */ 134 void 135 fiq_release(struct fiqhandler *fh) 136 { 137 u_int oldirqstate; 138 struct fiqhandler *ofh; 139 140 oldirqstate = disable_interrupts(FIQ_BIT); 141 142 /* 143 * If we are the currently active FIQ handler, then we 144 * need to save our registers and pop the next one back 145 * into the vector. 146 */ 147 if (fh == TAILQ_FIRST(&fiqhandler_stack)) { 148 if (fh->fh_regs != NULL) 149 fiq_getregs(fh->fh_regs); 150 TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 151 if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 152 if (ofh->fh_regs != NULL) 153 fiq_setregs(ofh->fh_regs); 154 fiq_installhandler(ofh->fh_func, ofh->fh_size); 155 } 156 } else 157 TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 158 159 if (TAILQ_FIRST(&fiqhandler_stack) == NULL) { 160 /* Copy the NULL handler back down into the vector. */ 161 fiq_installhandler(fiq_nullhandler, 162 (size_t)(fiq_nullhandler_end - fiq_nullhandler)); 163 164 /* Make sure FIQs are disabled when we return. */ 165 oldirqstate |= FIQ_BIT; 166 } 167 168 oldirqstate &= ~FIQ_BIT; 169 restore_interrupts(oldirqstate); 170 } 171 #endif /* !ARM_HAS_VBAR */ 172