<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

ARM Linux中斷分析

作者: 時(shí)間:2008-03-21 來(lái)源:電子開(kāi)發(fā)網(wǎng) 收藏

        ARM體系結構中,把復位、中斷、快速中斷等都看作‘異常’,當這些‘異常’發(fā)生時(shí),CPU會(huì )到固定地址處去找指令,他們對應的地址如下:
 

本文引用地址:http://dyxdggzs.com/article/80447.htm

地址 異常類(lèi)型 進(jìn)入時(shí)的工作模式
0x00000000 Reset Supervisor
0x00000004 Und Undefined
0x00000008 Soft interupt Supervisor
0x0000000c  Abort(prefetch)  Abort
0x00000010 Abort(data) Abort
0x00000014 Reserved  Reserved
0x00000018 IRQ IRQ
0x0000001c FIQ FIQ

  首先要明確的一點(diǎn)就是,無(wú)論內存地址空間是如何映射的,以上這些地址都不會(huì )變,比如當有快速中斷發(fā)生時(shí),ARM將鐵定到0X0000001C這個(gè)地址處取指令。這也是BOOTLOADER把操作系統引導以后,內存必須重映射的原因!否則操作系統不能真正接管整套系統!
  

        LINUX啟動(dòng)以后要初始化這些區域,初始化代碼在main.c中的start_kernel()中,具體是調用函數trap_ini()來(lái)實(shí)現的。如下面所示(具體可參照entry-armv.S):

.LCvectors: swi SYS_ERROR0
b __real_stubs_start + (vector_undefinstr - __stubs_start)
ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)
b __real_stubs_start + (vector_prefetch - __stubs_start)
b __real_stubs_start + (vector_data - __stubs_start)
b __real_stubs_start + (vector_addrexcptn - __stubs_start)
b __real_stubs_start + (vector_IRQ - __stubs_start)
b __real_stubs_start + (vector_FIQ - __stubs_start)

ENTRY(__trap_init)
stmfd sp!, {r4 - r6, lr}
adr r1, .LCvectors @ set up the vectors
ldmia r1, {r1, r2, r3, r4, r5, r6, ip, lr}
stmia r0, {r1, r2, r3, r4, r5, r6, ip, lr}
add r2, r0, #0x200
adr r0, __stubs_start @ copy stubs to 0x200
adr r1, __stubs_end
1: ldr r3, [r0], #4
str r3, [r2], #4
cmp r0, r1
blt 1b
LOADREGS(fd, sp!, {r4 - r6, pc})

  以上可以看出這個(gè)函數初始化了中斷向量,實(shí)際上把相應的跳轉指令拷貝到了對應的地址。
  

        當發(fā)生中斷時(shí),不管是從用戶(hù)模式還是管理模式調用的,最終都要調用do_IRQ():

__irq_usr: sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ save r0 - r12
ldr r4, .LCirq
add r8, sp, #S_PC
ldmia r4, {r5 - r7} @ get saved PC, SPSR
stmia r8, {r5 - r7} @ save pc, psr, old_r0
stmdb r8, {sp, lr}^
alignment_trap r4, r7, __temp_irq
zero_fp
1: get_irqnr_and_base r0, r6, r5, lr
movne r1, sp
adrsvc ne, lr, 1b
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
bne do_IRQ @ 調用do_IRQ來(lái)實(shí)現具體的中斷處理
mov why, #0
get_current_task tsk
b ret_to_user

  對于以上代碼,在很多文章中都有過(guò)分析,這里不再贅述。

  Linux每個(gè)中斷通過(guò)一個(gè)結構irqdesc來(lái)描述,各中斷的信息都在這個(gè)結構中得以體現:

struct irqdesc {
unsigned int nomask : 1; /* IRQ does not mask in IRQ */
unsigned int enabled : 1; /* IRQ is currently enabled */
unsigned int triggered: 1; /* IRQ has occurred */
unsigned int probing : 1; /* IRQ in use for a probe */
unsigned int probe_ok : 1; /* IRQ can be used for probe */
unsigned int valid : 1; /* IRQ claimable */
unsigned int noautoenable : 1; /* don't automatically enable IRQ */
unsigned int unused :25;
void (*mask_ack)(unsigned int irq); /* Mask and acknowledge IRQ */
void (*mask)(unsigned int irq); /* Mask IRQ */
void (*unmask)(unsigned int irq); /* Unmask IRQ */
struct irqaction *action;
/*
* IRQ lock detection
*/
unsigned int lck_cnt;
unsigned int lck_pc;
unsigned int lck_jif;
};

  在具體的ARM芯片中會(huì )有很多的中斷類(lèi)型,每一種類(lèi)型的中斷用以上結構來(lái)表示:
  

  struct irqdesc irq_desc[NR_IRQS]; /* NR_IRQS根據不同的MCU會(huì )有所區別*/

  在通過(guò)request_irq()函數注冊中斷服務(wù)程序的時(shí)候,將會(huì )把中斷向量和中斷服務(wù)程序對應起來(lái)。
  

  我們來(lái)看一下request_irq的源碼:

