arm汇编 调用linux中断,GNU ARM汇编(四)中断汇编之非嵌套中断处理

原标题:GNU ARM汇编(四)中断汇编之非嵌套中断处理

在写这篇blog之前,不得不感慨一句:纸上得来终觉浅,绝知此事要躬行.作为EE出身的,虽然好久好久没用汇编写 的中断了,但自我感觉对中断的理解还是比较深入的,本以为在 下搞个中断会很容易,谁知道断断续续花了我几周.完全用汇编写中断和用c中的_irq写中断还是有区别的,谁用谁知道.还是那句话:深入细节是必须的,也是值得的.

这一篇blog的理论知识主要来源于:《ARM System Developer's Guide》.

ARM的异常和相应的模式之间的对应关系见下表:

c86aa53aaf6783321db98a86ecb56936.png

当一个异常导致模式的改变时,内核自动地:

1、把cpsr保存到相应模式下的spsr

2、把pc保存到相应模式下的lr

3、设置cpsr为相应异常模式

4、设置pc为相应异常处理程序的入口地址

从异常中断处理程序返回包含下面两个操作:

1、从spsr_mode中恢复内容到cpsr中

2、从lr_mode中恢复内容到pc中,返回到异常中断的指令的下一条政令处执行.

上面刚提到了异常发生时内核的一些动作,那对与IRQ或者FIQ而言,还多一项变化:禁用相关的中断IRQ或FIQ,禁止同类型的其他中断被触发.

5c80c02e41cd859a47c406556259b300.png

对于最简单的的处理流程如下:

b66a366e8cfdfd28eb955e023efea0e3.png

下面给出汇编代码:

[cpp] view plaincopyprint?

/*

simple interruption

copyleft@dndxhej@gmail.com

*/

.equ NOINT, 0xc0

.equ WTCON, 0x53000000

.equ GPBCON, 0x56000010 @

.equ GPBDAT, 0x56000014 @led

.equ GPBUP, 0x56000018 @led

.equ GPFCON, 0x56000050 @interrupt config

.equ EINTMASK, 0x560000a4

.equ EXTINT0, 0x56000088

.equ EXTINT1, 0x5600008c

.equ EXTINT2, 0x56000090

.equ INTMSK, 0x4A000008

.equ EINTPEND, 0x560000a8

.equ INTSUBMSK, 0X4A00001C

.equ SRCPND, 0X4A000000

.equ INTPND, 0X4A000010

.global _start

_start: b reset

ldr pc, _undefined_instruction

ldr pc, _software_interrupt

ldr pc, _prefetch_abort

ldr pc, _data_abort

ldr pc, _not_used

@b irq

ldr pc, _irq

ldr pc, _fiq

_undefined_instruction: .word undefined_instruction

_software_interrupt: .word software_interrupt

_prefetch_abort: .word prefetch_abort

_data_abort: .word data_abort

_not_used: .word not_used

_irq: .word irq

_fiq: .word fiq

.balignl 16,0xdeadbeef

reset:

ldr r3, =WTCON

mov r4, #0x0

str r4, [r3] @ disable watchdog

ldr r0, =GPBCON

ldr r1, =0x15400

str r1, [r0]

ldr r2, =GPBDAT

ldr r1, =0x160

str r1, [r2]

bl delay

msr cpsr_c, #0xd2 @进入中断模式

ldr sp, =3072 @中断模式的栈指针定义

msr cpsr_c, #0xdf @进入系统模式

ldr sp, =4096 @设置系统模式的栈指针

@--------------------------------------------

ldr r0, =GPBUP

ldr r1, =0x03f0

str r1, [r0]

ldr r0, =GPFCON

ldr r1, =0x2ea@0x2

str r1, [r0]

ldr r0, =EXTINT0

ldr r1, =0x8f888@0x0@0x8f888 @~(7|(7<<4)|(7<<8)|(7<<16))

str r1, [r0]

ldr r0, =EINTPEND

ldr r1, =0xf0@0b10000

str r1, [r0]

ldr r0, =EINTMASK

ldr r1, =0x00@0b00000

str r1, [r0]

ldr r0, =SRCPND

ldr r1, =0xff@0x1@0b11111

str r1, [r0]

ldr r0, =INTPND

ldr r1, =0xff@0x1@0b11111

str r1, [r0]

ldr r0, =INTMSK

ldr r1, =0xffffff00@0b00000

str r1, [r0]

MRS r1, cpsr

BIC r1, r1, #0x80

MSR cpsr_c, r1

bl main

irq:

sub lr,lr,#4

stmfd sp!,{r0-r12,lr}

bl irq_isr

