⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 synth_intr.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 4 页
字号:
//=============================================================================////      synth_intr.c////      Interrupt and clock code for the Linux synthetic target.////=============================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 2002 Bart Veer// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//=============================================================================//#####DESCRIPTIONBEGIN####//// Author(s):    bartv// Contributors: bartv, asl// Date:         2001-03-30// Purpose:      Implement the interrupt subsystem for the synthetic target//####DESCRIPTIONEND####//=============================================================================// sigprocmask handling.//// In the synthetic target interrupts and exceptions are based around// POSIX sighandlers. When the clock ticks a SIGALRM signal is raised.// When the I/O auxiliary wants to raise some other interrupt, it// sends a SIGIO signal. When an exception occurs this results in// signals like SIGILL and SIGSEGV. This implies an implementation// where the VSR is the signal handler. Disabling interrupts would// then mean using sigprocmask() to block certain signals, and// enabling interrupts means unblocking those signals.//// However there are a few problems. One of these is performance: some// bits of the system such as buffered tracing make very extensive use// of enabling and disabling interrupts, so making a sigprocmask// system call each time adds a lot of overhead. More seriously, there// is a subtle discrepancy between POSIX signal handling and hardware// interrupts. Signal handlers are expected to return, and then the// system automatically passes control back to the foreground thread.// In the process, the sigprocmask is manipulated before invoking the// signal handler and restored afterwards. Interrupt handlers are// different: it is quite likely that an interrupt results in another// eCos thread being activated, so the signal handler does not// actually return until the interrupted thread gets another chance to// run. //// The second problem can be addressed by making the sigprocmask part// of the thread state, saving and restoring it as part of a context// switch (c.f. siglongjmp()). This matches quite nicely onto typical// real hardware, where there might be a flag inside some control// register that controls whether or not interrupts are enabled.// However this adds more system calls to context switch overhead.//// The alternative approach is to implement interrupt enabling and// disabling in software. The sigprocmask is manipulated only once,// during initialization, such that certain signals are allowed// through and others are blocked. When a signal is raised the signal// handler will always be invoked, but it will decide in software// whether or not the signal should be processed immediately. This// alternative approach does not correspond particularly well with// real hardware: effectively the VSR is always allowed to run.// However for typical applications this will not really matter, and// the performance gains outweigh the discrepancy.//// Nested interrupts and interrupt priorities can be implemented in// software, specifically by manipulating the current mask of blocked// interrupts. This is not currently implemented.//// At first glance it might seem that an interrupt stack could be// implemented trivially using sigaltstack. This does not quite work:// signal handlers do not always return immediately, so the system// does not get a chance to clean up the signal handling stack. A// separate interrupt stack is possible but would have to be// implemented here, in software, e.g. by having the signal handler// invoke the VSR on that stack. Unfortunately the system may have// pushed quite a lot of state on to the current stack already when// raising the signal, so things could get messy.// ----------------------------------------------------------------------------#include <pkgconf/hal.h>#include <pkgconf/hal_synth.h>// There are various dependencies on the kernel, e.g. how exceptions// should be handled.#include <pkgconf/system.h>#ifdef CYGPKG_KERNEL# include <pkgconf/kernel.h>#endif#include <cyg/infra/cyg_type.h>         // base types#include <cyg/infra/diag.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_intr.h>#include <cyg/hal/hal_io.h>#include <cyg/infra/cyg_ass.h>          // Assertions are safe in the synthetic target#include "synth_protocol.h"// ----------------------------------------------------------------------------// Statics.// Are interrupts currently enabled?volatile cyg_bool_t hal_interrupts_enabled = false;// These flags are updated by the signal handler when a signal comes in// and interrupts are disabled.static volatile cyg_bool_t  synth_sigio_pending         = false;static volatile cyg_bool_t  synth_sigalrm_pending       = false;// The current VSR, to be invoked by the signal handler. This allows// application code to install an alternative VSR, without that VSR// having to check for interrupts being disabled and updating the// pending flags. Effectively, the VSR is only invoked when interrupts// are enabled.static void (*synth_VSR)(void)                          = (void (*)(void)) 0;// The current ISR status and mask registers, or rather software// emulations thereof. These are not static since application-specific// VSRs may want to examine/manipulate these. They are also not// exported in any header file, forcing people writing such VSRs to// know what they are doing.volatile cyg_uint32 synth_pending_isrs      = 0;volatile cyg_uint32 synth_masked_isrs       = 0xFFFFFFFF;// The vector of interrupt handlers.typedef struct synth_isr_handler {    cyg_ISR_t*          isr;    CYG_ADDRWORD        data;    CYG_ADDRESS         obj;    cyg_priority_t      pri;} synth_isr_handler;static synth_isr_handler synth_isr_handlers[CYGNUM_HAL_ISR_COUNT];static void  synth_alrm_sighandler(int);static void  synth_io_sighandler(int);// ----------------------------------------------------------------------------// Basic ISR and VSR handling.// The default ISR handler. The system should never receive an interrupt it// does not know how to handle.static cyg_uint32synth_default_isr(cyg_vector_t vector, cyg_addrword_t data){    CYG_UNUSED_PARAM(cyg_vector_t, vector);    CYG_UNUSED_PARAM(cyg_addrword_t, data);    CYG_FAIL("Default isr handler should never get invoked");    return CYG_ISR_HANDLED;}// The VSR is invoked//  1) directly by a SIGALRM or SIGIO signal handler, if interrupts//     were enabled.//  2) indirectly by hal_enable_interrupts(), if a signal happened//     while interrupts were disabled. hal_enable_interrupts()//     will have re-invoked the signal handler.//// On entry interrupts are disabled, and there should be one or more// pending ISRs which are not masked off.//// The implementation is as per the HAL specification, where// applicable.static voidsynth_default_vsr(void){    int         isr_vector;    cyg_uint32  isr_result;    CYG_ASSERT(!hal_interrupts_enabled, "VSRs should only be invoked when interrupts are disabled");    CYG_ASSERT(0 != (synth_pending_isrs & ~synth_masked_isrs), "VSRs should only be invoked when an interrupt is pending");    // No need to save the cpu state. Either we are in a signal    // handler and the system has done that for us, or we are called    // synchronously via enable_interrupts.    // Increment the kernel scheduler lock, if the kernel is present.    // This prevents context switching while interrupt handling is in    // progress.#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT    cyg_scheduler_lock();#endif    // Do not switch to an interrupt stack - functionality is not    // implemented    // Do not allow nested interrupts - functionality is not    // implemented.    // Decode the actual external interrupt being delivered. This is    // determined from the pending and masked variables. Only one isr    // source can be handled here, since interrupt_end must be invoked    // with details of that interrupt. Multiple pending interrupts    // will be handled by a recursive call     HAL_LSBIT_INDEX(isr_vector, (synth_pending_isrs & ~synth_masked_isrs));    CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= isr_vector) && (isr_vector <= CYGNUM_HAL_ISR_MAX), "ISR vector must be valid");    isr_result = (*synth_isr_handlers[isr_vector].isr)(isr_vector, synth_isr_handlers[isr_vector].data);    // Do not switch back from the interrupt stack, there isn't one.        // Interrupts were not enabled before, so they must be enabled    // now. This may result in a recursive invocation if other IRQs    // are still pending. The ISR should have either acknowledged or    // masked the current interrupt source, to prevent a recursive    // call for the current interrupt.    hal_enable_interrupts();    // Now call interrupt_end() with the result of the isr and the    // ISR's object This may return straightaway, or it may result in    // a context switch to another thread. In the latter case, when    // the current thread is reactivated we end up back here. The    // third argument should be a pointer to the saved state, but that    // is only relevant for thread-aware debugging which is not yet    // supported by the synthetic target.    {        extern void interrupt_end(cyg_uint32, CYG_ADDRESS, HAL_SavedRegisters*);        interrupt_end(isr_result, synth_isr_handlers[isr_vector].obj, (HAL_SavedRegisters*) 0);    }    // Restore machine state and return to the interrupted thread.    // That requires no effort here.}// Enabling interrupts. If a SIGALRM or SIGIO arrived at an inconvenient// time, e.g. when already interacting with the auxiliary, then these// will have been left pending and must be serviced now. Next, enabling// interrupts means checking the interrupt pending and mask registers// and seeing if the VSR should be invoked.voidhal_enable_interrupts(void){    hal_interrupts_enabled = true;    if (synth_sigalrm_pending) {        synth_sigalrm_pending = false;        synth_alrm_sighandler(CYG_HAL_SYS_SIGALRM);    }    if (synth_sigio_pending) {        synth_sigio_pending = false;        synth_io_sighandler(CYG_HAL_SYS_SIGIO);    }    // The interrupt mask "register" may have been modified while    // interrupts were disabled. If there are pending interrupts,    // invoke the VSR. The VSR must be invoked with interrupts    // disabled, and will return with interrupts enabled.    // An alternative implementation that might be more accurate    // is to raise a signal, e.g. SIGUSR1. That way all interrupts    // come in via the system's signal handling mechanism, and    // it might be possible to do something useful with saved contexts    // etc., facilitating thread-aware debugging.    if (0 != (synth_pending_isrs & ~synth_masked_isrs)) {        hal_interrupts_enabled = false;        (*synth_VSR)();        CYG_ASSERT( hal_interrupts_enabled, "Interrupts should still be enabled on return from the VSR");    }}// ----------------------------------------------------------------------------// Other interrupt-related routines. Mostly these just involve// updating some of the statics, but they may be called while// interrupts are still enabled so care has to be taken.cyg_bool_thal_interrupt_in_use(cyg_vector_t vec){    CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only attach to valid ISR vectors");    return synth_default_isr != synth_isr_handlers[vec].isr;}voidhal_interrupt_attach(cyg_vector_t vec, cyg_ISR_t* isr, CYG_ADDRWORD data, CYG_ADDRESS obj){    CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only attach to valid ISR vectors");    CYG_CHECK_FUNC_PTR( isr, "A valid ISR must be supplied");    // The object cannot be validated, it may be NULL if chained    // interrupts are enabled.    CYG_ASSERT( synth_isr_handlers[vec].isr == &synth_default_isr, "Only one ISR can be attached to a vector at the HAL level");    CYG_ASSERT( (false == hal_interrupts_enabled) || (0 != (synth_masked_isrs & (0x01 << vec))), "ISRs should only be attached when it is safe");    // The priority will have been installed shortly before this call.    synth_isr_handlers[vec].isr     = isr;    synth_isr_handlers[vec].data    = data;    synth_isr_handlers[vec].obj     = obj;}voidhal_interrupt_detach(cyg_vector_t vec, cyg_ISR_t* isr){    CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only detach from valid ISR vectors");    CYG_CHECK_FUNC_PTR( isr, "A valid ISR must be supplied");    CYG_ASSERT( isr != &synth_default_isr, "An ISR must be attached before it can be detached");    CYG_ASSERT( (false == hal_interrupts_enabled) || (0 != (synth_masked_isrs & (0x01 << vec))), "ISRs should only be detached when it is safe");    // The Cyg_Interrupt destructor does an unconditional detach, even if the    // isr is not currently attached.    if (isr == synth_isr_handlers[vec].isr) {        synth_isr_handlers[vec].isr     = &synth_default_isr;        synth_isr_handlers[vec].data    = (CYG_ADDRWORD) 0;        synth_isr_handlers[vec].obj     = (CYG_ADDRESS) 0;    }        // The priority is not updated here. This should be ok, if another    // isr is attached then the appropriate priority will be installed    // first.}void (*hal_vsr_get(cyg_vector_t vec))(void){    CYG_ASSERT( (CYGNUM_HAL_VSR_MIN <= vec) && (vec <= CYGNUM_HAL_VSR_MAX), "Can only get valid VSR vectors");    return synth_VSR;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -