The flags member takes two sets of flags.
The first set deals with the characteristics of the interrupts:
- INTR_FLAG_NMI
- Indicates that this is a NonMaskable Interrupt (NMI). An
NMI is an interrupt which can't be disabled by clearing
the CPU's interrupt enable flag, unlike most normal interrupts.
NonMaskable interrupts are typically
used to signal events that require immediate action,
such as a parity error, a hardware failure, or
imminent loss of power.
The address for the handler's NMI is stored
in the BIOS's Interrupt Vector table at position 02H.
For this reason an NMI is often referred to as INT 02H.
The code in the kernel needs to differentiate between
normal interrupts and NMIs, because with an NMI the
kernel needs to know that it can't protect (mask) the
interrupt (hence the "N" in NonMaskable
Interrupt). We strongly discourage the use of the NMI
vector in x86 designs; we don't support it on any
non-x86 platforms.
Note:
Regular interrupts that are normally used and referred to by number
are called maskable interrupts. Unlike non maskable interrupts,
maskable interrupts are those that can be masked, or ignored,
to allow the processor to complete a task.
- INTR_FLAG_CASCADE_IMPLICIT_EOI
- Indicates that an EOI to the primary interrupt controller
is not required when handling a cascaded interrupt (e.g.
it's done automatically). Only used if this entry
describes a cascaded controller.
- INTR_FLAG_CPU_FAULT
- Indicates that one or more of the vectors described by
this entry is not connected to a hardware
interrupt source, but rather is generated as a result
of a CPU fault (e.g. bus fault, parity error). Note that
we strongly discourage designing your hardware this way.
The implication is that a check needs to be inserted for
an exception into the generated code stream; after
the interrupt has been identified, an EOI needs to be sent
to the controller. The EOI code burst has the additional
responsibility of detecting what address caused the fault,
retrieving the fault type, and then passing the fault on.
The primary disadvantage of this approach is that it
causes extra code to be inserted into the code path.
The second set of flags deals with code generation:
- INTR_GENFLAG_LOAD_SYSPAGE
- Before the interrupt identification or EOI code sequence is
generated, a piece of code needs to be inserted to
fetch the system page pointer into a register so that
it's usable within the identification code sequence.
Note:
If you use the interrupt_id_dec(),
interrupt_id_dec_smp(), or interrupt_eoi_dec()
callouts, you must specify the INTR_GENFLAG_LOAD_SYSPAGE
flag in the genflags field of the
intrinfo_entry structure in the board-specific code.
- INTR_GENFLAG_LOAD_INTRINFO
- Same as INTR_GENFLAG_LOAD_SYSPAGE, except that
it loads a pointer to this structure.
- INTR_GENFLAG_LOAD_INTRMASK
- Used only by EOI routines for hardware that doesn't
automatically mask at the chip level. When the EOI
routine is about to reenable interrupts, it should
reenable only those interrupts that are actually
enabled at the user level (e.g. managed by the functions
InterruptMask() and InterruptUnmask()).
When this flag is set, the existing interrupt mask is stored
in a register for access by the EOI routine.
A zero in the register indicates that the interrupt should be
unmasked; a nonzero indicates it should remain masked.
- INTR_GENFLAG_NOGLITCH
- Used by the interrupt ID code to cause a check to be made to
see if the interrupt was due to a glitch or to a different
controller.
If this flag is set, the check is omitted — you're
indicating that there's no reason (other than the fact that
the hardware actually did generate an interrupt) to be in
the interrupt service routine.
If this flag is not set, the check is made to verify that
the suspected hardware really is the source of the interrupt.
- INTR_GENFLAG_LOAD_CPUNUM
- Same as INTR_GENFLAG_LOAD_SYSPAGE, except that
it loads a pointer to the number of the CPU this structure uses.
- INTR_GENFLAG_ID_LOOP
- Some interrupt controllers have read-and-clear registers indicating
the active interrupts.
That is, the first read returns a bitset with the pending interrupts,
and then immediately zeroes the register.
Since the interrupt ID callout can return only one interrupt number
at a time, that means that we might fail to process all the interrupts
if there's more than one bit on in the status register.
When INTR_GENFLAG_ID_LOOP is on,
the kernel generates code to jump back to
the ID callout after the EOI has finished.
In the ID callout, you need to allocate read-write storage as
per the usual procedures.
This storage is initially set to zero (done by default).
When the callout runs, the first thing it does is check the storage area:
- If the storage is nonzero, the callout uses it to identify another
interrupt to process, knocks that bit down, writes the new value back
into the storage location and returns the identified interrupt number.
- If the storage location is zero, the callout reads the hardware
status register (clearing it) and identifies the interrupt number from it.
It then knocks that bit off, writes the value to the storage location,
and then returns the appropriate interrupt number.
- If both the storage and hardware register are zero, the routine
returns -1 to indicate no interrupt is present as per usual.