1129198Scognet/* $NetBSD: fiq.c,v 1.5 2002/04/03 23:33:27 thorpej Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 5129198Scognet * All rights reserved. 6129198Scognet * 7129198Scognet * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8129198Scognet * 9129198Scognet * Redistribution and use in source and binary forms, with or without 10129198Scognet * modification, are permitted provided that the following conditions 11129198Scognet * are met: 12129198Scognet * 1. Redistributions of source code must retain the above copyright 13129198Scognet * notice, this list of conditions and the following disclaimer. 14129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 15129198Scognet * notice, this list of conditions and the following disclaimer in the 16129198Scognet * documentation and/or other materials provided with the distribution. 17129198Scognet * 3. All advertising materials mentioning features or use of this software 18129198Scognet * must display the following acknowledgement: 19129198Scognet * This product includes software developed for the NetBSD Project by 20129198Scognet * Wasabi Systems, Inc. 21129198Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22129198Scognet * or promote products derived from this software without specific prior 23129198Scognet * written permission. 24129198Scognet * 25129198Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27129198Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28129198Scognet * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29129198Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30129198Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31129198Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32129198Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33129198Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34129198Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35129198Scognet * POSSIBILITY OF SUCH DAMAGE. 36129198Scognet */ 37129198Scognet 38129198Scognet#include <sys/cdefs.h> 39129198Scognet__FBSDID("$FreeBSD$"); 40129198Scognet 41129198Scognet#include <sys/param.h> 42129198Scognet#include <sys/systm.h> 43129198Scognet 44271398Sandrew#include <machine/armreg.h> 45129198Scognet#include <machine/cpufunc.h> 46129198Scognet#include <machine/fiq.h> 47129198Scognet#include <vm/vm.h> 48129198Scognet#include <machine/pcb.h> 49129198Scognet#include <vm/pmap.h> 50143682Sjmg#include <machine/cpu.h> 51129198Scognet 52129198ScognetTAILQ_HEAD(, fiqhandler) fiqhandler_stack = 53129198Scognet TAILQ_HEAD_INITIALIZER(fiqhandler_stack); 54129198Scognet 55262980Sianextern char *fiq_nullhandler_code; 56262980Sianextern uint32_t fiq_nullhandler_size; 57129198Scognet 58129198Scognet/* 59129198Scognet * fiq_installhandler: 60129198Scognet * 61129198Scognet * Actually install the FIQ handler down at the FIQ vector. 62283366Sandrew * 63262980Sian * The FIQ vector is fixed by the hardware definition as the 64262980Sian * seventh 32-bit word in the vector page. 65129198Scognet * 66129198Scognet * Note: If the FIQ is invoked via an extra layer of 67129198Scognet * indirection, the actual FIQ code store lives in the 68129198Scognet * data segment, so there is no need to manipulate 69129198Scognet * the vector page's protection. 70129198Scognet */ 71129198Scognetstatic void 72129198Scognetfiq_installhandler(void *func, size_t size) 73129198Scognet{ 74262980Sian const uint32_t fiqvector = 7 * sizeof(uint32_t); 75262980Sian 76295696Sskra#if __ARM_ARCH < 6 && !defined(__ARM_FIQ_INDIRECT) 77129198Scognet vector_page_setprot(VM_PROT_READ|VM_PROT_WRITE); 78129198Scognet#endif 79129198Scognet 80262980Sian memcpy((void *)(vector_page + fiqvector), func, size); 81129198Scognet 82295696Sskra#if __ARM_ARCH < 6 && !defined(__ARM_FIQ_INDIRECT) 83129198Scognet vector_page_setprot(VM_PROT_READ); 84129198Scognet#endif 85295319Smmel icache_sync((vm_offset_t) fiqvector, size); 86129198Scognet} 87129198Scognet 88129198Scognet/* 89129198Scognet * fiq_claim: 90129198Scognet * 91129198Scognet * Claim the FIQ vector. 92129198Scognet */ 93129198Scognetint 94129198Scognetfiq_claim(struct fiqhandler *fh) 95129198Scognet{ 96129198Scognet struct fiqhandler *ofh; 97129198Scognet u_int oldirqstate; 98129198Scognet int error = 0; 99129198Scognet 100129198Scognet if (fh->fh_size > 0x100) 101129198Scognet return (EFBIG); 102129198Scognet 103271398Sandrew oldirqstate = disable_interrupts(PSR_F); 104129198Scognet 105129198Scognet if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 106129198Scognet if ((ofh->fh_flags & FH_CANPUSH) == 0) { 107129198Scognet error = EBUSY; 108129198Scognet goto out; 109129198Scognet } 110129198Scognet 111129198Scognet /* Save the previous FIQ handler's registers. */ 112129198Scognet if (ofh->fh_regs != NULL) 113129198Scognet fiq_getregs(ofh->fh_regs); 114129198Scognet } 115129198Scognet 116129198Scognet /* Set FIQ mode registers to ours. */ 117129198Scognet if (fh->fh_regs != NULL) 118129198Scognet fiq_setregs(fh->fh_regs); 119129198Scognet 120129198Scognet TAILQ_INSERT_HEAD(&fiqhandler_stack, fh, fh_list); 121129198Scognet 122129198Scognet /* Now copy the actual handler into place. */ 123129198Scognet fiq_installhandler(fh->fh_func, fh->fh_size); 124129198Scognet 125129198Scognet /* Make sure FIQs are enabled when we return. */ 126271398Sandrew oldirqstate &= ~PSR_F; 127129198Scognet 128129198Scognet out: 129129198Scognet restore_interrupts(oldirqstate); 130129198Scognet return (error); 131129198Scognet} 132129198Scognet 133129198Scognet/* 134129198Scognet * fiq_release: 135129198Scognet * 136129198Scognet * Release the FIQ vector. 137129198Scognet */ 138129198Scognetvoid 139129198Scognetfiq_release(struct fiqhandler *fh) 140129198Scognet{ 141129198Scognet u_int oldirqstate; 142129198Scognet struct fiqhandler *ofh; 143129198Scognet 144271398Sandrew oldirqstate = disable_interrupts(PSR_F); 145129198Scognet 146129198Scognet /* 147129198Scognet * If we are the currently active FIQ handler, then we 148129198Scognet * need to save our registers and pop the next one back 149129198Scognet * into the vector. 150129198Scognet */ 151129198Scognet if (fh == TAILQ_FIRST(&fiqhandler_stack)) { 152129198Scognet if (fh->fh_regs != NULL) 153129198Scognet fiq_getregs(fh->fh_regs); 154129198Scognet TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 155129198Scognet if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 156129198Scognet if (ofh->fh_regs != NULL) 157129198Scognet fiq_setregs(ofh->fh_regs); 158129198Scognet fiq_installhandler(ofh->fh_func, ofh->fh_size); 159129198Scognet } 160129198Scognet } else 161129198Scognet TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 162129198Scognet 163129198Scognet if (TAILQ_FIRST(&fiqhandler_stack) == NULL) { 164129198Scognet /* Copy the NULL handler back down into the vector. */ 165262980Sian fiq_installhandler(fiq_nullhandler_code, fiq_nullhandler_size); 166129198Scognet 167129198Scognet /* Make sure FIQs are disabled when we return. */ 168271398Sandrew oldirqstate |= PSR_F; 169129198Scognet } 170129198Scognet 171129198Scognet restore_interrupts(oldirqstate); 172129198Scognet} 173