📄 synth_intr.c
字号:
//=============================================================================//// 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 + -