xenarm irq routine
/*
当一个异常出现以后,ARM微处理器会执行以下几步操作: (这些是中断发生时,自动处理的)
1、 将下一条指令的地址存入相应连接寄存器LR,以便程序在处理异常返回时能从正确的位置重新开始执行。若异常是从ARM状态进入,LR寄存器中保存的是下一 条指令的地址(当前PC+4或PC+8,与异常的类型有关);若异常是从Thumb状态进入,则在LR寄存器中保存当前 PC的偏移量,这样,异常处理程序就不需要确定异常是从何种状态进入的。例如:在软件中断异常SWI,指令MOV PC,R14_svc总是返回到下一条指令,不管SWI是在ARM状态执行,还是在Thumb状态执行。
2、将CPSR复制到相应的SPSR中。
3、根据异常类型,强制设置CPSR的运行模式位。
4、 强制PC从相关的异常向量地址取下一条指令执行,从而跳转到相应的异常处理程序处。还可以设置中断禁止位,以禁止中断发生.当有异常发生时,处理器会跳转 到对应的0xffff0000起始的向量处取指令,然后,通过b指令散转到异常处理代码.因为ARM中b指令是相对跳转,而 且只有+/-32MB的寻址范围,所以把__stubs_start~__stubs_end之间的异常处理代码复制到了0xffff0200起始处.这 里可直接用b指令跳转过去,这样比使用绝对跳转(ldr)效率高。
*/
b vector_undefined_instruction + stubs_offset
ldr pc, .LCvswi + stubs_offset
b vector_prefetch_abort + stubs_offset
b vector_data_abort + stubs_offset
b vector_addrexcptn + stubs_offset
b vector_irq + stubs_offset
b vector_FIQ + stubs_offset
#define INSTALL_VECTOR_STUB(name, offset, mode, correction, branch_table)
vector_##name:
vector_stub offset, mode, correction, branch_table
.macro vector_stub offset, mode, correction, branch_table
sub sp, sp, #16
sub lr, lr, #correction @修正返回地址
stmia sp!, {r0, lr}
mrs r0, spsr @spsr保存的是cpsr的值
mov lr, #offset
stmia sp!, {r0, lr}
mrs lr, cpsr
eor lr, lr, #(mode ^ PSR_MODE_SVC)
msr spsr_cxsf, lr @改变spsr以重启irq @ switch to SVC_32 mode
and r0, r0, #15
adr lr, branch_table
ldr lr, [lr, r0, lsl #2] @根据spsr内容来决定进入哪一个irq_
sub r0, sp, #16
movs pc, lr @ Changes mode and branches
.endm
__irq_svc:
save_svc_context
#ifdef CONFIG_MACHINE_VERSATILE
get_irqnr_preamble r5, lr @ minsung
#endif
1: get_irqnr_and_base r0, r6, r5, lr
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, 1b
bne asm_do_IRQ
/* restore svc mode register */
ldr r0, [sp, #S_PSR] @ irqs are already disabled
msr spsr_cxsf, r0
ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
.macro save_svc_context
sub sp, sp, #S_FRAME_SIZE
SPFIX( tst sp, #4 )
SPFIX( bicne sp, sp, #4 )
stmib sp, {r1 - r12}
ldmia r0, {r1 - r4}
add r5, sp, #S_SP
add r0, sp, #S_FRAME_SIZE
SPFIX( addne r0, r0, #4 )
str r1, [sp] @ Save real R0
mov r1, lr
stmia r5, {r0 - r4}
.endm
/*
从下面这段程序可以看出来,
如何获得goldfish中断号,
如何获得goldfish状态
如果没有中断号,还可以设置条件描述符
*/
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
ldr base, =IO_ADDRESS(GOLDFISH_INTERRUPT_BASE)
ldr irqnr, [base, #GOLDFISH_INTERRUPT_NUMBER]
ldr irqstat, [base, #GOLDFISH_INTERRUPT_STATUS]
teq irqstat, #0
/* EQ will be set if no irqs pending */
.endm
/*
时间中断来了,仅仅是打开了一个软中断而已。
*/
irqreturn_t goldfish_timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
{
uint32_t timer_base = IO_ADDRESS(GOLDFISH_TIMER_BASE);
timer_tick(regs);
raise_softirq(TIMER_SOFTIRQ);
__raw_writel(1, timer_base + TIMER_CLEAR_INTERRUPT);
goldfish_timer_set_next_event(LATCH);
return IRQ_HANDLED;
}
//软中断,跟定时器又联系上了。
static void timer_softirq_action(void)
{
int cpu = smp_processor_id();
struct timer *t, **heap;
s_time_t now;
void (*fn)(void *);
void *data;
DPRINTK(5, "%s:%dn", __FUNCTION__, __LINE__);
spin_lock_irq(&timers[cpu].lock);
do {
heap = timers[cpu].heap;
now = NOW();
while ( (GET_HEAP_SIZE(heap) != 0) && ( (t = heap[1])->expires < (now + (s_time_t)TIMER_SLOP) ) )
{
remove_entry(heap, t);
timers[cpu].running = t;
fn = t->function;
data = t->data;
// printk("fn:%x", fn);
spin_unlock_irq(&timers[cpu].lock);
(*fn)(data);//执行定时器routine
DPRINTK(5, "%s:%dn", __FUNCTION__, __LINE__);
spin_lock_irq(&timers[cpu].lock);
/* Heap may have grown while the lock was released. */
heap = timers[cpu].heap;
}
timers[cpu].running = NULL;
}
while ( !reprogram_timer(GET_HEAP_SIZE(heap) ? heap[1]->expires : 0) );
DPRINTK(5, "%s:%dn", __FUNCTION__, __LINE__);
spin_unlock_irq(&timers[cpu].lock);
}
/*
从异常返回
异常处理完毕之后,ARM微处理器会执行以下几步操作从异常返回:
1、将连接寄存器LR的值减去相应的偏移量后送到PC中。
2、将SPSR复制回CPSR中。
3、若在进入异常处理时设置了中断禁止位,要在此清除。
*/
当一个异常出现以后,ARM微处理器会执行以下几步操作: (这些是中断发生时,自动处理的)
1、 将下一条指令的地址存入相应连接寄存器LR,以便程序在处理异常返回时能从正确的位置重新开始执行。若异常是从ARM状态进入,LR寄存器中保存的是下一 条指令的地址(当前PC+4或PC+8,与异常的类型有关);若异常是从Thumb状态进入,则在LR寄存器中保存当前 PC的偏移量,这样,异常处理程序就不需要确定异常是从何种状态进入的。例如:在软件中断异常SWI,指令MOV PC,R14_svc总是返回到下一条指令,不管SWI是在ARM状态执行,还是在Thumb状态执行。
2、将CPSR复制到相应的SPSR中。
3、根据异常类型,强制设置CPSR的运行模式位。
4、 强制PC从相关的异常向量地址取下一条指令执行,从而跳转到相应的异常处理程序处。还可以设置中断禁止位,以禁止中断发生.当有异常发生时,处理器会跳转 到对应的0xffff0000起始的向量处取指令,然后,通过b指令散转到异常处理代码.因为ARM中b指令是相对跳转,而 且只有+/-32MB的寻址范围,所以把__stubs_start~__stubs_end之间的异常处理代码复制到了0xffff0200起始处.这 里可直接用b指令跳转过去,这样比使用绝对跳转(ldr)效率高。
*/
b vector_undefined_instruction + stubs_offset
ldr pc, .LCvswi + stubs_offset
b vector_prefetch_abort + stubs_offset
b vector_data_abort + stubs_offset
b vector_addrexcptn + stubs_offset
b vector_irq + stubs_offset
b vector_FIQ + stubs_offset
#define INSTALL_VECTOR_STUB(name, offset, mode, correction, branch_table)
vector_##name:
vector_stub offset, mode, correction, branch_table
.macro vector_stub offset, mode, correction, branch_table
sub sp, sp, #16
sub lr, lr, #correction @修正返回地址
stmia sp!, {r0, lr}
mrs r0, spsr @spsr保存的是cpsr的值
mov lr, #offset
stmia sp!, {r0, lr}
mrs lr, cpsr
eor lr, lr, #(mode ^ PSR_MODE_SVC)
msr spsr_cxsf, lr @改变spsr以重启irq @ switch to SVC_32 mode
and r0, r0, #15
adr lr, branch_table
ldr lr, [lr, r0, lsl #2] @根据spsr内容来决定进入哪一个irq_
sub r0, sp, #16
movs pc, lr @ Changes mode and branches
.endm
__irq_svc:
save_svc_context
#ifdef CONFIG_MACHINE_VERSATILE
get_irqnr_preamble r5, lr @ minsung
#endif
1: get_irqnr_and_base r0, r6, r5, lr
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, 1b
bne asm_do_IRQ
/* restore svc mode register */
ldr r0, [sp, #S_PSR] @ irqs are already disabled
msr spsr_cxsf, r0
ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
.macro save_svc_context
sub sp, sp, #S_FRAME_SIZE
SPFIX( tst sp, #4 )
SPFIX( bicne sp, sp, #4 )
stmib sp, {r1 - r12}
ldmia r0, {r1 - r4}
add r5, sp, #S_SP
add r0, sp, #S_FRAME_SIZE
SPFIX( addne r0, r0, #4 )
str r1, [sp] @ Save real R0
mov r1, lr
stmia r5, {r0 - r4}
.endm
/*
从下面这段程序可以看出来,
如何获得goldfish中断号,
如何获得goldfish状态
如果没有中断号,还可以设置条件描述符
*/
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
ldr base, =IO_ADDRESS(GOLDFISH_INTERRUPT_BASE)
ldr irqnr, [base, #GOLDFISH_INTERRUPT_NUMBER]
ldr irqstat, [base, #GOLDFISH_INTERRUPT_STATUS]
teq irqstat, #0
/* EQ will be set if no irqs pending */
.endm
/*
时间中断来了,仅仅是打开了一个软中断而已。
*/
irqreturn_t goldfish_timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
{
uint32_t timer_base = IO_ADDRESS(GOLDFISH_TIMER_BASE);
timer_tick(regs);
raise_softirq(TIMER_SOFTIRQ);
__raw_writel(1, timer_base + TIMER_CLEAR_INTERRUPT);
goldfish_timer_set_next_event(LATCH);
return IRQ_HANDLED;
}
//软中断,跟定时器又联系上了。
static void timer_softirq_action(void)
{
int cpu = smp_processor_id();
struct timer *t, **heap;
s_time_t now;
void (*fn)(void *);
void *data;
DPRINTK(5, "%s:%dn", __FUNCTION__, __LINE__);
spin_lock_irq(&timers[cpu].lock);
do {
heap = timers[cpu].heap;
now = NOW();
while ( (GET_HEAP_SIZE(heap) != 0) && ( (t = heap[1])->expires < (now + (s_time_t)TIMER_SLOP) ) )
{
remove_entry(heap, t);
timers[cpu].running = t;
fn = t->function;
data = t->data;
// printk("fn:%x", fn);
spin_unlock_irq(&timers[cpu].lock);
(*fn)(data);//执行定时器routine
DPRINTK(5, "%s:%dn", __FUNCTION__, __LINE__);
spin_lock_irq(&timers[cpu].lock);
/* Heap may have grown while the lock was released. */
heap = timers[cpu].heap;
}
timers[cpu].running = NULL;
}
while ( !reprogram_timer(GET_HEAP_SIZE(heap) ? heap[1]->expires : 0) );
DPRINTK(5, "%s:%dn", __FUNCTION__, __LINE__);
spin_unlock_irq(&timers[cpu].lock);
}
/*
从异常返回
异常处理完毕之后,ARM微处理器会执行以下几步操作从异常返回:
1、将连接寄存器LR的值减去相应的偏移量后送到PC中。
2、将SPSR复制回CPSR中。
3、若在进入异常处理时设置了中断禁止位,要在此清除。
*/
评论
发表评论