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

📄 synth_intr.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
//=============================================================================
//
//      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) 2005 eCosCentric Ltd
// 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.

// The bogomips rating, used by HAL_DELAY_US()
int hal_bogomips;

// 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_uint32
synth_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 void
synth_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.
void
hal_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

⌨️ 快捷键说明

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