Implementation of exception in Linux
2009-12-10 11:19
411 查看
Implementation of exception in Linux
Background
In
the MIPS architecture, interrupt, traps, system calls and everything
else that can disrupt the normal flow of execution are called exception
and are handled by a single mechanism.
This
document introduces how these exceptions are supported in Linux kernel
and how to add implement interrupt handler for new MIPS platform..
The referenced code for this document is based on:
a)
Linux 2.6.18
b)
MIPS32 without EIC
Part 1: Introduction for MIPS exception
1.
Exception vectors
All
exception entry points lie in un-translated regions of memory, kseg1
for uncached entry point and kseg0 for cached ones. The uncached entry
points used when SR(BEV) is set are fixed, while EBase register can be
programmed to shift all the entry points to another block when SR(BEV)
is cleared.
The following table shows the MIPS exception entry point:
When
Linux is running, SR(BEV) is cleared and EBase is set to 0x80000000 in
default, so we shall copy the general exceptions handler to 0x80000180
and interrupt handler to 0x80000200. Since the size for entry point is
limited, only a jump instruction is placed in every entry point in most
cases.
2.
Cause ExcCode
In
CP0 Cause register, there are 5 bits (Cause[2:6]) to tell you what kind
of exception happened, when we get exception, we need read this
register to know what causes this exception exactly. The following
table shows the ExcCode values and it is copied from “See MIPS Run”
The value is not listed in this table is not used currently.
3.
Interrupt enable
There
are 8 bits in CP0 Status Register SR[8:15] for interrupt mask. If there
is no EIC, MIPS can support 8 interrupt sources. When one or some bits
of SR[8:15] is set, the interrupt sources corresponding to these bits
will be allowed to cause an exception. Six of the interrupt sources are
generated by signals from outside the CPU core while the other two are
the software-writable interrupt bits in the Cause register. These bits
are enabled in arch_init_irq() API according to platform interrupt
design. The arch_init_irq() API will be introduced in part 3.
SR[0]
is the global interrupt enable bit. If we set this bit, we will allow
the interrupts corresponding to the set bits of SR[8:15] to be
generated. If we clear this bit, no interrupt will be generated.
Part 2: Implementation in Linux
1.
Exception initialization in Linux
The exception initialization is implemented in
trap_init()
of
linux-2.6.18/arch/mips/kernel/trap.c
, which includes exception vectors install and exception handlers registering.
1)
exception vectors install
a)
At the beginning of this API, it will call the following statement to
copy the generic exception handler to EBase + 0x180, where is the
general exception entry point:
set_handler(0x180, &except_vec3_generic, 0x80);
b) At the end of this API, it will copy the exception handler to the different entry point according to different platform:
if (cpu_has_vce)
/* Special exception: R4[04]00 uses also the divec space. */
memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100);
else if (cpu_has_4kex)
memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80);
else
memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80);
c) For interrupt handler initialization, it will call the following statement to copy the general handler to entry point:
else if (cpu_has_divec)
set_handler(0x200, &except_vec4, 0x8);
please notice that “EBase + 0x200” is the interrupt handler entry point.
d)
Since ExcCode(0) means interrupt, it will set the interrupt handler
again when set exception vector for ExcCode(0) with
“set_except_vector(0, handle_int);”:
void *set_except_vector(int n, void *addr)
{
unsigned long handler = (unsigned long) addr;
unsigned long old_handler = exception_handlers
;
exception_handlers
= handler;
if (n == 0 && cpu_has_divec) {
*(volatile u32 *)(ebase + 0x200) = 0x08000000 |
(0x03ffffff & (handler >> 2));
flush_icache_range(ebase + 0x200, ebase + 0x204);
}
return (void *)old_handler;
}
According
to MIPS instruction encoding, 0x08000000 is a jump instruction, so the
actual instruction in EBase + 0x200 is “j handle_int”
2)
handlers registering
In
trap_init() API, it define a global array unsigned long
exception_handlers[32] to contain 32 exception handlers for 32 ExcCodes
and it will call set_except_vector() function to register these
handlers to this array.
set_except_vector(0, handle_int);
set_except_vector(1, handle_tlbm);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);
set_except_vector(4, handle_adel);
set_except_vector(5, handle_ades);
set_except_vector(6, handle_ibe);
set_except_vector(7, handle_dbe);
set_except_vector(8, handle_sys);
set_except_vector(9, handle_bp);
set_except_vector(10, handle_ri);
set_except_vector(11, handle_cpu);
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);
…
2.
How to handle exception
The basic flow of exception processing is like the following diagram:
![](http://byfiles.storage.live.com/y1pS60bF71IDXx_oQqdBpEyUfJyxEWkBdU_hn-4TnFHXs_jOdyxUFlJDhLL2-wUDSJLTt0o1x9d7j8)
As
said above, exception handlers for different causes are registered to
exception_handlers[32] and exception_vec3_generic is copied to EBase +
0x180, so when there is exception, CPU will jump to EBase + 0x180 and
except_vec3_generic() will be called.
The
except_vec3_generic() is implemented in
Linux-2.6.18/arch/mips/kernel/genex.S. In this function, it will read
the Cause register to get the ExcCode firstly, then it will use this
ExcCode to get the corresponding exception handler from
exception_handler[32] array and execute the exception handler.
For
example, when user calls system calling function, it will use “syscall”
instruction to generate the exception, for which the ExcCode is 8; When
CPU gets this exception, it will call except_vec3_generic() to handle
it: get the exception handler for ExcCode 8 (handle_sys()) from
exception_handler[32] array and execute handle_sys() function.
3.
How to handle Interrupt
In
Linux 2.6.18, it defines an array irq_desc[NR_IRQS] in
linux-2.6.18/include/linux/irq.h to store the information needed by
interrupt handler. This array item is a structure “struct irq_desc”
which is defined in the same file.
When
Linux device driver registers it’s interrupt handler with request_irq()
API, this API will call setup_irq() function to check the flags and
store the interrupt handler to irq_desc[] array according to the
registered irq number. Both these functions are implemented in
linux-2.6.18/kernel/irq/manage.c.
When
an interrupt is detected by CPU, it will jump to EBase + 0x200 and
“handle_int()” will be called which is implemented in
Linux-2.6.18/arch/mips/kernel/genex.S. The following is the source code
for this function:
NESTED(handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
TRACE_IRQS_OFF
PTR_LA
ra, ret_from_irq
move
a0, sp
j
plat_irq_dispatch
END(handle_int)
From
the code, we can see that it will save all GPR firstly, then disable
interrupt and call plat_irq_dispatch() function; after it return from
plat_irq_dispatch() function, it will call ret_from_irq() function to
restore GPR registers and enable the interrupt.
The
implementation of plat_irq_dispatch() function is related with
different platform. However, it’s basic function is like this: Read
Status and Cause register to get the interrupt source firstly, then get
the exact irq number according it’s interrupt design; at the end of
this function, it will call do_IRQ() function.
The
do_IRQ() function will get the interrupt handler from irq_desc[] array
according to irq number and execute the interrupt handler. This
implementation of this function is in
linux-2.6.18/arch/mips/kernel/irq.c.
The following diagram shows the brief processing flow of interrupt.
![](http://byfiles.storage.live.com/y1pS60bF71IDXx5Sswkq9h_eyc7sxtmKdpNsk_7zC8_7RZh3RCJadVYqCTmN8SpKrFolR--Nwlu_bo)
Implementation of exception in Linux (Cont)
Part 3: How to implement interrupt for new platform
When
adding a new platform in Linux kernel, two APIs are needed to be
implemented for interrupt part: arch_init_irq() and plat_irq_dispatch().
1.
arch_init_irq()
The
arch_init_irq() API is used to initialize the platform interrupt
controller and enable the MIPS interrupt according to it’s interrupt
source.
The reference code for this API is like the following:
static struct irq_chip newplat_irq_type = {
.typename = "Newplat",
.startup = startup_newplat_irq,
.shutdown = shutdown_newplat_irq,
.enable = enable_newplat_irq,
.disable = disable_newplat_irq,
.ack = ack_newplat_irq,
.end = end_newplat_irq,
};
static struct irqaction newplat_irq = {
.handler = no_action,
.name = "Newplat cascade"
};
void __init arch_init_irq(void)
{
int i;
/*TODO: Initialization for Platform interrupt related part */
...
/*Initialize irq_desc[] for the platform used irqs range*/
for (i = NEWPLAT_INT_BASE; i <= NEWPLAT_INT_END; i++) {
irq_desc[i].status
= IRQ_DISABLED;
irq_desc[i].action
= 0;
irq_desc[i].depth
= 1;
irq_desc[i].chip
= &newplat_irq_type;
spin_lock_init(&irq_desc[i].lock);
}
/*Assume MIPS interrupt source base is 0 in this platform*/
mips_cpu_irq_init(0);
/*Enable interrupt source 4*/
setup_irq(4, &newplat_irq);
}
In
this sample code, we assume only interrupt source 4 is used in this
platform and assume the base value for MIPS interrupt source is 0, so
the irq number for this platform must be larger than 7, which means “NEWPLAT_INT_BASE
” must be 8 or more.
We
define a structure newplat_irq_type in this same code and this
structure include many functions’ pointer: startup(), shutdown(),
enable(), disable(), ack() and end(). These functions’ implementation
is platform dependent and is valid for irq number between NEWPLAT_INT_BASE
and NEWPLAT_INT_END
. The following shows the general implementation for these functions.
void disable_newplat_irq(unsigned int irq_nr)
{
if(irq_nr < MIRA_INT_BASE)
return;
/*TODO: Disable the irq_nr interrupt, which means clear the interrupt mask bit for irq_nr*/
iob();
}
void enable_newplat_irq(unsigned int irq_nr)
{
if(irq_nr < MIRA_INT_BASE)
return;
/*TODO: Enable the irq_nr interrupt, which means set the interrupt mask bit for irq_nr*/
iob();
}
static unsigned int startup_newplat_irq(unsigned int irq)
{
enable_newplat_irq(irq);
return 0;
}
#define shutdown_newplat_irq
disable_newplat_irq
void ack_newplat_irq(unsigned int irq_nr)
{
if(irq_nr < MIRA_INT_BASE)
return;
/*TODO: Clear the interrupt status bit corresponding to irq_nr*/
iob();
}
static void end_newplat_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_newplat_irq(irq);
}
The
startup() or enable() function is called in setup_irq() function, which
is called by request_irq() API, so when device driver registers the
interrupt handler with request_irq(), it also enables this interrupt at
the same time. The shutdown() or disable() function is called in
free_irq() API to disable this interrupt when device driver calls
free_irq().
As
said before, the defined structure “newplat_irq_type” is only valid for
platform interrupt. For MIPS interrupt source (0-7 in our sample code),
the similar structure “mips_cpu_irq_controller” is defined in
linux-2.6.18/arch/mips/kernel/irq_cpu.c and this structure is connected
with the MIPS interrupt source (2-7) in mips_cpu_irq_init() API which
is called in arch_init_irq(). From the implementation of
arch_init_irq() API, we can see setup_irq() function is called
following mips_cpu_irq_init() function, so the startup() or enable()
function in “mips_cpu_irq_controller” structure will be called to set
the corresponding bits in Status[10:15] bits.
2. plat_irq_dispatch()
From
part2, we can see that the plat_irq_dispatch() function shall get the
interrupt source from Status and Cause registers firstly, then it shall
get the exact irq number from platform dependent interrupt controller.
The following code shows the general implementation:
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
/*Assume only interrupt source 4 is used in this platform*/
if (pending & CAUSEF_IP4)
newplat_hw4_irqdispatch(regs);
else
spurious_interrupt(regs);
}
void newplat_hw4_irqdispatch(struct pt_regs *regs)
{
int irq;
/*TODO: get the irq from platform dependent registers*/
do_IRQ(irq, regs);
}
Background
Inthe MIPS architecture, interrupt, traps, system calls and everything
else that can disrupt the normal flow of execution are called exception
and are handled by a single mechanism.
This
document introduces how these exceptions are supported in Linux kernel
and how to add implement interrupt handler for new MIPS platform..
The referenced code for this document is based on:
a)
Linux 2.6.18
b)
MIPS32 without EIC
Part 1: Introduction for MIPS exception
1.Exception vectors
All
exception entry points lie in un-translated regions of memory, kseg1
for uncached entry point and kseg0 for cached ones. The uncached entry
points used when SR(BEV) is set are fixed, while EBase register can be
programmed to shift all the entry points to another block when SR(BEV)
is cleared.
The following table shows the MIPS exception entry point:
Memory region | Entry point | Exception |
Reset | 0xBFC00000 | Reset and NMI |
ROM (SR(BEV) = 1) | 0xBFC00400 | Interrupts (Cause(IV) = 1) |
0xBFC00380 | General exceptions | |
0xBFC00300 | Cache error | |
0xBFC00200 | Simple TLB refill (SR(EXL) = 0) | |
RAM (SR(BEV) = 0) | EBase + 0x200 | Interrupts (Cause(IV) = 1) |
EBase + 0x180 | General exceptions | |
EBase + 0x100 | Cache error | |
EBase + 0x000 | Simple TLB refill (SR(EXL) = 0) |
Linux is running, SR(BEV) is cleared and EBase is set to 0x80000000 in
default, so we shall copy the general exceptions handler to 0x80000180
and interrupt handler to 0x80000200. Since the size for entry point is
limited, only a jump instruction is placed in every entry point in most
cases.
2.
Cause ExcCode
In
CP0 Cause register, there are 5 bits (Cause[2:6]) to tell you what kind
of exception happened, when we get exception, we need read this
register to know what causes this exception exactly. The following
table shows the ExcCode values and it is copied from “See MIPS Run”
The value is not listed in this table is not used currently.
Value | Description |
0 | Interrupt |
1 | Store but page is marked as read-only in TLB |
2/3 | TLBL/TLBS: No TLB translation |
4/5 | AdEL/AdES: Address error |
6/7 | IBE/DBE: Bus error |
8 | SysCall |
9 | Break, for debuggers |
10 | Instruction code not recognized |
11 | Coprocessor is not enabled in SR(CU0-3) |
12 | Overflow from trapping form of integer arithmetic |
13 | Teq register condition is met |
15 | Float point exception |
18 | Exception from coprocessor 2 |
22 | Tried to run MDMX instruction while SR(MX) is not set |
23 | Value in WatchLo/WatchHi register is met |
24 | CPU detected some disastrous error in the CPU control system |
25 | Thread related exception |
26 | Tried to run an DSP ASE instruction while it is not supported |
30 | Parity/ECC error somewhere in the core |
Interrupt enable
There
are 8 bits in CP0 Status Register SR[8:15] for interrupt mask. If there
is no EIC, MIPS can support 8 interrupt sources. When one or some bits
of SR[8:15] is set, the interrupt sources corresponding to these bits
will be allowed to cause an exception. Six of the interrupt sources are
generated by signals from outside the CPU core while the other two are
the software-writable interrupt bits in the Cause register. These bits
are enabled in arch_init_irq() API according to platform interrupt
design. The arch_init_irq() API will be introduced in part 3.
SR[0]
is the global interrupt enable bit. If we set this bit, we will allow
the interrupts corresponding to the set bits of SR[8:15] to be
generated. If we clear this bit, no interrupt will be generated.
Part 2: Implementation in Linux
1.Exception initialization in Linux
The exception initialization is implemented in
trap_init()
of
linux-2.6.18/arch/mips/kernel/trap.c
, which includes exception vectors install and exception handlers registering.
1)
exception vectors install
a)
At the beginning of this API, it will call the following statement to
copy the generic exception handler to EBase + 0x180, where is the
general exception entry point:
set_handler(0x180, &except_vec3_generic, 0x80);
b) At the end of this API, it will copy the exception handler to the different entry point according to different platform:
if (cpu_has_vce)
/* Special exception: R4[04]00 uses also the divec space. */
memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100);
else if (cpu_has_4kex)
memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80);
else
memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80);
c) For interrupt handler initialization, it will call the following statement to copy the general handler to entry point:
else if (cpu_has_divec)
set_handler(0x200, &except_vec4, 0x8);
please notice that “EBase + 0x200” is the interrupt handler entry point.
d)
Since ExcCode(0) means interrupt, it will set the interrupt handler
again when set exception vector for ExcCode(0) with
“set_except_vector(0, handle_int);”:
void *set_except_vector(int n, void *addr)
{
unsigned long handler = (unsigned long) addr;
unsigned long old_handler = exception_handlers
;
exception_handlers
= handler;
if (n == 0 && cpu_has_divec) {
*(volatile u32 *)(ebase + 0x200) = 0x08000000 |
(0x03ffffff & (handler >> 2));
flush_icache_range(ebase + 0x200, ebase + 0x204);
}
return (void *)old_handler;
}
According
to MIPS instruction encoding, 0x08000000 is a jump instruction, so the
actual instruction in EBase + 0x200 is “j handle_int”
2)
handlers registering
In
trap_init() API, it define a global array unsigned long
exception_handlers[32] to contain 32 exception handlers for 32 ExcCodes
and it will call set_except_vector() function to register these
handlers to this array.
set_except_vector(0, handle_int);
set_except_vector(1, handle_tlbm);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);
set_except_vector(4, handle_adel);
set_except_vector(5, handle_ades);
set_except_vector(6, handle_ibe);
set_except_vector(7, handle_dbe);
set_except_vector(8, handle_sys);
set_except_vector(9, handle_bp);
set_except_vector(10, handle_ri);
set_except_vector(11, handle_cpu);
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);
…
2.
How to handle exception
The basic flow of exception processing is like the following diagram:
As
said above, exception handlers for different causes are registered to
exception_handlers[32] and exception_vec3_generic is copied to EBase +
0x180, so when there is exception, CPU will jump to EBase + 0x180 and
except_vec3_generic() will be called.
The
except_vec3_generic() is implemented in
Linux-2.6.18/arch/mips/kernel/genex.S. In this function, it will read
the Cause register to get the ExcCode firstly, then it will use this
ExcCode to get the corresponding exception handler from
exception_handler[32] array and execute the exception handler.
For
example, when user calls system calling function, it will use “syscall”
instruction to generate the exception, for which the ExcCode is 8; When
CPU gets this exception, it will call except_vec3_generic() to handle
it: get the exception handler for ExcCode 8 (handle_sys()) from
exception_handler[32] array and execute handle_sys() function.
3.
How to handle Interrupt
In
Linux 2.6.18, it defines an array irq_desc[NR_IRQS] in
linux-2.6.18/include/linux/irq.h to store the information needed by
interrupt handler. This array item is a structure “struct irq_desc”
which is defined in the same file.
When
Linux device driver registers it’s interrupt handler with request_irq()
API, this API will call setup_irq() function to check the flags and
store the interrupt handler to irq_desc[] array according to the
registered irq number. Both these functions are implemented in
linux-2.6.18/kernel/irq/manage.c.
When
an interrupt is detected by CPU, it will jump to EBase + 0x200 and
“handle_int()” will be called which is implemented in
Linux-2.6.18/arch/mips/kernel/genex.S. The following is the source code
for this function:
NESTED(handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
TRACE_IRQS_OFF
PTR_LA
ra, ret_from_irq
move
a0, sp
j
plat_irq_dispatch
END(handle_int)
From
the code, we can see that it will save all GPR firstly, then disable
interrupt and call plat_irq_dispatch() function; after it return from
plat_irq_dispatch() function, it will call ret_from_irq() function to
restore GPR registers and enable the interrupt.
The
implementation of plat_irq_dispatch() function is related with
different platform. However, it’s basic function is like this: Read
Status and Cause register to get the interrupt source firstly, then get
the exact irq number according it’s interrupt design; at the end of
this function, it will call do_IRQ() function.
The
do_IRQ() function will get the interrupt handler from irq_desc[] array
according to irq number and execute the interrupt handler. This
implementation of this function is in
linux-2.6.18/arch/mips/kernel/irq.c.
The following diagram shows the brief processing flow of interrupt.
Implementation of exception in Linux (Cont)
Part 3: How to implement interrupt for new platform
Whenadding a new platform in Linux kernel, two APIs are needed to be
implemented for interrupt part: arch_init_irq() and plat_irq_dispatch().
1.
arch_init_irq()
The
arch_init_irq() API is used to initialize the platform interrupt
controller and enable the MIPS interrupt according to it’s interrupt
source.
The reference code for this API is like the following:
static struct irq_chip newplat_irq_type = {
.typename = "Newplat",
.startup = startup_newplat_irq,
.shutdown = shutdown_newplat_irq,
.enable = enable_newplat_irq,
.disable = disable_newplat_irq,
.ack = ack_newplat_irq,
.end = end_newplat_irq,
};
static struct irqaction newplat_irq = {
.handler = no_action,
.name = "Newplat cascade"
};
void __init arch_init_irq(void)
{
int i;
/*TODO: Initialization for Platform interrupt related part */
...
/*Initialize irq_desc[] for the platform used irqs range*/
for (i = NEWPLAT_INT_BASE; i <= NEWPLAT_INT_END; i++) {
irq_desc[i].status
= IRQ_DISABLED;
irq_desc[i].action
= 0;
irq_desc[i].depth
= 1;
irq_desc[i].chip
= &newplat_irq_type;
spin_lock_init(&irq_desc[i].lock);
}
/*Assume MIPS interrupt source base is 0 in this platform*/
mips_cpu_irq_init(0);
/*Enable interrupt source 4*/
setup_irq(4, &newplat_irq);
}
In
this sample code, we assume only interrupt source 4 is used in this
platform and assume the base value for MIPS interrupt source is 0, so
the irq number for this platform must be larger than 7, which means “NEWPLAT_INT_BASE
” must be 8 or more.
We
define a structure newplat_irq_type in this same code and this
structure include many functions’ pointer: startup(), shutdown(),
enable(), disable(), ack() and end(). These functions’ implementation
is platform dependent and is valid for irq number between NEWPLAT_INT_BASE
and NEWPLAT_INT_END
. The following shows the general implementation for these functions.
void disable_newplat_irq(unsigned int irq_nr)
{
if(irq_nr < MIRA_INT_BASE)
return;
/*TODO: Disable the irq_nr interrupt, which means clear the interrupt mask bit for irq_nr*/
iob();
}
void enable_newplat_irq(unsigned int irq_nr)
{
if(irq_nr < MIRA_INT_BASE)
return;
/*TODO: Enable the irq_nr interrupt, which means set the interrupt mask bit for irq_nr*/
iob();
}
static unsigned int startup_newplat_irq(unsigned int irq)
{
enable_newplat_irq(irq);
return 0;
}
#define shutdown_newplat_irq
disable_newplat_irq
void ack_newplat_irq(unsigned int irq_nr)
{
if(irq_nr < MIRA_INT_BASE)
return;
/*TODO: Clear the interrupt status bit corresponding to irq_nr*/
iob();
}
static void end_newplat_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_newplat_irq(irq);
}
The
startup() or enable() function is called in setup_irq() function, which
is called by request_irq() API, so when device driver registers the
interrupt handler with request_irq(), it also enables this interrupt at
the same time. The shutdown() or disable() function is called in
free_irq() API to disable this interrupt when device driver calls
free_irq().
As
said before, the defined structure “newplat_irq_type” is only valid for
platform interrupt. For MIPS interrupt source (0-7 in our sample code),
the similar structure “mips_cpu_irq_controller” is defined in
linux-2.6.18/arch/mips/kernel/irq_cpu.c and this structure is connected
with the MIPS interrupt source (2-7) in mips_cpu_irq_init() API which
is called in arch_init_irq(). From the implementation of
arch_init_irq() API, we can see setup_irq() function is called
following mips_cpu_irq_init() function, so the startup() or enable()
function in “mips_cpu_irq_controller” structure will be called to set
the corresponding bits in Status[10:15] bits.
2. plat_irq_dispatch()
From
part2, we can see that the plat_irq_dispatch() function shall get the
interrupt source from Status and Cause registers firstly, then it shall
get the exact irq number from platform dependent interrupt controller.
The following code shows the general implementation:
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
/*Assume only interrupt source 4 is used in this platform*/
if (pending & CAUSEF_IP4)
newplat_hw4_irqdispatch(regs);
else
spurious_interrupt(regs);
}
void newplat_hw4_irqdispatch(struct pt_regs *regs)
{
int irq;
/*TODO: get the irq from platform dependent registers*/
do_IRQ(irq, regs);
}
相关文章推荐
- the implementation of system call in linux
- Eclipse 报 “Exception in thread "main" java.lang.OutOfMemoryError: Java heap space ”错误的解决办法
- Tomcat内存溢出的原因--Exception in thread “RMI TCP Connection(idle)” ---OutOfMemoryError: PermGen space
- Exception in thread "http-bio-8080-exec-2" java.lang.OutOfMemoryError: PermGen space[解决方案]
- Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
- javax.management.MalformedObjectNameException: Invalid character '' in value part of property ,Oracle 驱动包的错误
- Linux 下运行Java程序报“Exception in thread "main" java.lang.NoClassDefFoundError”
- Exception in thread "main" java.io.IOException: Failed to set permissions of path
- Rsync (Remote Sync): 10 Practical Examples of Rsync Command in Linux
- Implementation of SOAP protocol in Java
- Exception in thread ""http-bio-80"exec-1" java.lang.OutOfMemoryError: PermGen s解决方案
- the diary of sleep jobs & fg command line in linux
- Intellij出现错误Exception in thread "RMI TCP Connection(idle)" java.lang.OutOfMemoryError: PermGen space
- Linux环境下,Exception in thread "main" java.lang.NoClassDefFoundError
- the diary of homework of script check dir in linux
- Bsu 打补丁 出现Exception in thread "main" java.lang.OutOfMemoryError:Java heap space报错
- I/O of select in linux
- 在Linux中部署web项目 java.util.zip.ZipException: error in opening zip file
- tomcat,javax.management.MalformedObjectNameException: Invalid character ':' in value part of propert
- How to find PID of process listening on a port in Linux? netstat and lsof command examples