@@ -206,6 +206,130 @@ The following code demonstrates a direct ISR:
206206 ...
207207 }
208208
209+ Implementation Details
210+ ======================
211+
212+ Interrupt tables are set up at build time using some special build tools. The
213+ details laid out here apply to all architectures except x86, which are
214+ covered in the `x86 Details `_ section below.
215+
216+ Any invocation of :c:macro: `IRQ_CONNECT ` will declare an instance of
217+ struct _isr_list which is placed in a special .intList section:
218+
219+ .. code-block :: c
220+
221+ struct _isr_list {
222+ /** IRQ line number */
223+ s32_t irq;
224+ /** Flags for this IRQ, see ISR_FLAG_* definitions */
225+ s32_t flags;
226+ /** ISR to call */
227+ void *func;
228+ /** Parameter for non-direct IRQs */
229+ void *param;
230+ };
231+
232+ Zephyr is built in two phases; the first phase of the build produces
233+ zephyr_prebuilt.elf which contains all the entries in the .intList section
234+ preceded by a header:
235+
236+ .. code-block :: c
237+
238+ struct {
239+ void *spurious_irq_handler;
240+ void *sw_irq_handler;
241+ u32_t num_isrs;
242+ u32_t num_vectors;
243+ struct _isr_list isrs[]; <- of size num_isrs
244+ };
245+
246+ This data consisting of the header and instances of struct _isr_list inside
247+ zephyr_prebuilt.elf is then used by the gen_isr_tables.py script to generate a
248+ C file defining a vector table and software ISR table that are then compiled
249+ and linked into the final application.
250+
251+ The priority level of any interrupt is not encoded in these tables, instead
252+ :c:macro: `IRQ_CONNECT ` also has a runtime component which programs the desired
253+ priority level of the interrupt to the interrupt controller. Some architectures
254+ do not support the notion of interrupt priority, in which case the priority
255+ argument is ignored.
256+
257+ Vector Table
258+ ------------
259+ A vector table is generated when CONFIG_GEN_IRQ_VECTOR_TABLE is enabled. This
260+ data structure is used natively by the CPU and is simply an array of function
261+ pointers, where each element n corresponds to the IRQ handler for IRQ line n,
262+ and the function pointers are:
263+
264+ #. For 'direct' interrupts declared with :c:macro: `IRQ_DIRECT_CONNECT `, the
265+ handler function will be placed here.
266+ #. For regular interrupts declared with :c:macro: `IRQ_CONNECT `, the address
267+ of the common software IRQ handler is placed here. This code does common
268+ kernel interrupt bookkeeping and looks up the ISR and parameter from the
269+ software ISR table.
270+ #. For interrupt lines that are not configured at all, the address of the
271+ spurious IRQ handler will be placed here. The spurious IRQ handler
272+ causes a system fatal error if encountered.
273+
274+ Some architectures (such as the Nios II internal interrupt controller) have a
275+ common entry point for all interrupts and do not support a vector table, in
276+ which case the CONFIG_GEN_IRQ_VECTOR_TABLE option should be disabled.
277+
278+ Some architectures may reserve some initial vectors for system exceptions
279+ and declare this in a table elsewhere, in which case
280+ CONFIG_GEN_IRQ_START_VECTOR needs to be set to properly offset the indicies
281+ in the table.
282+
283+ SW ISR Table
284+ ------------
285+ This is an array of struct _isr_table_entry:
286+
287+ .. code-block :: c
288+
289+ struct _isr_table_entry {
290+ void *arg;
291+ void (*isr)(void *);
292+ };
293+
294+ This is used by the common software IRQ handler to look up the ISR and its
295+ argument and execute it. The active IRQ line is looked up in an interrupt
296+ controller register and used to index this table.
297+
298+ x86 Details
299+ -----------
300+
301+ The x86 architecture has a special type of vector table called the Interrupt
302+ Descriptor Table (IDT) which must be laid out in a certain way per the x86
303+ processor documentation. It is still fundamentally a vector table, and the
304+ gen_idt tool uses the .intList section to create it. However, on APIC-based
305+ systems the indexes in the vector table do not correspond to the IRQ line. The
306+ first 32 vectors are reserved for CPU exceptions, and all remaining vectors (up
307+ to index 255) correspond to the priority level, in groups of 16. In this
308+ scheme, interrupts of priority level 0 will be placed in vectors 32-47, level 1
309+ 48-63, and so forth. When the gen_idt tool is constructing the IDT, when it
310+ configures an interrupt it will look for a free vector in the appropriate range
311+ for the requested priority level and set the handler there.
312+
313+ There are some APIC variants (such as MVIC) where priorities cannot be set
314+ by the user and the position in the vector table does correspond to the
315+ IRQ line. Systems like this will enable CONFIG_X86_FIXED_IRQ_MAPPING.
316+
317+ On x86 when an interrupt or exception vector is executed by the CPU, there is
318+ no foolproof way to determine which vector was fired, so a software ISR table
319+ indexed by IRQ line is not used. Instead, the :c:macro: `IRQ_CONNECT ` call
320+ creates a small assembly language function which calls the common interrupt
321+ code in :cpp:func: `_interrupt_enter ` with the ISR and parameter as arguments.
322+ It is the address of this assembly interrupt stub which gets placed in the IDT.
323+ For interrupts declared with :c:macro: `IRQ_DIRECT_CONNECT ` the parameterless
324+ ISR is placed directly in the IDT.
325+
326+ On systems where the position in the vector table corresponds to the
327+ interrupt's priority level, the interrupt controller needs to know at
328+ runtime what vector is associated with an IRQ line. gen_idt additionally
329+ creates an _irq_to_interrupt_vector array which maps an IRQ line to its
330+ configured vector in the IDT. This is used at runtime by :c:macro: `IRQ_CONNECT `
331+ to program the IRQ-to-vector association in the interrupt controller.
332+
209333Suggested Uses
210334**************
211335
0 commit comments