Andor 发表于 2004-6-2 02:10:53

arm linux日记(1)

在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,
5                mrs lr, spsr
6                str lr,
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,
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

啊~,困了,休息。明天继续:)

faint 发表于 2004-6-6 00:56:59

顶一下!

Anomymous 发表于 2004-6-10 11:13:41

好文章,受益非浅

walimis 发表于 2004-6-24 14:35:13

建议使用skyeye来研究armlinux,源代码+运行效果,什么都尽在掌握。如果感兴趣,可以加入skyeye的开发,我们现在需要人手。目前成功支持的armlinux有
ep7312,pxa250,strongarm1100。
正在支持的有:
at91rm920,s3c2410。
另外,还可以跑uclinux for at91和s3c4510.

jackzheng2002 发表于 2004-6-24 16:50:57

哪里有详细的文档 :arrow:

liuspider 发表于 2004-7-18 07:17:29

光驱的问题看看是不是由于数据线引起的,试试换一个ide口

liangzhang 发表于 2004-8-3 13:36:36

ding yixia

theseus 发表于 2004-8-20 22:28:34

研究嵌入式Linux还是不要从Linux入手,否则事倍功半。
先从CPU的体系结构入手,然后就是CPU的汇编,再上升到Linux上,事半功倍。
事实上,搞懂了ARM的体系结构和外设接口,上面的代码是非常容易的。

lizw 发表于 2004-8-23 17:27:12

谢谢,上面的兄弟指点
我明白了

itnow 发表于 2004-8-31 09:08:45

是是是,,那哪里有CPU的体系结构呢》?41

winme 发表于 2004-8-31 21:59:22

我们公司好象用的是个ttlinux的,打开看是 RED HAT LINUX 7 的

jackzheng2002 发表于 2004-8-31 23:05:36

:)

xbzjackey 发表于 2007-1-30 17:45:19

狂顶,好文章,加油!
页: [1]
查看完整版本: arm linux日记(1)