ldmfd sp!,{r0-r12,pc}^

irq_isr:

ldr r2, =GPBDAT

ldr r1, =0x0e0

str r1, [r2]

ldr r0,=EINTPEND

ldr r1,=0xf0

str r1,[r0]

ldr r0, =SRCPND

ldr r1, =0x3f@0b11111

str r1, [r0]

ldr r0, =INTPND

ldr r1, =0x3f@0b11111

str r1, [r0]

mov pc,lr

delay:

ldr r3,=0xffff

delay1:

sub r3,r3,#1

cmp r3,#0x0

bne delay1

mov pc,lr

main:

ledloop:

ldr r1,=0x1c0

str r1,[r2]

bl delay

ldr r1,=0x1a0

str r1,[r2]

bl delay

ldr r1,=0x160

str r1,[r2]

bl delay

ldr r1,=0x0e0

str r1,[r2]

bl delay

b ledloop

undefined_instruction:

nop

software_interrupt:

nop

prefetch_abort:

nop

data_abort:

nop

not_used:

nop

fiq:

nop

/* simple interruption copyleft@dndxhej@gmail.com */ .equ NOINT, 0xc0 .equ WTCON, 0x53000000 .equ GPBCON, 0x56000010 @led .equ GPBDAT, 0x56000014 @led .equ GPBUP, 0x56000018 @led .equ GPFCON, 0x56000050 @interrupt config .equ EINTMASK, 0x560000a4 .equ EXTINT0, 0x56000088 .equ EXTINT1, 0x5600008c .equ EXTINT2, 0x56000090 .equ INTMSK, 0x4A000008 .equ EINTPEND, 0x560000a8 .equ INTSUBMSK, 0X4A00001C .equ SRCPND, 0X4A000000 .equ INTPND, 0X4A000010 .global _start _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used @b irq ldr pc, _irq ldr pc, _fiq _undefined_instruction: .word undefined_instruction _software_interrupt: .word software_interrupt _prefetch_abort: .word prefetch_abort _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq .balignl 16,0xdeadbeef reset: ldr r3, =WTCON mov r4, #0x0 str r4, [r3] @ disable watchdog ldr r0, =GPBCON ldr r1, =0x15400 str r1, [r0] ldr r2, =GPBDAT ldr r1, =0x160 str r1, [r2] bl delay msr cpsr_c, #0xd2 @进入中断模式 ldr sp, =3072 @中断模式的栈指针定义 msr cpsr_c, #0xdf @进入系统模式 ldr sp, =4096 @设置系统模式的栈指针 @-------------------------------------------- ldr r0, =GPBUP ldr r1, =0x03f0 str r1, [r0] ldr r0, =GPFCON ldr r1, =0x2ea@0x2 str r1, [r0] ldr r0, =EXTINT0 ldr r1, =0x8f888@0x0@0x8f888 @~(7|(7<<4)|(7<<8)|(7<<16)) str r1, [r0] ldr r0, =EINTPEND ldr r1, =0xf0@0b10000 str r1, [r0] ldr r0, =EINTMASK ldr r1, =0x00@0b00000 str r1, [r0] ldr r0, =SRCPND ldr r1, =0xff@0x1@0b11111 str r1, [r0] ldr r0, =INTPND ldr r1, =0xff@0x1@0b11111 str r1, [r0] ldr r0, =INTMSK ldr r1, =0xffffff00@0b00000 str r1, [r0] MRS r1, cpsr BIC r1, r1, #0x80 MSR cpsr_c, r1 bl main irq: sub lr,lr,#4 stmfd sp!,{r0-r12,lr} bl irq_isr ldmfd sp!,{r0-r12,pc}^ irq_isr: ldr r2, =GPBDAT ldr r1, =0x0e0 str r1, [r2] ldr r0,=EINTPEND ldr r1,=0xf0 str r1,[r0] ldr r0, =SRCPND ldr r1, =0x3f@0b11111 str r1, [r0] ldr r0, =INTPND ldr r1, =0x3f@0b11111 str r1, [r0] mov pc,lr delay: ldr r3,=0xffff delay1: sub r3,r3,#1 cmp r3,#0x0 bne delay1 mov pc,lr main: ledloop: ldr r1,=0x1c0 str r1,[r2] bl delay ldr r1,=0x1a0 str r1,[r2] bl delay ldr r1,=0x160 str r1,[r2] bl delay ldr r1,=0x0e0 str r1,[r2] bl delay b ledloop undefined_instruction: nop software_interrupt: nop prefetch_abort: nop data_abort: nop not_used: nop fiq: nop

lds文件:

[cpp] view plaincopyprint?

