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