When an interrupt occurs, this routine is called with interrupts cleared. It receives the interrupt number and a pointer to the saved used state. Although such state looks like a trap frame only the saved segment registers and the register state frame are valid.
Delivering simply calls raise in the interrupt table for the
current processor. Note that the interrupt has already been
acknowledged by the assembly stub.
We always deliver an interrupt, no matter if a previous one has been already processed or not. Interrupt handlers should protect themselves against pending interrupts: portal serviced interrupts can do so by limiting the number of available stacks to just one; procedure serviced interrupts should use a ``nested interrupt'' counter to deal with missed interrupts. Delivering code offers a small protection in that interrupts will be disabled until the message has been sent (or the procedure called). Interrupts are enabled again as soon the machine dependent interrupt handler returns.
Clock interrupt handling is a little bit special, because we do not
want it to travel the common interrupt delivering path. To avoid that,
it is handled apart by the handler. A external routine
clock_handler will be called without arguments. Such routine
should be provided by whoever is in charge of handling timers.
<off_mdep_intr_handler implementation. >= (U->)
// Handles an interrupt.
//
volatile void off_mdep_intr_handler(unsigned irq, struct trap_state *ts)
{
extern void off_clock_handler(void);
// < <Nest user state (w/ ts) here. > > XXX
if (irq == OFF_MDEP_CLOCK_IRQ)
off_clock_handler();
else
off_Processor::self()->get_irq(irq)->raise();
// < <Unwind user state. > >
}
Where, on Intels, MDEP_CLOCK_IRQ is
<Off machine dependent interrupt numbers. >+= (U->) [<-D] const natural_t OFF_MDEP_CLOCK_IRQ=0; // Timer interrupt.
This function must have access to Shtl::set_uctx and
Shtl::set_kctx.
<Friend declaration for upcall and system call procedures. >= friend void off_mdep_intr_handler(...); // For ev.nw trap & irq handling
<Off machine dependent event table implementation dependencies. >+= (U->) [<-D->] #include <hw/Processor.h> // for off_Processor
That handler is called by a small assembly glue code. First, we will
initialize in the base IDT base_idt new entries for every PC
hardware interrupt. Each descriptor jumps to an interrupt entry
point as defined in off_mdep_intr_inittab (see below). After that,
the master en slave PICs are initialized vectoring to the entries
installed in the IDT. Thus we are able now to receive hardware
interrupts and they will lead to our interrupt routine being invoked,
though they were initially disabled in the PIC (using
pic_disable_all) to avoid undesired interrupt receipts before
their handlers are actually ready and initialized. This is done when
the interrupt table is instantiated.
The idt is used both to vector traps and interrupts. First 32
(0x0 to 0x1f) of a total number of 256 entries will be used
for Intel processor traps. Next 16 entries (0x20 to 0x2f)
entries will be used for PC hardware interrupts. Remaining ones can be
defined later on by the user --but for the one used for system calls,
0x30, and returns from upcalls, 0x31.
<Machine dependent interrupt hardware initialization. >= (<-U) gate_init(base_idt, off_mdep_intr_inittab, KERNEL_CS); pic_init(PICM_VECTBASE, PICS_VECTBASE); pic_disable_all();
<Off machine dependent event table implementation dependencies. >+= (U->) [<-D->] #include <flux/machine/base_gdt.h> // for KERNEL_CS #include <flux/machine/base_idt.h> // for base_idt #include <flux/machine/gate_init.h> // for gate_init #include <hw/mdep/intr.h> // for off_mdep_intr_inittab
The interrupt table off_mdep_intr_inittab is maintained in a
separate assembly file together with the real interrupt entry point.
<Off machine dependent interrupt inittab. >= (U-> U->) extern struct gate_init_entry off_mdep_intr_inittab[];
We will need some includes for this code to work.
<Off hardware interrupts implementation dependencies. >= (U->) #include <flux/machine/asm.h> #include <flux/machine/gate_init.h> #include <flux/machine/seg.h>
To make easy the task of interrupt entry point declaration, a macro is
used to generate an interrupt entry point. Such entry point will push
the interrupt number and pass control to allints. Interrupt gates
will be placed on the idt at offset IDT_IRQ_BASE.
<Off hardware interrupts definitions. >= (U->)
#define INTERRUPT(irq) \
GATE_ENTRY((irq) + IDT_IRQ_BASE, 0f, ACC_PL_K|ACC_INTR_GATE) ;\
P2ALIGN(TEXT_ALIGN) ;\
0: ;\
cld ;\
pushl $0 ;\
pushl $(irq) ;\
pushal ;\
movl $(irq),%eax ;\
jmp allints
DefinesINTERRUPT(links are to index).
<Off hardware IRQBASE. >= (U->)
#define IDT_IRQ_BASE 0x20
Now we can use the above macro and \oskit{} GATE_INITTAB_ macros
to define a table of interrupt (and trap) entry points. Remember that
allints must pop eax and execute an iret to return:
<Off hardware interrupt return. >= (U->)
popal
addl $8,%esp
iret
The entry point definitions are now really easy.
<Off hardware interrupt entry points. >= (U->) GATE_INITTAB_BEGIN(off_mdep_intr_inittab) INTERRUPT(0) INTERRUPT(1) INTERRUPT(2) INTERRUPT(3) INTERRUPT(4) INTERRUPT(5) INTERRUPT(6) INTERRUPT(7) INTERRUPT(8) INTERRUPT(9) INTERRUPT(10) INTERRUPT(11) INTERRUPT(12) INTERRUPT(13) INTERRUPT(14) INTERRUPT(15) GATE_INITTAB_END
Definesoff_mdep_intr_inittab(links are to index).
The common interrupt handling routine is allints. This routine
handles initial interrupt hardware details and then jumps to the
C++ entry point (with C linkage). A global counter counting the
number of nested interrupts is also managed here. We will switch from
user to kernel segments on interrupt.
<Off hardware interrupt common handling routine. >= (U->)
cli
pushl %ds # save segments
pushl %es
pushl %fs
pushl %gs
movl $0x18,%cx # set kernel segments
movl %cx,%ds
movl %cx,%es
# incl off_mdep_intr_count
movl $1,%edx # if this master or slave?
movl %eax,%ecx
cmpl $8,%eax
jge 1f
movb $0x20,%al # ack int
outb %al,$0x20
jmp 2f
1: # slave PIC
movb $0x20,%al # ack irq
outb %al,$0x20
outb %al,$0xa0
addl $8,%ecx # adjust irq nb. 0th is 8th.
2:
incl off_mdep_intr_nest # count this int
pushl %esp # and usr state ptr.
pushl %ecx # push int #
call EXT(off_mdep_intr_handler) # call interrupt handler
popl %ecx # clean handler arguments
popl %esp
2:
cmpl $1,off_mdep_intr_nest # check for software intr
jne 1f
cmpl $0,off_mdep_intr_pending
je 1f
movl $0,off_mdep_intr_pending
call EXT(off_mdep_intr_handler)
sti
1:
decl off_mdep_intr_nest
popl %gs # restore segments
popl %fs
popl %es
popl %ds
<Off hardware interrupt return. >
.data
P2ALIGN(DATA_ALIGN)
.globl off_mdep_intr_nest
off_mdep_intr_pending:
.long 0
.globl off_mdep_intr_pe
off_mdep_intr_nest:
.long 0
# .globl off_mdep_intr_count
#off_mdep_intr_count:
# .long 0
Definesallints,off_mdep_intr_count,off_mdep_intr_nest,off_mdep_intr_pending(links are to index).
We have this counters available
<Off hardware interrupt counters. >= (U->) extern volatile u_long off_mdep_intr_nest; extern volatile u_long off_mdep_intr_pending; //extern volatile u_long off_mdep_intr_count;
\subsubsection{Trap delivering}
The OSKit delivers traps to the base_trap_handler routine, if
defined. We provide such routine just to notify the trap table of the
current processor that a trap happened.
Such handler is installed by the machine dependent trap table at boot time.
<Other private members of off_TrapTbl. >+= (<-U) [<-D]
off_mdepTrapTbl mdep; // Mach dep. trap table.
<Initialize other aggregate members of off_TrapTbl. >+= (<-U) [<-D]
mdep()
<Off machine dependent trap table. >= (U->)
// An ix86 trap table
//
class off_mdepTrapTbl {
public:
// Creates an x86 trap table.
off_mdepTrapTbl(void);
// Returns the id for the page fault trap.
static inline int get_pgflt(void);
};
extern inline int off_mdepTrapTbl::get_pgflt(void){ return T_PAGE_FAULT;}
Definesoff_mdepTrapTbl(links are to index).
<Off machine dependent event table dependencies. >+= (U->) [<-D] #include <flux/machine/trap.h> // for T_PAGE_FAULT
<off_mdepTrapTbl::off_mdepTrapTbl implementation. >= (U->)
extern "C" {
extern int off_mdep_trap_handler(struct trap_state *state);
};
off_mdepTrapTbl::off_mdepTrapTbl(void)
{
base_trap_handler = off_mdep_trap_handler;
}
<Off machine dependent event table implementation dependencies. >+= (U->) [<-D] #include <flux/machine/base_trap.h> // for base_trap_handler
The machine dependent trap handler simply obtains a reference to the current processor and delivers the trap on its trap table. In those cases where extra information must be gathered from hardware to determine the trap reason (e.g. on page faults)
<off_mdep_trap_handler implementation. >= (U->)
//
//
int off_mdep_trap_handler(struct trap_state *state)
{
err_t err;
// < <Nest user [[state]] (w/ ts) here. > > XXX
err=off_Processor::self()->get_trap(state->trapno)->raise(state->err);
// < <Unwind user [[state]]. > >
return err;
}
Definesoff_mdep_trap_handler(links are to index).
\subsubsection{Machine dependent Event \cpp{} source files}
We maintain machine dependent event table stuff in
mdep/mEventTbl.h and mdep/mEventTbl.C.
<mdep mEventTbl.h*>=
<Read the literate code instead warning. >
#ifndef __OFF_MDEP_EV_TBL_H
#define __OFF_MDEP_EV_TBL_H 1
<Off machine dependent event table dependencies. >
<Off machine dependent interrupt table size. >
<Off machine dependent trap table size. >
<Off machine dependent interrupt numbers. >
#ifdef __KERNEL__
<Off machine dependent interrupt mask. >
<Off machine dependent interrupt table. >
<Off machine dependent trap table. >
#endif // __KERNEL__
#ifdef __KERNEL__
<off_mdepIntTbl::is_masked implementation. >
#endif // __KERNEL__
#endif // __OFF_MDEP_EV_TBL_H
<mdep mEventTbl.C*>= <Read the literate code instead warning. > #include <hw/mdep/mEventTbl.h> // Exported interface <Off machine dependent event table implementation dependencies. > <Off machine dependent interrupt inittab. > <off_mdepIntTbl::off_mdepIntTblimplementation. > <off_mdepTrapTbl::off_mdepTrapTblimplementation. > <off_mdepIntTbl::maskimplementation. > <off_mdepIntTbl::unmaskimplementation. > extern "C" { <off_mdep_intr_handlerimplementation. > <off_mdep_trap_handlerimplementation. > };
Finally, assembly interrupt glue code is kept in mdep/intr.h and
mdep/intr.S.
<mdep intr.h*>=
#ifndef __MDEP_INTR_H
#define __MDEP_INTR_H 1
#ifndef ASSEMBLER
extern "C" {
<Off machine dependent interrupt inittab. >
#endif
#include <flux/machine/gate_init.h>
#ifndef ASSEMBLER
<Off hardware interrupt counters. >
#endif
<Off hardware IRQBASE. >
#ifndef ASSEMBLER
} // "C" linkage
#endif
#endif // __MDEP_INTR_H
DefinesIDT_IRQ_BASE(links are to index).
The interrupt entry point code is adapted from the \oskit{} libfdev
utility library. The layout of this file is as follows
<mdep intr.S*>=
<Oskit copyright notice. >
#include <hw/mdep/intr.h> // Exported interface
<Off hardware interrupts implementation dependencies. >
.text
<Off hardware interrupts definitions. >
<Off hardware interrupt entry points. >
P2ALIGN(TEXT_ALIGN)
allints:
<Off hardware interrupt common handling routine. >
P2ALIGN(TEXT_ALIGN)
As the code is taken almost literally from the \oskit{} their copyright notice is included:
<Oskit copyright notice. >= (<-U) /* * Copyright (c) 1996 The University of Utah and * the Computer Systems Laboratory at the University of Utah (CSL). * All rights reserved. * * Permission to use, copy, modify and distribute this software is hereby * granted provided that (1) source code retains these copyright, permission, * and disclaimer notices, and (2) redistributions including binaries * reproduce the notices in supporting documentation, and (3) all advertising * materials mentioning features or use of this software display the following * acknowledgement: ``This product includes software developed by the * Computer Systems Laboratory at the University of Utah.'' * * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * CSL requests users of this software to return to csl-dist@cs.utah.edu any * improvements that they make and grant CSL redistribution rights. */
this interrupt can be raised. >: U1, D2
off_CompResource::make_available. >: U1, U2
i_alloc. >: U1, D2
off_Event. >: U1, U2, U3, U4, D5
off_IntTbl. >: U1, D2, D3
off_Irq. >: U1, D2, D3
off_TrapTbl. >: U1, D2, D3
t_alloc. >: U1, D2
IRQBASE. >: D1, U2
off_Event::get_count implementation. >: D1, U2
off_Event::get_handler implementation. >: D1, U2
off_Event::off_Event implementation. >: D1, D2, D3, D4, U5
off_Event::~off_Event implementation. >: D1, U2
off_Event::raise implementation. >: D1, U2
off_Event::set_handler implementation. >: D1, U2
off_IntAllocator::operator + implementation. >: D1, U2
off_IntTbl::alloc implementation. >: D1, U2
off_IntTbl::defer implementation. >: D1, U2
off_IntTbl::free implementation. >: D1, U2
off_IntTbl::get_allocator implementation. >: D1, U2
off_IntTbl::get_clk implementation. >: D1, U2
off_IntTbl::get_count implementation. >: D1, U2
off_IntTbl::get_url implementation. >: D1, U2
off_IntTbl::get_vint0 implementation. >: D1, U2
off_IntTbl::is_local implementation. >: D1, U2
off_IntTbl::mask unmask and is_masked implementation. >: D1, U2
off_IntTbl::nameof implementation. >: D1, U2
off_IntTbl::off_IntTbl implementation. >: D1, U2
off_IntTbl::operator + implementation. >: D1, U2
off_IntTbl::spl implementation. >: D1, U2
off_Irq::copy_state implementation. >: D1, U2
off_Irq::defer implementation. >: D1, U2
off_Irq::deferred implementation. >: D1, U2
off_Irq::get_prty implementation. >: D1, U2
off_Irq::get_url_holder implementation. >: D1, U2
off_Irq::is_masked implementation. >: D1, U2
off_Irq::mask implementation. >: D1, U2
off_Irq::off_Irq implementation. >: D1, U2
off_Irq::~off_Irq implementation. >: D1, U2
off_Irq::operator new/delete implementation. >: D1, U2
off_Irq::raise implementation. >: D1, U2
off_Irq::restore_state implementation. >: D1, U2
off_Irq::set_prty implementation. >: D1, U2
off_Irq::unmask implementation. >: D1, U2
off_KrnEventHandler::off_KrnEventHandler implementation. >: D1, U2
off_KrnEventHandler::operator() implementation. >: D1, U2
off_Magic::nameof case for m_numbers. >: D1, D2
off_mdep_intr_handler implementation. >: D1, U2
off_mdepIntTbl::is_masked implementation. >: D1, U2
off_mdepIntTbl::mask implementation. >: D1, U2
off_mdepIntTbl::off_mdepIntTbl implementation. >: D1, U2
off_mdepIntTbl::unmask implementation. >: D1, U2
off_mdep_trap_handler implementation. >: D1, U2
off_mdepTrapTbl::off_mdepTrapTbl implementation. >: D1, U2
off_TrapAllocator::operator + implementation. >: D1, U2
off_Trap::copy_state implementation. >: D1, U2
off_Trap::get_url_holder implementation. >: D1, U2
off_Trap::operator new/delete implementation. >: D1, U2
off_Trap::raise implementation. >: D1, U2
off_Trap::restore_state implementation. >: D1, U2
off_TrapTbl::alloc implementation. >: D1, U2
off_TrapTbl::free implementation. >: D1, U2
off_TrapTbl::get_allocator implementation. >: D1, U2
off_TrapTbl::get_count implementation. >: D1, U2
off_TrapTbl::get_url implementation. >: D1, U2
off_TrapTbl::get_vtrap0 and get_pgflt implementation. >: D1
off_TrapTbl::is_local implementation. >: D1, U2
off_TrapTbl::nameof implementation. >: D1, U2
off_TrapTbl::off_TrapTbl implementation. >: D1, U2
off_TrapTbl::operator + implementation. >: D1, U2
off_UsrEventHandler::off_UsrEventHandler implementation. >: D1, U2
off_UsrEventHandler::operator() implementation. >: D1, U2
off_Event. >: U1, D2, D3
off_IntTbl. >: U1, D2, D3, D4, D5, D6, D7
off_Irq. >: U1, D2, D3, D4
off_KrnEventHandler. >: U1, D2
off_mdepIntTbl. >: U1, D2
off_Trap. >: U1, D2
off_TrapTbl. >: U1, D2, D3, D4
off_UsrEventHandler. >: U1, D2
off_Event. >: U1, D2, D3, D4, D5
off_EventTbl. >: U1, D2, D3, D4
off_IntTbl. >: U1, D2
off_Irq. >: U1, D2, D3, D4
off_Trap. >: U1, D2, D3
off_TrapTbl. >: U1, D2
off_Event. >: U1, D2, D3, D4
off_EventTbl. >: U1, D2, D3
off_IntAllocator. >: U1, D2
off_IntTbl. >: U1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12
off_Irq. >: U1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12
off_KrnEventHandler. >: U1, D2
off_Trap. >: U1, D2, D3, D4, D5, D6, D7, D8
off_TrapAllocator. >: U1, D2
off_TrapTbl. >: U1, D2, D3, D4, D5, D6, D7, D8, D9
off_UsrEventHandler. >: U1, D2
%% --------------------------------------------------------------