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 44129198Scognet#include <machine/cpufunc.h> 45129198Scognet#include <machine/fiq.h> 46129198Scognet#include <vm/vm.h> 47129198Scognet#include <machine/pcb.h> 48129198Scognet#include <vm/pmap.h> 49143682Sjmg#include <machine/cpu.h> 50129198Scognet 51129198ScognetTAILQ_HEAD(, fiqhandler) fiqhandler_stack = 52129198Scognet TAILQ_HEAD_INITIALIZER(fiqhandler_stack); 53129198Scognet 54129198Scognetextern char fiqvector[]; 55129198Scognetextern char fiq_nullhandler[], fiq_nullhandler_end[]; 56129198Scognet 57129198Scognet#define IRQ_BIT I32_bit 58129198Scognet#define FIQ_BIT F32_bit 59129198Scognet 60129198Scognet/* 61129198Scognet * fiq_installhandler: 62129198Scognet * 63129198Scognet * Actually install the FIQ handler down at the FIQ vector. 64129198Scognet * 65129198Scognet * Note: If the FIQ is invoked via an extra layer of 66129198Scognet * indirection, the actual FIQ code store lives in the 67129198Scognet * data segment, so there is no need to manipulate 68129198Scognet * the vector page's protection. 69129198Scognet */ 70129198Scognetstatic void 71129198Scognetfiq_installhandler(void *func, size_t size) 72129198Scognet{ 73129198Scognet#if !defined(__ARM_FIQ_INDIRECT) 74129198Scognet vector_page_setprot(VM_PROT_READ|VM_PROT_WRITE); 75129198Scognet#endif 76129198Scognet 77143682Sjmg memcpy(vector_page + fiqvector, func, size); 78129198Scognet 79129198Scognet#if !defined(__ARM_FIQ_INDIRECT) 80129198Scognet vector_page_setprot(VM_PROT_READ); 81129198Scognet cpu_icache_sync_range((vm_offset_t) fiqvector, size); 82129198Scognet#endif 83129198Scognet} 84129198Scognet 85129198Scognet/* 86129198Scognet * fiq_claim: 87129198Scognet * 88129198Scognet * Claim the FIQ vector. 89129198Scognet */ 90129198Scognetint 91129198Scognetfiq_claim(struct fiqhandler *fh) 92129198Scognet{ 93129198Scognet struct fiqhandler *ofh; 94129198Scognet u_int oldirqstate; 95129198Scognet int error = 0; 96129198Scognet 97129198Scognet if (fh->fh_size > 0x100) 98129198Scognet return (EFBIG); 99129198Scognet 100129198Scognet oldirqstate = disable_interrupts(FIQ_BIT); 101129198Scognet 102129198Scognet if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 103129198Scognet if ((ofh->fh_flags & FH_CANPUSH) == 0) { 104129198Scognet error = EBUSY; 105129198Scognet goto out; 106129198Scognet } 107129198Scognet 108129198Scognet /* Save the previous FIQ handler's registers. */ 109129198Scognet if (ofh->fh_regs != NULL) 110129198Scognet fiq_getregs(ofh->fh_regs); 111129198Scognet } 112129198Scognet 113129198Scognet /* Set FIQ mode registers to ours. */ 114129198Scognet if (fh->fh_regs != NULL) 115129198Scognet fiq_setregs(fh->fh_regs); 116129198Scognet 117129198Scognet TAILQ_INSERT_HEAD(&fiqhandler_stack, fh, fh_list); 118129198Scognet 119129198Scognet /* Now copy the actual handler into place. */ 120129198Scognet fiq_installhandler(fh->fh_func, fh->fh_size); 121129198Scognet 122129198Scognet /* Make sure FIQs are enabled when we return. */ 123129198Scognet oldirqstate &= ~FIQ_BIT; 124129198Scognet 125129198Scognet out: 126129198Scognet restore_interrupts(oldirqstate); 127129198Scognet return (error); 128129198Scognet} 129129198Scognet 130129198Scognet/* 131129198Scognet * fiq_release: 132129198Scognet * 133129198Scognet * Release the FIQ vector. 134129198Scognet */ 135129198Scognetvoid 136129198Scognetfiq_release(struct fiqhandler *fh) 137129198Scognet{ 138129198Scognet u_int oldirqstate; 139129198Scognet struct fiqhandler *ofh; 140129198Scognet 141129198Scognet oldirqstate = disable_interrupts(FIQ_BIT); 142129198Scognet 143129198Scognet /* 144129198Scognet * If we are the currently active FIQ handler, then we 145129198Scognet * need to save our registers and pop the next one back 146129198Scognet * into the vector. 147129198Scognet */ 148129198Scognet if (fh == TAILQ_FIRST(&fiqhandler_stack)) { 149129198Scognet if (fh->fh_regs != NULL) 150129198Scognet fiq_getregs(fh->fh_regs); 151129198Scognet TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 152129198Scognet if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 153129198Scognet if (ofh->fh_regs != NULL) 154129198Scognet fiq_setregs(ofh->fh_regs); 155129198Scognet fiq_installhandler(ofh->fh_func, ofh->fh_size); 156129198Scognet } 157129198Scognet } else 158129198Scognet TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 159129198Scognet 160129198Scognet if (TAILQ_FIRST(&fiqhandler_stack) == NULL) { 161129198Scognet /* Copy the NULL handler back down into the vector. */ 162129198Scognet fiq_installhandler(fiq_nullhandler, 163129198Scognet (size_t)(fiq_nullhandler_end - fiq_nullhandler)); 164129198Scognet 165129198Scognet /* Make sure FIQs are disabled when we return. */ 166129198Scognet oldirqstate |= FIQ_BIT; 167129198Scognet } 168129198Scognet 169129198Scognet restore_interrupts(oldirqstate); 170129198Scognet} 171