ARM bootloader:中断向量表理解

12 arm interrupt bootloader

下面的代码是用于定义中断向量表的u-boot的第一部分,我的问题是如何使用每一行.我理解前两行是起点和第一条实现的指令:reset,我们在下面定义reset.但我们什么时候会在下面使用这些说明?根据System.map,每条指令都有一个固定的地址,所以_fiq在0x0000001C,当我们想要执行fiq时,我们会将这个地址复制到pc然后执行,对吧?但是我们可以通过哪种方式跳转到这条指令:ldr pc,_fiq?它是通过硬件还是软件实现的?希望我能让自己理解正确.

>.globl _start  
>_start:b         reset  
>       ldr       pc, _undefined_instruction  
>       ldr       pc, _software_interrupt  
>       ldr       pc, _prefetch_abort  
>       ldr       pc, _data_abort  
>       ldr       pc, _not_used  
>       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  
Run Code Online (Sandbox Code Playgroud)

old*_*mer 11

如果您了解重置,那么您就能理解所有这些.

当处理器复位时,硬件将pc设置为0x0000并通过获取0x0000处的指令开始执行.当执行未定义的指令或尝试执行时,硬件通过将pc设置为0x0004来响应并开始执行0x0004处的指令.irq中断,硬件完成正在执行的指令开始执行地址0x0018的指令.等等.

00000000 <_start>:
   0:   ea00000d    b   3c <reset>
   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>

00000020 <_undefined_instruction>:
  20:   00000000    andeq   r0, r0, r0

00000024 <_software_interrupt>:
  24:   00000000    andeq   r0, r0, r0

00000028 <_prefetch_abort>:
  28:   00000000    andeq   r0, r0, r0

0000002c <_data_abort>:
  2c:   00000000    andeq   r0, r0, r0

00000030 <_not_used>:
  30:   00000000    andeq   r0, r0, r0

00000034 <_irq>:
  34:   00000000    andeq   r0, r0, r0

00000038 <_fiq>:
  38:   00000000    andeq   r0, r0, r0
Run Code Online (Sandbox Code Playgroud)

当然,除了更改pc并从这些地址开始执行之外.硬件将保存机器的状态,必要时切换处理器模式,然后从向量表开始执行新地址.

我们作为程序员的工作是构建二进制文件,以便我们希望为每条指令运行的指令位于正确的地址.硬件为每个位置提供一个字,一条指令.现在,如果您从未期望过任何这些异常,那么您不必在地址零处有一个分支,例如您可以让您的程序启动,这些地址的内存没有任何魔力.如果您希望有这些例外,那么对于一个单词的指令有两种选择,并且可以跳出后面的异常.一个是分支,另一个是负载pc.各有利弊.

  • 您将 cortex-m 与常规臂核混淆了。常规的arm内核就像上面一样,它们在异常表中的地址处执行指令。cortex-m 核心是一个向量表,其中零向量是堆栈指针的加载值,偏移量 4 是重置时的重置向量,它从向量表加载堆栈指针,然后在重置向量地址处开始执行 (3认同)

Not*_*hat 6

当硬件发生异常时,程序计数器(PC)自动设置为相关异常向量的地址,处理器开始执行该地址的指令.当处理器复位时,PC会自动设置为base+0.未定义的指令将PC设置为base+4,等等.向量表(base)的基址是0x00000000,0xFFFF0000,或者VBAR取决于处理器和配置.请注意,这在向量表放置的位置提供了有限的灵活性,您需要查阅ARM文档以及您用于获取正确值的设备的参考手册.

表的布局(每个异常4个字节)使得必须立即从向量分支到实际的异常处理程序.这种LDR PC, label方法的原因是双重的 - 因为PC相对分支仅限于(24 << 2)位(+/- 32MB)使用B会稍微限制内存中代码的布局; 通过加载绝对地址,处理程序可以位于内存中的任何位置.其次,通过简单地将不同的地址写入该位置,而不必组装和热补分支指令,可以非常简单地在运行时更改异常处理程序.

以这种方式拥有可重映射的复位向量几乎没有价值,但这就是为什么你倾向于看到一个实现为一个简单的分支,以跳过其余的向量到真正的入口点代码.