fiq.c revision 283366
1/* $NetBSD: fiq.c,v 1.5 2002/04/03 23:33:27 thorpej 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__FBSDID("$FreeBSD: head/sys/arm/arm/fiq.c 283366 2015-05-24 12:20:11Z andrew $"); 40 41#include <sys/param.h> 42#include <sys/systm.h> 43 44#include <machine/armreg.h> 45#include <machine/cpufunc.h> 46#include <machine/fiq.h> 47#include <vm/vm.h> 48#include <machine/pcb.h> 49#include <vm/pmap.h> 50#include <machine/cpu.h> 51 52TAILQ_HEAD(, fiqhandler) fiqhandler_stack = 53 TAILQ_HEAD_INITIALIZER(fiqhandler_stack); 54 55extern char *fiq_nullhandler_code; 56extern uint32_t fiq_nullhandler_size; 57 58/* 59 * fiq_installhandler: 60 * 61 * Actually install the FIQ handler down at the FIQ vector. 62 * 63 * The FIQ vector is fixed by the hardware definition as the 64 * seventh 32-bit word in the vector page. 65 * 66 * Note: If the FIQ is invoked via an extra layer of 67 * indirection, the actual FIQ code store lives in the 68 * data segment, so there is no need to manipulate 69 * the vector page's protection. 70 */ 71static void 72fiq_installhandler(void *func, size_t size) 73{ 74 const uint32_t fiqvector = 7 * sizeof(uint32_t); 75 76#if !defined(__ARM_FIQ_INDIRECT) 77 vector_page_setprot(VM_PROT_READ|VM_PROT_WRITE); 78#endif 79 80 memcpy((void *)(vector_page + fiqvector), func, size); 81 82#if !defined(__ARM_FIQ_INDIRECT) 83 vector_page_setprot(VM_PROT_READ); 84 cpu_icache_sync_range((vm_offset_t) fiqvector, size); 85#endif 86} 87 88/* 89 * fiq_claim: 90 * 91 * Claim the FIQ vector. 92 */ 93int 94fiq_claim(struct fiqhandler *fh) 95{ 96 struct fiqhandler *ofh; 97 u_int oldirqstate; 98 int error = 0; 99 100 if (fh->fh_size > 0x100) 101 return (EFBIG); 102 103 oldirqstate = disable_interrupts(PSR_F); 104 105 if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 106 if ((ofh->fh_flags & FH_CANPUSH) == 0) { 107 error = EBUSY; 108 goto out; 109 } 110 111 /* Save the previous FIQ handler's registers. */ 112 if (ofh->fh_regs != NULL) 113 fiq_getregs(ofh->fh_regs); 114 } 115 116 /* Set FIQ mode registers to ours. */ 117 if (fh->fh_regs != NULL) 118 fiq_setregs(fh->fh_regs); 119 120 TAILQ_INSERT_HEAD(&fiqhandler_stack, fh, fh_list); 121 122 /* Now copy the actual handler into place. */ 123 fiq_installhandler(fh->fh_func, fh->fh_size); 124 125 /* Make sure FIQs are enabled when we return. */ 126 oldirqstate &= ~PSR_F; 127 128 out: 129 restore_interrupts(oldirqstate); 130 return (error); 131} 132 133/* 134 * fiq_release: 135 * 136 * Release the FIQ vector. 137 */ 138void 139fiq_release(struct fiqhandler *fh) 140{ 141 u_int oldirqstate; 142 struct fiqhandler *ofh; 143 144 oldirqstate = disable_interrupts(PSR_F); 145 146 /* 147 * If we are the currently active FIQ handler, then we 148 * need to save our registers and pop the next one back 149 * into the vector. 150 */ 151 if (fh == TAILQ_FIRST(&fiqhandler_stack)) { 152 if (fh->fh_regs != NULL) 153 fiq_getregs(fh->fh_regs); 154 TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 155 if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 156 if (ofh->fh_regs != NULL) 157 fiq_setregs(ofh->fh_regs); 158 fiq_installhandler(ofh->fh_func, ofh->fh_size); 159 } 160 } else 161 TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 162 163 if (TAILQ_FIRST(&fiqhandler_stack) == NULL) { 164 /* Copy the NULL handler back down into the vector. */ 165 fiq_installhandler(fiq_nullhandler_code, fiq_nullhandler_size); 166 167 /* Make sure FIQs are disabled when we return. */ 168 oldirqstate |= PSR_F; 169 } 170 171 restore_interrupts(oldirqstate); 172} 173