在google上输入arm linux,找到全是如何配制,就没有人解释一下吗?靠,我觉得不仅要知其然,还要知其所以然。不知道放哪里好。我喜欢这里,所以来这里投,试试 还有,我的机还在用PII,老是出问题,前不久,分区就没了一会,心痛啊!!!!!!!!!!!好多好东东都没了。顺便问一下大家谁有碰到过没有光驱接上,硬盘就不能启动的问题啊。这个问题可把我这个自称高手的人给难坏了 2004.5.23
今天开始,我要好好看看arm linux的代码了,好久没有这样的豪言壮语了 拿哪个开刀呢。翻翻以前的工作,加上正好有人问,所以决定先搞定entry-armv.S文件。 看我一刀
文件一开始是一大堆宏定义,用于指明是用的何种芯片。定义了三个针对不同芯片的宏,disable_fiq、get_irqnr_and_base和irq_prio_table。
跳过这些宏,来到: .section “.text.init”, #alloc, #execinstr 这里说明了下面的段是初始化段,有关初始化段的内容参考书籍。
1 vector_IRQ: 2 ldr r13, .LCsirq 3 sub lr, lr, #4 4 str lr, [r13] 5 mrs lr, spsr 6 str lr, [r13, #4] 7 mrs r13, spsr 8 bic r13, r13, #MODE_MASK 9 orr r13, r13, #MODE_SVC|I_BIT 10 msr spsr_c, r13 11 and lr, lr, #15 12 ldr lr, [pc, lr, lsl #2] 13 movs pc, lr 14 .LCtab_irq: .word __irq_usr 15 .word __irq_invalid 16 .word __irq_invalid 17 .word __irq_svc 18 .word __irq_invalid … 解释: 1.IRQ中断向量的入口 2.读取.LCsirq地址的内容到r13寄存器中。.LCsirq定义如下: .LCsirq: .word __temp_irq 即.LCsirq中保存了__temp_irq的地址,而__temp_irq定义如下: __temp_irq: .word 0 @saved lr_irq .word 0 @saved spsr_irq .word -1 @old_r0 从这里可以得出r13保存了__temp_irq的地址,而这个地址用来保存了lr_irq、spsr_irq、old_r0的值。具体情况参见下面的解释。 3.恢复发生中断时的地址(该地址即是中断返回地址),参考ARM IRQ异常的书籍。 4.保存返回地址到r13,前面看到了r13的赋值情况,所以地址是被保存在__temp_irq的第一个word中。 5.读取中断发生时的CPSR,有关情况参考ARM IRQ异常的书籍 6.保存CPSR到__temp_irq的第二个word中。 7.将SPSR保存到r13中。注:这里不使用lr,而要另赋值到r13中,是因为要改变SPSR的值,而原来的值也有用。所以改变用r13,原来的值用lr。 8.清除模式位。MODE_MASK的定义参见\linux-2.4.26\include\asm-arm\proc-armv\ ptrace.h文件: #define MODE_MASK 0x1f 9.在\linux-2.4.26\include\asm-arm\proc-armv\ ptrace.h下还定义了: #define SVC_MODE 0x13 #define I_BIT 0x80 这时r13被修改为禁止irq中断的svc模式。 10.将修改好的模式放入spsr中。 11.lr保留了原来的cpsr,做与操作后,只保留其模式位。即说明该中断发生自何种模式下。 12.读取.LCtab_irq中的内容,放置于lr寄存器中。而.LCtab_irq中保存了中断发生自各种不同模式下的处理函数。其中使用了pc寄存器,详情参考ARM书籍。 13.切换模式并跳转到相应处理函数。
0 __irq_usr: sub sp, sp, #S_FRAME_SIZE 1 stmia sp, {r0 - r12} 2 ldr r4, .LCirq 3 add r8, sp, #S_PC 4 ldmia r4, {r5 - r7} 5 stmia r8, {r5 - r7} 6 stmdb r8, {sp, lr}^ 7 alignment_trap r4, r7, __temp_irq 8 zero_fp 9 get_irqnr_and_base r0, r6, r5, lr 10 movne r1, sp 11 adrsvc ne, lr, 1b 12 bne do_IRQ 13 mov why, #0 14 get_current_task tsk 15 b ret_to_usr
解释: 0.此函数是当IRQ中断发生在usr模式时,调用的。它首先从堆栈中保留出存放寄存器的空间,用于保存现场。在entry-header.s中定义了如下宏: #define S_FRAME_SIZE 72 #define S_OLD_R0 68 #define S_PSR 64 #else #define S_FRAME_SIZE 68 #define S_OLD_R0 64 #define S_PSR 60 #endif
#define S_PC 60 #define S_LR 56 #define S_SP 52 #define S_IP 48 #define S_FP 44 #define S_R10 40 #define S_R9 36 #define S_R8 32 #define S_R7 28 #define S_R6 24 #define S_R5 20 #define S_R4 16 #define S_R3 12 #define S_R2 8 #define S_R1 4 #define S_R0 0 #define S_OFF 8 #define S_FRAME_SIZE 72 #define S_OLD_R0 68 #define S_PSR 64
从这些宏中,我们可以得到arm linux使用的栈结构如下图: 0 |-------------| | S_R0 | 4 |-------------| | S_R1 | 8 |-------------| | S_R2 | 12 |-------------| | S_R3 | 16 |-------------| | S_R4 | 20 |-------------| | S_R5 | 24 |-------------| | S_R6 | 28 |-------------| | S_R7 | 32 |-------------| | S_R8 | 36 |-------------| | S_R9 | 40 |-------------| | S_R10 | 44 |-------------| | S_FP | 48 |-------------| | S_IP | 52 |-------------| | S_SP | 56 |-------------| | S_LR | 60 |-------------| | S_PC | 64 |-------------| | S_PSR | 68 |-------------| | S_OLD_R0 | 72 |-------------|
注:这个图在arm linux中很重要!
1.保存如上图所示的r0到r12寄存器。因为这些寄存器得以保存。我们现在可以大胆的使用这些寄存器了 2.读取.LCirq的内容到r4寄存器中。.LCirq的定义如下: .LCirq .word __temp_irq 哈哈,在vector_IRQ中提到的__temp_irq在此显身。我们知道__temp_irq中保存了些什么。我想各位应该猜到了下面的代码是什么了吧 在这里将.LCirq的地址放到r4寄存器中。 3.将r8指到前面所说的保存S_PC的地方。前面保存了r0-r12,还有S_SP、S_LR、S_PC、S_PSR、S_OLD_R0没有保存。 4.读取__temp_irq中的内容 5.保存S_PC、S_PSR、S_OLD_R0。 6.保存S_SP、S_LR,要注意保存的是用户模式的sp和lr。 7.在entry-header.S中,定义了alignment_trap宏:
.macro alignment_trap, rbase, rtemp, sym #ifdef CONFIG_ALIGNMENT_TRAP #define OFF_CR_ALIGNMENT(x) cr_alignment - x
ldr \rtemp, [\rbase, #OFF_CR_ALIGNMENT(\sym)] mcr p15, 0, \rtemp, c1, c0 #endif .endm
|