From c2b620b4f8dc36790b74e5b4d535376a24472c60 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 3 Mar 2017 08:55:16 -0600 Subject: [PATCH] Implements support for smaller interrupt tables as described at http://www.nuttx.org/doku.php?id=wiki:howtos:smallvectors . This is largely the work of Mark Schulte. However, I have made several changes to match with the Wiki document. If you like the change, thanks go to Marc. For any errors you can blame me. --- arch/Kconfig | 38 ++++++++++++++++++++++++++++++++++++++ include/nuttx/arch.h | 2 +- include/nuttx/irq.h | 18 +++++++++++++++--- sched/irq/irq.h | 25 ++++++++++++++++++++++--- sched/irq/irq_attach.c | 24 ++++++++++++++++++++---- sched/irq/irq_dispatch.c | 20 ++++++++++++++++++-- sched/irq/irq_initialize.c | 22 ++++++++++++++++++++-- 7 files changed, 134 insertions(+), 15 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index f57f510355..4c791777c5 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -621,6 +621,44 @@ config ARCH_RAMVECTORS If ARCH_RAMVECTORS is defined, then the architecture will support modifiable vectors in a RAM-based vector table. +config ARCH_MINIMAL_VECTORTABLE + bool "Minimal RAM usage for vector table" + default n + ---help--- + Use a minimum amount of RAM for the vector table. + + Instead of allowing irq_attach() to work for all interrupt vectors, + restrict to only working for a select few (defined in your board + configuration). This can dramatically reduce the amount of RAM used + be your vector table. + + To use this setting, you must have a file in your board config that + provides: + + #include + const irq_t g_irqmap[NR_IRQS] = + { + ... IRQ to index mapping values ... + }; + + This table is index by the hardware IRQ number and provides a value + in the range of 0 to CONFIG_ARCH_NUSER_INTERRUPTS that the new, + mapped index into the vector table. Unused, unmapped interrupts + should be set to (irq_t)-1. So, for example, if g_irqmap[37] == 24, + Then the hardware interrupt vector 37 will be mapped to the interrupt + vector table at index 24. if g_irqmap[42] == (irq_t)-1, then hardware + interrupt vector 42 is not used and if it occurs will result in an + unexpected interrupt crash. + +config ARCH_NUSER_INTERRUPTS + int "Number of interrupts" + default 0 + depends on ARCH_MINIMAL_VECTORTABLE + ---help--- + If CONFIG_ARCH_MINIMAL_VECTORTABLE is defined, then this setting + defines the actual number of valid, mapped interrupts in g_irqmap. + This number will be the new size of the OS vector table + comment "Board Settings" config BOARD_LOOPSPERMSEC diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index ce72c82c90..4789e49cf6 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/arch.h * - * Copyright (C) 2007-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without diff --git a/include/nuttx/irq.h b/include/nuttx/irq.h index 59d8a3a330..7afca9f09c 100644 --- a/include/nuttx/irq.h +++ b/include/nuttx/irq.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/irq.h * - * Copyright (C) 2007-2011, 2013, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2011, 2013, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,7 @@ #include #ifndef __ASSEMBLY__ +# include # include # include #endif @@ -50,6 +51,7 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* IRQ detach is a convenience definition. Detaching an interrupt handler * is equivalent to setting a NULL interrupt handler. */ @@ -62,9 +64,19 @@ * Public Types ****************************************************************************/ -/* This struct defines the way the registers are stored */ - #ifndef __ASSEMBLY__ +/* This type is an integer type large enough to hold the largest IRQ number. */ + +#if NR_IRQS <= 256 +typedef uint8_t irq_t; +#elif NR_IRQS <= 65536 +typedef uint16_t irq_t; +#else +typedef uint32_t irq_t; +#endif + +/* This struct defines the form of an interrupt service routine */ + typedef int (*xcpt_t)(int irq, FAR void *context, FAR void *arg); #endif diff --git a/sched/irq/irq.h b/sched/irq/irq.h index 59bd5ea243..817149b33d 100644 --- a/sched/irq/irq.h +++ b/sched/irq/irq.h @@ -51,7 +51,16 @@ #include /**************************************************************************** - * Public Data + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_ARCH_MINIMAL_VECTORTABLE) && \ + !defined(CONFIG_ARCH_NUSER_INTERRUPTS) +# error CONFIG_ARCH_NUSER_INTERRUPTS is not defined +#endif + +/**************************************************************************** + * Public Types ****************************************************************************/ /* This is the type of the list of interrupt handlers, one for each IRQ. @@ -60,7 +69,7 @@ * interrupt. */ -struct irq +struct irq_info_s { xcpt_t handler; /* Address of the interrupt handler */ FAR void *arg; /* The argument provided to the interrupt handler. */ @@ -75,7 +84,17 @@ struct irq * occurrence of an interrupt. */ -extern struct irq g_irqvector[NR_IRQS]; +#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE +extern struct irq_info_s g_irqvector[CONFIG_ARCH_NUSER_INTERRUPTS]; +#else +extern struct irq_info_s g_irqvector[NR_IRQS]; +#endif + +#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE +/* This is the interrupt vector mapping table */ + +extern const irq_t g_irqmap[NR_IRQS]; +#endif #ifdef CONFIG_SMP /* This is the spinlock that enforces critical sections when interrupts are diff --git a/sched/irq/irq_attach.c b/sched/irq/irq_attach.c index 218ceb7ca1..9d45d9c637 100644 --- a/sched/irq/irq_attach.c +++ b/sched/irq/irq_attach.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/irq/irq_attach.c * - * Copyright (C) 2007-2008, 2010, 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2008, 2010, 2012, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -64,6 +64,21 @@ int irq_attach(int irq, xcpt_t isr, FAR void *arg) if ((unsigned)irq < NR_IRQS) { irqstate_t flags; + int ndx; + +#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE + /* Is there a mapping for this IRQ number? */ + + ndx = g_irqmap[irq]; + if ((unsigned)ndx >= CONFIG_ARCH_NUSER_INTERRUPTS) + { + /* No.. then return failure. */ + + return ret; + } +#else + ndx = irq; +#endif /* If the new ISR is NULL, then the ISR is being detached. * In this case, disable the ISR and direct any interrupts @@ -94,10 +109,11 @@ int irq_attach(int irq, xcpt_t isr, FAR void *arg) arg = NULL; } - /* Save the new ISR in the table. */ + /* Save the new ISR and its argument in the table. */ + + g_irqvector[ndx].handler = isr; + g_irqvector[ndx].arg = arg; - g_irqvector[irq].handler = isr; - g_irqvector[irq].arg = arg; leave_critical_section(flags); ret = OK; } diff --git a/sched/irq/irq_dispatch.c b/sched/irq/irq_dispatch.c index 576e757628..f975812839 100644 --- a/sched/irq/irq_dispatch.c +++ b/sched/irq/irq_dispatch.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/irq/irq_dispatch.c * - * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -67,18 +67,34 @@ void irq_dispatch(int irq, FAR void *context) /* Perform some sanity checks */ #if NR_IRQS > 0 - if ((unsigned)irq >= NR_IRQS || g_irqvector[irq].handler == NULL) + if ((unsigned)irq >= NR_IRQS) { vector = irq_unexpected_isr; arg = NULL; } else { +#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE + int ndx = g_irqmap[irq]; + if ((unsigned)ndx >= CONFIG_ARCH_NUSER_INTERRUPTS) + { + vector = irq_unexpected_isr; + arg = NULL; + } + else + { + vector = g_irqvector[ndx].handler; + arg = g_irqvector[ndx].arg; + } +#else vector = g_irqvector[irq].handler; arg = g_irqvector[irq].arg; +#endif } + #else vector = irq_unexpected_isr; + arg = NULL; #endif /* Then dispatch to the interrupt handler */ diff --git a/sched/irq/irq_initialize.c b/sched/irq/irq_initialize.c index e03d27abdc..18bbafc4b3 100644 --- a/sched/irq/irq_initialize.c +++ b/sched/irq/irq_initialize.c @@ -43,11 +43,29 @@ #include "irq/irq.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* This is the number of entries in the interrupt vector table */ + +#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE +# define TAB_SIZE CONFIG_ARCH_NUSER_INTERRUPTS +#else +# define TAB_SIZE NR_IRQS +#endif + /**************************************************************************** * Public Data ****************************************************************************/ -struct irq g_irqvector[NR_IRQS]; +/* This is the interrupt vector table */ + +#ifdef CONFIG_ARCH_MINIMAL_VECTORTABLE +struct irq_info_s g_irqvector[CONFIG_ARCH_NUSER_INTERRUPTS]; +#else +struct irq_info_s g_irqvector[NR_IRQS]; +#endif /**************************************************************************** * Public Functions @@ -67,7 +85,7 @@ void irq_initialize(void) /* Point all interrupt vectors to the unexpected interrupt */ - for (i = 0; i < NR_IRQS; i++) + for (i = 0; i < TAB_SIZE; i++) { g_irqvector[i].handler = irq_unexpected_isr; g_irqvector[i].arg = NULL;