首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ARM Linux外部中断处理过程(2)

ARM Linux外部中断处理过程(2)

可以知道add     pc, r10, #12  的#12意思是跳过3个指令,执行b        _arm920_setup
在arm920_setup设置完协处理器和返回寄存器r0之后,跳回到__ret31行)。
在__xscale_setup中会读取CP15的controlregister(c1)的值到r1寄存器,并在r1寄存器中设置相应的标志位(其中包括设置V位=1),但在__xscale_setup中,r1寄存器并不立即写回到Cp15的controlregister中,而是在返回后的某个地方,接下来会慢慢分析到。__xscale_setup调用move pc, lr指令返回跳转到31行。
  31行,在lr寄存器中放置__switch_data中的数据__mmap_switched,在36行程序会跳转到__mmap_switched处。
  32,33行,把r0寄存器中的值写回到cp15的control register(c1)中,再读出来放在r0中。
  
  接下来再来看一下跳转到__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行的结果是:r4=__bss_start,r5=__end,...,r8=cr_alignment,..,这里r8保存的是cr_alignment变量的地址.
  到了53行,由于之前r0保存的是cp15的control register(c1)的值,这里把r0的值写入r8指向的地址,即cr_alignment=r0.到此为止,我们就看清楚了cr_alignment的赋值过程。
  
  让我们回到trap_init()函数,经过上面的分析,我们知道vectors_base返回0xffff0000。函数__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}  /* 压栈,保存数据*/
      /* 复制异常向量表(.LCvectors起始的8个地址)到r0指向的地址(异常向量地址),r0就是__trap_init(base)函数调用时传递的参数,不明白的请参考ATPCS*/(传递参数顺次利用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偏移处,放置散转代码,即__stubs_start~__stubs_end之间的各个异常处理代码*/
      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}) /*出栈,恢复数据,函数__trap_init返回*/
    __trap_init函数填充后的向量表如下:
    虚拟地址      异常              处理代码
    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      数据异常      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)
   
  当有异常发生时,处理器会跳转到对应的0xffff0000起始的向量处取指令,然后,通过b指令散转到异常处理代码.因为ARM中b指令是相对跳转,而且只有+/-32MB的寻址范围,所以把__stubs_start~__stubs_end之间的异常处理代码复制到了0xffff0200起始处.这里可直接用b指令跳转过去,这样比使用绝对跳转(ldr)效率高。
继承事业,薪火相传
返回列表