diff --git a/arch/Kconfig b/arch/Kconfig index 79b7e51b57..93a50ef2ad 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -72,7 +72,6 @@ config ARCH_SIM select ARCH_HAVE_TICKLESS select ARCH_HAVE_POWEROFF select ARCH_HAVE_TESTSET - select ARCH_NOINTC select ALARM_ARCH select ONESHOT select SERIAL_CONSOLE diff --git a/arch/sim/include/irq.h b/arch/sim/include/irq.h index 808266b56c..bec1d78c05 100644 --- a/arch/sim/include/irq.h +++ b/arch/sim/include/irq.h @@ -44,9 +44,7 @@ * Pre-processor Definitions ****************************************************************************/ -/* No interrupts */ - -#define NR_IRQS 0 +#define NR_IRQS 64 /* Number of registers saved in context switch */ diff --git a/arch/sim/src/sim/up_hostirq.c b/arch/sim/src/sim/up_hostirq.c index 9acbd59f10..b92962017b 100644 --- a/arch/sim/src/sim/up_hostirq.c +++ b/arch/sim/src/sim/up_hostirq.c @@ -25,6 +25,19 @@ #include #include #include +#include + +#include "up_internal.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_SMP +volatile void *g_current_regs[CONFIG_SMP_NCPUS]; +#else +volatile void *g_current_regs[1]; +#endif /**************************************************************************** * Private Types @@ -36,6 +49,19 @@ union sigset_u sigset_t sigset; }; +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_handle_irq + ****************************************************************************/ + +static void up_handle_irq(int irq, siginfo_t *info, void *context) +{ + up_doirq(irq, context); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -86,3 +112,48 @@ void up_irq_restore(uint64_t flags) void up_irqinitialize(void) { } + +/**************************************************************************** + * Name: up_enable_irq + * + * Description: + * Enable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_enable_irq(int irq) +{ + struct sigaction act; + sigset_t set; + + /* Register signal handler */ + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = up_handle_irq; + act.sa_flags = SA_SIGINFO; + sigfillset(&act.sa_mask); + sigaction(irq, &act, NULL); + + /* Unmask the signal */ + + sigemptyset(&set); + sigaddset(&set, irq); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); +} + +/**************************************************************************** + * Name: up_disable_irq + * + * Description: + * Disable the IRQ specified by 'irq' + * + ****************************************************************************/ + +void up_disable_irq(int irq) +{ + /* Since it's hard to mask the signal on all threads, + * let's change the signal handler to ignore instead. + */ + + signal(irq, SIG_IGN); +} diff --git a/arch/sim/src/sim/up_internal.h b/arch/sim/src/sim/up_internal.h index 26e3f5102b..df24178a87 100644 --- a/arch/sim/src/sim/up_internal.h +++ b/arch/sim/src/sim/up_internal.h @@ -169,6 +169,28 @@ struct ioexpander_dev_s; * Public Data ****************************************************************************/ +/* g_current_regs[] holds a references to the current interrupt level + * register storage structure. If is non-NULL only during interrupt + * processing. Access to g_current_regs[] must be through the macro + * CURRENT_REGS for portability. + */ + +#ifdef CONFIG_SMP +/* For the case of architectures with multiple CPUs, then there must be one + * such value for each processor that can receive an interrupt. + */ + +int up_cpu_index(void); /* See include/nuttx/arch.h */ +extern volatile void *g_current_regs[CONFIG_SMP_NCPUS]; +# define CURRENT_REGS (g_current_regs[up_cpu_index()]) + +#else + +extern volatile void *g_current_regs[1]; +# define CURRENT_REGS (g_current_regs[0]) + +#endif + #ifdef CONFIG_SMP /* These spinlocks are used in the SMP configuration in order to implement * up_cpu_pause(). The protocol for CPUn to pause CPUm is as follows @@ -192,6 +214,8 @@ extern volatile uint8_t g_cpu_paused[CONFIG_SMP_NCPUS]; * Public Function Prototypes ****************************************************************************/ +void *up_doirq(int irq, void *regs); + /* up_setjmp32.S ************************************************************/ int up_setjmp(void *jb); diff --git a/arch/sim/src/sim/up_interruptcontext.c b/arch/sim/src/sim/up_interruptcontext.c index 91661acb72..7a3a9e404b 100644 --- a/arch/sim/src/sim/up_interruptcontext.c +++ b/arch/sim/src/sim/up_interruptcontext.c @@ -41,6 +41,7 @@ #include #include + #include "up_internal.h" /**************************************************************************** @@ -58,7 +59,38 @@ bool up_interrupt_context(void) { - /* The simulation is never in the interrupt state */ - - return false; + return CURRENT_REGS != NULL; +} + +/**************************************************************************** + * Name: up_doirq + ****************************************************************************/ + +void *up_doirq(int irq, void *regs) +{ + /* Current regs non-zero indicates that we are processing an interrupt; + * CURRENT_REGS is also used to manage interrupt level context switches. + */ + + CURRENT_REGS = regs; + + /* Deliver the IRQ */ + + irq_dispatch(irq, regs); + + /* If a context switch occurred while processing the interrupt then + * CURRENT_REGS may have change value. If we return any value different + * from the input regs, then the lower level will know that a context + * switch occurred during interrupt processing. + */ + + regs = (void *)CURRENT_REGS; + + /* Restore the previous value of CURRENT_REGS. NULL would indicate that + * we are no longer in an interrupt handler. It will be non-NULL if we + * are returning from a nested interrupt. + */ + + CURRENT_REGS = NULL; + return regs; }