中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. 新聞中心

        ARM Linux中斷分析

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

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

        本文引用地址:http://www.antipu.com.cn/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ú)論內(nèi)存地址空間是如何映射的,以上這些地址都不會(huì)變,比如當(dāng)有快速中斷發(fā)生時(shí),ARM將鐵定到0X0000001C這個(gè)地址處取指令。這也是BOOTLOADER把操作系統(tǒng)引導(dǎo)以后,內(nèi)存必須重映射的原因!否則操作系統(tǒng)不能真正接管整套系統(tǒng)!
          

                LINUX啟動(dòng)以后要初始化這些區(qū)域,初始化代碼在main.c中的start_kernel()中,具體是調(diào)用函數(shù)trap_ini()來(lái)實(shí)現(xiàn)的。如下面所示(具體可參照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ù)初始化了中斷向量,實(shí)際上把相應(yīng)的跳轉(zhuǎn)指令拷貝到了對(duì)應(yīng)的地址。
          

                當(dāng)發(fā)生中斷時(shí),不管是從用戶模式還是管理模式調(diào)用的,最終都要調(diào)用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 @ 調(diào)用do_IRQ來(lái)實(shí)現(xiàn)具體的中斷處理
        mov why, #0
        get_current_task tsk
        b ret_to_user

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

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

        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)型的中斷用以上結(jié)構(gòu)來(lái)表示:
          

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

          在通過(guò)request_irq()函數(shù)注冊(cè)中斷服務(wù)程序的時(shí)候,將會(huì)把中斷向量和中斷服務(wù)程序?qū)?yīng)起來(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結(jié)構(gòu)*/
        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); /*把中斷號(hào)irq和action 對(duì)應(yīng)起來(lái)*/
        if (retval)
        kfree(action);
        return retval;
        }
          其中第一個(gè)參數(shù)irq就是中斷向量,第二個(gè)參數(shù)即是要注冊(cè)的中斷服務(wù)程序。很多同仁可能疑惑的是,我們要注冊(cè)的中斷向量號(hào)是怎么確定的呢?這要根據(jù)具體芯片的中斷控制器,比如三星的S3C2410,需要通過(guò)讀取其中的中斷狀態(tài)寄存器,來(lái)獲得是哪個(gè)設(shè)備發(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

          以上代碼也告訴了我們,中斷號(hào)的確定,其實(shí)是和S3C2410手冊(cè)中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的文檔。

          總結(jié)

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

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

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

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




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

        評(píng)論


        相關(guān)推薦

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

        關(guān)閉