在google上輸入arm linux,找到全是如何配制,就沒有人解釋一下嗎?靠,我覺得不僅要知其然,還要知其所以然。不知道放哪里好。我喜歡這里,所以來這里投,試試 還有,我的機還在用PII,老是出問題,前不久,分區(qū)就沒了一會,心痛啊。。。。。。。。。!好多好東東都沒了。順便問一下大家誰有碰到過沒有光驅(qū)接上,硬盤就不能啟動的問題啊。這個問題可把我這個自稱高手的人給難壞了 2004.5.23
今天開始,我要好好看看arm linux的代碼了,好久沒有這樣的豪言壯語了 拿哪個開刀呢。翻翻以前的工作,加上正好有人問,所以決定先搞定entry-armv.S文件。 看我一刀
文件一開始是一大堆宏定義,用于指明是用的何種芯片。定義了三個針對不同芯片的宏,disable_fiq、get_irqnr_and_base和irq_prio_table。
跳過這些宏,來到: .section “.text.init”, #alloc, #execinstr 這里說明了下面的段是初始化段,有關(guān)初始化段的內(nèi)容參考書籍。
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地址的內(nèi)容到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.恢復(fù)發(fā)生中斷時的地址(該地址即是中斷返回地址),參考ARM IRQ異常的書籍。 4.保存返回地址到r13,前面看到了r13的賦值情況,所以地址是被保存在__temp_irq的第一個word中。 5.讀取中斷發(fā)生時的CPSR,有關(guān)情況參考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,做與操作后,只保留其模式位。即說明該中斷發(fā)生自何種模式下。 12.讀取.LCtab_irq中的內(nèi)容,放置于lr寄存器中。而.LCtab_irq中保存了中斷發(fā)生自各種不同模式下的處理函數(shù)。其中使用了pc寄存器,詳情參考ARM書籍。 13.切換模式并跳轉(zhuǎn)到相應(yīng)處理函數(shù)。
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.此函數(shù)是當(dāng)IRQ中斷發(fā)生在usr模式時,調(diào)用的。它首先從堆棧中保留出存放寄存器的空間,用于保存現(xiàn)場。在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使用的棧結(jié)構(gòu)如下圖: 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寄存器。因為這些寄存器得以保存。我們現(xiàn)在可以大膽的使用這些寄存器了 2.讀取.LCirq的內(nèi)容到r4寄存器中。.LCirq的定義如下: .LCirq .word __temp_irq 哈哈,在vector_IRQ中提到的__temp_irq在此顯身。我們知道__temp_irq中保存了些什么。我想各位應(yīng)該猜到了下面的代碼是什么了吧 在這里將.LCirq的地址放到r4寄存器中。 3.將r8指到前面所說的保存S_PC的地方。前面保存了r0-r12,還有S_SP、S_LR、S_PC、S_PSR、S_OLD_R0沒有保存。 4.讀取__temp_irq中的內(nèi)容 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
|