OUTPUT_FORMAT("elf32-little", "elf32-littlearm", "elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS{

. = 0x00000000;

.text : {

*(.text)

*(.rodata)

}

.data ALIGN(4): {

*(.data)

}

.bss ALIGN(4): {

*(.bss)

}

}

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS{ . = 0x00000000; .text : { *(.text) *(.rodata) } .data ALIGN(4): { *(.data) } .bss ALIGN(4): { *(.bss) } }

makefile:

[cpp] view plaincopyprint?

CROSS = arm-linux-

CFLAGS = -nostdlib

int.bin: start.S

${CROSS}gcc $(CFLAGS) -c -o start.o start.S

${CROSS}ld -Tint.lds start.o -o int.elf

# ${CROSS}ld -Ttext-segment 0x30000000 start.o -o int.elf

${CROSS}objcopy -O binary -S int.elf int.bin

# rm -f *.o

clean:

rm -f *.elf *.o

rm -f int.bin

CROSS = arm-linux- CFLAGS = -nostdlib int.bin: start.S ${CROSS}gcc $(CFLAGS) -c -o start.o start.S ${CROSS}ld -Tint.lds start.o -o int.elf # ${CROSS}ld -Ttext-segment 0x30000000 start.o -o int.elf ${CROSS}objcopy -O binary -S int.elf int.bin # rm -f *.o clean: rm -f *.elf *.o rm -f int.bin

该程序实现的流水灯,然后四个按键可以实现外部中断.

代码中值得注意的地方有几点:

1、lds文件中的地址配为0x00000000,因为程序是download到nandflash中运行的.最开始这里写的是0x30000000,那在异常向量表中:

@b irq

ldr pc, _irq

就出现了一个问题:只能用b irq跳转,无法用ldr pc, _irq跳转.当时就觉得奇怪,找了半天原因.后来才知道b跳转和用ldr伪指令只有区别的:

b是位置无关的,ldr不是位置无关的

b的范围只能是前后16M,总共32M,而ldr是4G

ldr的跳转是根据_irq: .word irq的值,这个值是链接的时候确定的,也就是与链接地址相关.

所以在lds中链接地址改为0x00000000后,b和ldr都是正确的.

具体可以用dump看一下实际效果:

当lds中是0x30000000时,arm-linux-objdump -d int.elf结果如下:

30000000 <_start>:

30000000: ea00000e b 30000040

30000004: e59ff014 ldr pc, [pc, #20] ; 30000020 <_undefined_instruction>

30000008: e59ff014 ldr pc, [pc, #20] ; 30000024 <_software_interrupt>

3000000c: e59ff014 ldr pc, [pc, #20] ; 30000028 <_prefetch_abort>

30000010: e59ff014 ldr pc, [pc, #20] ; 3000002c <_data_abort>

30000014: e59ff014 ldr pc, [pc, #20] ; 30000030 <_not_used>

30000018: e59ff014 ldr pc, [pc, #20] ; 30000034 <_irq>

3000001c: e59ff014 ldr pc, [pc, #20] ; 30000038 <_fiq>

而lds中是0x00000000时,dump的结果如下:

00000000 <_start>:

0: ea00000e b 40

4: e59ff014 ldr pc, [pc, #20] ; 20 <_undefined_instruction>

8: e59ff014 ldr pc, [pc, #20] ; 24 <_software_interrupt>

c: e59ff014 ldr pc, [pc, #20] ; 28 <_prefetch_abort>

10: e59ff014 ldr pc, [pc, #20] ; 2c <_data_abort>

14: e59ff014 ldr pc, [pc, #20] ; 30 <_not_used>

18: e59ff014 ldr pc, [pc, #20] ; 34 <_irq>

1c: e59ff014 ldr pc, [pc, #20] ; 38 <_fiq>

解决了这第一个问题,总算可以用ldr跳入中断向量了.

2、中断处理程序的写法:

[cpp] view plaincopyprint?

irq:

sub lr,lr,#4

stmfd sp!,{r0-r12,lr}

bl irq_isr

ldmfd sp!,{r0-r12,pc}^

irq: sub lr,lr,#4 stmfd sp!,{r0-r12,lr} bl irq_isr ldmfd sp!,{r0-r12,pc}^ 值得注意的是ldmfd sp!,{r0-r12,pc}^ 会自动的从spsr_irq中恢复到cpsr中.

stmfd等价于stmdb,ldmfd等价于ldmia.因为arm使用FD(向低地址整长的满栈),所以堆栈处理都用fd的后缀即可.

3、记得在中断处理程序中清除中断,不然的话会一直响应那个中断.

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值