微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux 中断向量表建立流程

ARM Linux 中断向量表建立流程

时间:11-09 来源:互联网 点击:

堆栈指针的地址round到8K地址边界上,这样它认为就得到了当前进程的task_struct数据结构了。它是因为内核在为每个进程分配一个task_struct结构时,实际上是分配两个连续的物理页面的(共8K),这两个页面的底部是用作进程的task_struct结构,而在结构的上面就用作进程的系统空间堆栈;数据结构task_struct的大小约为1K,进程系统空间堆栈大小就约为7K。当进程在系统空间运行时,常常需要访问当前进程自身的task_struct数据结构,为此内核中定义了一个宏操作current,提供指向当前进程task_struct结构的指针,它的实现实际上也与这里的get_current_task宏是差不多的。
/* include/asm-arm/current.h */
static inline struct task_struct *get_current(void)
{
register unsigned long sp asm ("sp");
return (struct task_struct *)(sp & ~0x1fff);
}
#define current (get_current())
再回到lin860,get_current_task的参数是tsk,它实际上是r9寄存器,它也是定义于arch/arm/kernel/entry-header.S中的:
tsk .req r9 @ current task
这样r9寄存器就保存了当前进程的task_struct结构的指针了。
Line861,程序跳转到ret_to_user,以完成从中断处理到返回用户空间的过程,前面提到的进程重新调度将在那里得以体现。ret_to_user定义于arch/arm/entry-common.S中:
55 reschedule:
56 bl SYMBOL_NAME(schedule)
57 ret_disable_irq:
58 disable_irq r1 @ ensure IRQs are disabled
59 ENTRY(ret_to_user)
60 ret_slow_syscall:
61 ldr r1, [tsk, #TSK_NEED_RESCHED]
62 ldr r2, [tsk, #TSK_SIGPENDING]
63 teq r1, #0 @ need_resched => schedule()
64 bne reschedule
65 1: teq r2, #0 @ sigpending => do_signal()
66 bne __do_signal
67 restore:
68 restore_user_regs
69
70 __do_signal:
71 enable_irq r1
72 mov r0, #0 @ NULL oldset
73 mov r1, sp @ regs
74 mov r2, why @ syscall
75 bl SYMBOL_NAME(do_signal) @ note the bl above sets lr
76 disable_irq r1 @ ensure IRQs are disabled
77 b restore
Line61,TSK_NEED_RESCHED值为20,它是task_struct结构中其成员变量need_resched相对于结构首地址的偏移量,所以此时r1的值就是当前进程task_struct结构里need_resched变量的值。同理在line62,r2存储就是task_struct->sigpenging的值。
从line63~64可见,只有在当前进程的task_struct结构中的need_resched字段为非0时才会转到reschedule处去调用schedule,那么,谁来设置这个字段呢?当然是内核,从用户空间是访问不到进程的task_struct结构的,那么,内核又是在什么情况下设置这个字段的呢?除当前进程通过系统调用自愿让出运行以及在系统调用中因某种原因受阻以外,主要就是当因某种原因唤醒一个进程的时候,以及在时钟中断服务程序发现当前进程已经连续运行太久的时候。(此段摘抄于Linux内核源代码情景分析》)
Line65~66,如果当前进程的task_struct结构中的sigpedding字段为非0时才会转到__do_signal处去调用do_signal处理信号。
Line68, restore_user_regs,它是一个宏定义于arch/arm/kernel/head-header.S中:
102 /*
103 * Must be called with IRQs already disabled.
104 */
105 .macro restore_user_regs
106 ldr r1, [sp, #S_PSR] @ Get calling cpsr
107 ldr lr, [sp, #S_PC]! @ Get PC
108 msr spsr, r1 @ save in spsr_svc
109 ldmdb sp, {r0 - lr}^ @ Get calling r0 - lr
110 mov r0, r0
111 add sp, sp, #S_FRAME_SIZE - S_PC
112 movs pc, lr @ return & move spsr_svc into cpsr
113 .endm
17 and lr, lr, #15
18 ldr lr, [pc, lr, lsl #2]
19 movs pc, lr @ Changes mode and branches
20
21.LCtab_irq: .word __irq_usr @ 0 (USR_26 / USR_32)
22 .word __irq_invalid @ 1 (FIQ_26 / FIQ_32)
23 .word __irq_invalid @ 2 (IRQ_26 / IRQ_32)
24 .word __irq_svc @ 3 (SVC_26 / SVC_32)
这里有点疑惑要进入__irq_usr,则18行lr应该为pc+4那么向回推算第7行的mrs lr, spsr中spsr[3:0]应该为0b0001;如果要进入__irq_svc,则18行lr应该为pc+16,那么spsr[3:0]应该为0b0100;
而cprs[4:0]=
10000 User 模式
10011 SVC 模式
请达人指点迷津。。。。)
行19,跳转到相应入口,并且ARM寄存器r13和r14则切换到了SVC模式下的寄存器
这里第18行中的pc值正好是21行的.LCtab_irq,如果是在用户空间,User模式10000,逻辑左移两位为0x0=0b0000,即pc+0x0,恰好到了.word __irq_usr ,如果是在内核空间,svc模式10011,移位后为0xc=0b1100,及pc+0xc,正好到了.word __irq_svc,一点都没错(当然不可能错,系统不是跑得好好的吗)
注意,pc值是当前指令地址+8
关于get_irqnr_and_base宏中:
bics irqstat, irqstat, irqnr 对照intmsk将intpnd中禁止的中断清0。因为intpnd在某一时刻只可以有一位为1,所以有一位被bics清0了,就会影响标志位从而beq跳转,return r0=0;从1001:开始所作的事情是循环查intpnd哪一位置为了1。有点疑惑的是tst 指令:
tst 类似于 CMP,不产生放置到目的寄存器中的结果。而是在给出的两个操作数上进行操作并把结果反映到状态标志上。使用 tst 来检查是否设置了特定的位。操作数 1 是要测试的数据字而操作数 2 是一个位掩码。经过测试后,如果匹配则设置 Zero 标志,否则清除它。
那么这里的tst irqstat, #1,当zero置1了表示有中断位,为什么下面是bne 1002f而不是beq?请教请教。。。。。。。)
没找到你看的内核版本中该宏的详细定义,我在我的2.6.12中pxa体系中的此宏中没找到tst指令,但想你的问题估计还是对tst的误解
pc值是当前指令地址+8
是因为armv5是三级流水线么?
pxa的宏里面好像是没用tst,这里我引申到s3c2410的宏里面。
tst的定义我翻的是网上搜的arm指令集,里面是这么说的:
TST : 测试位
(Test bits)
TST{条件}{P} ,
Status = op_1 AND op_2
TST 类似于 CMP,不产生放置到目的寄存器中的结果。而是在给出的两个操作数上进行操作并把结果反映到状态标志上。使用 TST 来检查是否设置了特定的位。操作数 1 是要测试的数据字而操作数 2 是一个位掩码。经过测试后,如果匹配则设置 Zero 标志,否则清除它。象 CMP 那样,你不需要指定 S 后缀。
TST R0, #%1 ; 测试在 R0 中是否设置了位 0。
我觉得在这里是有点转不过弯来了,,,
ARM linux的中断向量表初始化分析
Author: jimmy.li
Time: 2007-06-09

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top