int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irq_flags, const char * devname, void *dev_id)
{
unsigned long retval;
struct irqaction *action;
if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
(irq_flags & SA_SHIRQ && !dev_id))
return -EINVAL;
action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action) /* 生成action結構*/
return -ENOMEM;
action->handler = handler;
action->flags = irq_flags;
action->mask = 0;
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
retval = setup_arm_irq(irq, action); /*把中斷號irq和action 對應起來(lái)*/
if (retval)
kfree(action);
return retval;
}
  其中第一個(gè)參數irq就是中斷向量,第二個(gè)參數即是要注冊的中斷服務(wù)程序。很多同仁可能疑惑的是,我們要注冊的中斷向量號是怎么確定的呢?這要根據具體芯片的中斷控制器,比如三星的S3C2410,需要通過(guò)讀取其中的中斷狀態(tài)寄存器,來(lái)獲得是哪個(gè)設備發(fā)生了中斷:

if defined(CONFIG_ARCH_S3C2410)
#include
.macro disable_fiq
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
mov r4, #INTBASE @ virtual address of IRQ registers
ldr irqnr, [r4, #0x8] @ read INTMSK 中斷掩碼寄存器
ldr irqstat, [r4, #0x10] @ read INTPND 中斷寄存器
bics irqstat, irqstat, irqnr
bics irqstat, irqstat, irqnr
beq 1002f
mov irqnr, #0
1001: tst irqstat, #1
bne 1002f @ found IRQ
add irqnr, irqnr, #1
mov irqstat, irqstat, lsr #1
cmp irqnr, #32
bcc 1001b
1002:
.endm
.macro irq_prio_table
.endm

  以上代碼也告訴了我們,中斷號的確定,其實(shí)是和S3C2410手冊中SRCPND寄存器是一致的,即:

/* Interrupt Controller */
#define IRQ_EINT0 0 /* External interrupt 0 */
#define IRQ_EINT1 1 /* External interrupt 1 */
#define IRQ_EINT2 2 /* External interrupt 2 */
#define IRQ_EINT3 3 /* External interrupt 3 */
#define IRQ_EINT4_7 4 /* External interrupt 4 ~ 7 */
#define IRQ_EINT8_23 5 /* External interrupt 8 ~ 23 */
#define IRQ_RESERVED6 6 /* Reserved for future use */
#define IRQ_BAT_FLT 7
#define IRQ_TICK 8 /* RTC time tick interrupt */
#define IRQ_WDT 9 /* Watch-Dog timer interrupt */
#define IRQ_TIMER0 10 /* Timer 0 interrupt */
#define IRQ_TIMER1 11 /* Timer 1 interrupt */
#define IRQ_TIMER2 12 /* Timer 2 interrupt */
#define IRQ_TIMER3 13 /* Timer 3 interrupt */
#define IRQ_TIMER4 14 /* Timer 4 interrupt */
#define IRQ_UART2 15 /* UART 2 interrupt */
#define IRQ_LCD 16 /* reserved for future use */
#define IRQ_DMA0 17 /* DMA channel 0 interrupt */
#define IRQ_DMA1 18 /* DMA channel 1 interrupt */
#define IRQ_DMA2 19 /* DMA channel 2 interrupt */
#define IRQ_DMA3 20 /* DMA channel 3 interrupt */
#define IRQ_SDI 21 /* SD Interface interrupt */
#define IRQ_SPI0 22 /* SPI interrupt */
#define IRQ_UART1 23 /* UART1 receive interrupt */
#define IRQ_RESERVED24 24
#define IRQ_USBD 25 /* USB device interrupt */
#define IRQ_USBH 26 /* USB host interrupt */
#define IRQ_IIC 27 /* IIC interrupt */
#define IRQ_UART0 28 /* UART0 transmit interrupt */
#define IRQ_SPI1 29 /* UART1 transmit interrupt */
#define IRQ_RTC 30 /* RTC alarm interrupt */
#define IRQ_ADCTC 31 /* ADC EOC interrupt */
#define NORMAL_IRQ_OFFSET 32

  這些宏定義在文件irqs.h中,大家可以看到它的定義取自S3C2410的文檔。

  總結

       linux在初始化的時(shí)候已經(jīng)把每個(gè)中斷向量的地址準備好了!就是說(shuō)添加中斷服務(wù)程序的框架已經(jīng)給出,當某個(gè)中斷發(fā)生時(shí),將會(huì )到確定的地址處去找指令,所以我們做驅動(dòng)程序時(shí),只需要經(jīng)過(guò)request_irq來(lái)掛接自己編寫(xiě)的中斷服務(wù)程序即可。

  對于快速中斷,linux在初始化時(shí)是空的,所以要對它掛接中斷處理程序,就需要單獨的函數set_fiq_handler來(lái)實(shí)現,此函數在源文件fiq.c中,有興趣的讀者可進(jìn)一步研究。

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)

linux相關(guān)文章:linux教程




關(guān)鍵詞: ARM Linux 中斷

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>