<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          ARM Linux 外部中斷

          作者: 時(shí)間:2016-11-20 來(lái)源:網(wǎng)絡(luò) 收藏
          最近在學(xué)習(xí)arm linux的整套外部中斷的處理過(guò)程,在網(wǎng)上匯總了一些資料,整個(gè)過(guò)程差不多都了解到了。如果沒(méi)有這些資料我真是沒(méi)信心從匯編開(kāi)始讀代碼,感謝 奔騰年代的jimmy.lee和 linux論壇的bx_bird。
          在下面的的注釋中有一些我讀代碼時(shí)遇到的問(wèn)題,要是大家知道是怎么回事,希望多多。

          =============================================
          一.ARM linux的中斷向量表初始化分析

          ARM linux內(nèi)核啟動(dòng)時(shí),通過(guò)start_kernel()->trap_init()的調(diào)用關(guān)系,初始化內(nèi)核的中斷異常向量表.

          /* arch/arm/kernel/traps.c */
          void __init trap_init(void)
          {
          extern void __trap_init(unsigned long);
          unsigned long base = vectors_base();
          __trap_init(base);
          if (base != 0)
          oopsprintk(KERN_DEBUG "Relocating machine vectors to 0x%08lxn", base);
          #ifdef CONFIG_CPU_32
          modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
          #endif
          }
          vectors_base是一個(gè)宏,它的作用是獲取ARM異常向量的地址,該宏在include/arch/asm-arm/proc-armv/system.h中定義:

          extern unsigned long cr_no_alignment; /* defined in entry-armv.S */
          extern unsigned long cr_alignment; /* defined in entry-armv.S */
          #if __LINUX_ARM_ARCH__ >= 4
          #define vectors_base() ((cr_alignment & CR_V) ? 0xffff0000 : 0)
          #else
          #define vectors_base() (0)
          #endif
            對(duì)于ARMv4以下的版本,這個(gè)地址固定為0;ARMv4及其以上的版本,ARM異常向量表的地址受協(xié)處理器CP15的c1寄存器(control register)中V位(bit[13])的控制,如果V=1,則異常向量表的地址為0x00000000~0x0000001C;如果V=0,則為:0xffff0000~0xffff001C。(詳情請(qǐng)參考ARM Architecture Reference Manual)
            下面分析一下cr_alginment的值是在哪確定的,我們?cè)赼rch/arm/kernel/entry-armv.S找到cr_alignment的定義:

          .globl SYMBOL_NAME(cr_alignment)
          .globl SYMBOL_NAME(cr_no_alignment)
          SYMBOL_NAME(cr_alignment):
          .space 4

          SYMBOL_NAME(cr_no_alignment):

          本文引用地址:http://www.ex-cimer.com/article/201611/318689.htm

          .space 4

            分析過(guò)head-armv.S文件的朋友都會(huì)知道,head-armv.S是非壓縮內(nèi)核的入口:

          1 .section ".text.init",#alloc,#execinstr
          2 .type stext, #function
          3ENTRY(stext)
          4 mov r12, r0

          6 mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
          7 msr cpsr_c, r0 @ and all irqs disabled
          8 bl __lookup_processor_type
          9 teq r10, #0 @ invalid processor?
          10 moveq r0, #p @ yes, error p
          11 beq __error
          12 bl __lookup_architecture_type
          13 teq r7, #0 @ invalid architecture?
          14 moveq r0, #a @ yes, error a
          15 beq __error
          16 bl __create_page_tables
          17 adr lr, __ret @ return address
          18 add pc, r10, #12 @ initialise processor
          19 @ (return control reg)
          20
          21 .type __switch_data, %object
          22__switch_data: .long __mmap_switched
          23 .long SYMBOL_NAME(__bss_start)
          24 .long SYMBOL_NAME(_end)
          25 .long SYMBOL_NAME(processor_id)
          26 .long SYMBOL_NAME(__machine_arch_type)
          27 .long SYMBOL_NAME(cr_alignment)
          28 .long SYMBOL_NAME(init_task_union)+8192
          29
          30 .type __ret, %function
          31__ret: ldr lr, __switch_data
          32 mcr p15, 0, r0, c1, c0
          33 mrc p15, 0, r0, c1, c0, 0 @ read it back.
          34 mov r0, r0
          35 mov r0, r0
          36 mov pc, lr
          這里我們關(guān)心的是從17行開(kāi)始,17行code處將lr放置為_(kāi)_ret標(biāo)號(hào)處的相對(duì)地址,以便將來(lái)某處返回時(shí)跳轉(zhuǎn)到31行繼續(xù)運(yùn)行18行,對(duì)于我所分析的pxa270平臺(tái),它將是跳轉(zhuǎn)到arch/arm/mm/proc-xscale.S中執(zhí)行__xscale_setup函數(shù),(在s3c2410平臺(tái)中,它跳轉(zhuǎn)到arch/arm/mm/proc-arm920.S,在
          type __arm920_proc_info,#object
          __arm920_proc_info:
          .long 0x41009200
          .long 0xff00fff0
          .long 0x00000c1e @ mmuflags
          b __arm920_setup
          .long cpu_arch_name
          .long cpu_elf_name
          .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
          .long cpu_arm920_info
          .long arm920_processor_functions
          可以知道add pc, r10, #12 的#12意思是跳過(guò)3個(gè)指令,執(zhí)行b _arm920_setup
          在arm920_setup設(shè)置完協(xié)處理器和返回寄存器r0之后,跳回到__ret:(31行)。
          在__xscale_setup中會(huì)讀取CP15的control register(c1)的值到r1寄存器,并在r1寄存器中設(shè)置相應(yīng)的標(biāo)志位(其中包括設(shè)置V位=1),但在__xscale_setup中,r1寄存器并不立即寫回到Cp15的control register中,而是在返回后的某個(gè)地方,接下來(lái)會(huì)慢慢分析到。__xscale_setup調(diào)用move pc, lr指令返回跳轉(zhuǎn)到31行。
            31行,在lr寄存器中放置__switch_data中的數(shù)據(jù)__mmap_switched,在36行程序會(huì)跳轉(zhuǎn)到__mmap_switched處。
            32,33行,把r0寄存器中的值寫回到cp15的control register(c1)中,再讀出來(lái)放在r0中。
            
            接下來(lái)再來(lái)看一下跳轉(zhuǎn)到__mmap_switched處的代碼:
          40 _mmap_switched:
          41 adr r3, __switch_data + 4
          42 ldmia r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat
          43 @ sp = stack pointer
          44
          45 mov fp, #0 @ Clear BSS (and zero fp)
          46 1: cmp r4, r5
          47 strcc fp, [r4],#4
          48 bcc 1b
          49
          50 str r9, [r6] @ Save processor ID
          51 str r1, [r7] @ Save machine type
          52 bic r2, r0, #2 @ Clear A bit
          53 stmia r8, {r0, r2} @ Save control register values
          54 b SYMBOL_NAME(start_kernel)

          41~42行的結(jié)果是:r4=__bss_start,r5=__end,...,r8=cr_alignment,..,這里r8保存的是cr_alignment變量的地址.
            到了53行,由于之前r0保存的是cp15的control register(c1)的值,這里把r0的值寫入r8指向的地址,即cr_alignment=r0.到此為止,我們就看清楚了cr_alignment的賦值過(guò)程。
            
            讓我們回到trap_init()函數(shù),經(jīng)過(guò)上面的分析,我們知道vectors_base返回0xffff0000。函數(shù)__trap_init由匯編代碼編寫,在arch/arm/kernel/entry-arm.S:
              .align 5
          __stubs_start:
          vector_IRQ:
               ...
          vector_data:
              ....
          vector_prefetch:
               ...
          vector_undefinstr:
               ...
          vector_FIQ: disable_fiq
               subs pc, lr, #4
          vector_addrexcptn:
               b vector_addrexcptn
              ...
          __stubs_end:
               .equ __real_stubs_start, .LCvectors + 0x200
          .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} /* 壓棧,保存數(shù)據(jù)*/
              /* 異常向量表(.LCvectors起始的8個(gè)地址)到r0指向的地址(異常向量地址),r0就是__trap_init(base)函數(shù)調(diào)用時(shí)傳遞的參數(shù),不明白的請(qǐng)參考ATPCS*/(傳遞參數(shù)順次利用r0,r1,r2,r3)
              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}

          /* 在異常向量地址后的0x200偏移處,放置散轉(zhuǎn)代碼,即__stubs_start~__stubs_end之間的各個(gè)異常處理代碼*/
               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}) /*出棧,恢復(fù)數(shù)據(jù),函數(shù)__trap_init返回*/
          __trap_init函數(shù)填充后的向量表如下:
          虛擬地址 異常 處理代碼
          0xffff0000 reset swi SYS_ERROR0
          0xffff0004 undefined b __real_stubs_start + (vector_undefinstr - __stubs_start)
          0xffff0008 軟件中斷 ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)
          0xffff000c 取指令異常 b __real_stubs_start + (vector_prefetch - __stubs_start)
          0xffff0010 數(shù)據(jù)異常 b __real_stubs_start + (vector_data - __stubs_start)
          0xffff0014 reserved b __real_stubs_start + (vector_addrexcptn - __stubs_start)
          0xffff0018 irq b __real_stubs_start + (vector_IRQ - __stubs_start)
          0xffff001c fiq b __real_stubs_start + (vector_FIQ - __stubs_start)

             當(dāng)有異常發(fā)生時(shí),處理器會(huì)跳轉(zhuǎn)到對(duì)應(yīng)的0xffff0000起始的向量處取指令,然后,通過(guò)b指令散轉(zhuǎn)到異常處理代碼.因?yàn)锳RM中b指令是相對(duì)跳轉(zhuǎn),而且只有+/-32MB的尋址范圍,所以把__stubs_start~__stubs_end之間的異常處理代碼到了0xffff0200起始處.這里可直接用b指令跳轉(zhuǎn)過(guò)去,這樣比使用絕對(duì)跳轉(zhuǎn)(ldr)效率高。



          關(guān)鍵詞: ARMLinux外部中

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();