ARM bootloader: Interrupt Vector Table Understanding

user2122968 picture user2122968 · Jan 23, 2014 · Viewed 24.5k times · Source

The code following is the first part of u-boot to define interrupt vector table, and my question is how every line will be used. I understand the first 2 lines which is the starting point and the first instruction to implement: reset, and we define reset below. But when will we use these instructions below? According to System.map, every instruction has a fixed address, so _fiq is at 0x0000001C, when we want to execute fiq, we will copy this address into pc and then execute,right? But in which way can we jump to this instruction: ldr pc, _fiq? It's realised by hardware or software? Hope I make myself understood correctly.

>.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  

Answer

old_timer picture old_timer · Jan 25, 2014

If you understand reset then you understand all of them.

When the processor is reset then hardware sets the pc to 0x0000 and starts executing by fetching the instruction at 0x0000. When an undefined instruction is executed or tries to be executed the hardware responds by setting the pc to 0x0004 and starts executing the instruction at 0x0004. irq interrupt, the hardware finishes the instruction it is executing starts executing the instruction at address 0x0018. and so on.

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

Now of course in addition to changing the pc and starting execution from these addresses. The hardware will save the state of the machine, switch processor modes if necessary and then start executing at the new address from the vector table.

Our job as programmers is to build the binary such that the instructions we want to be run for each of these instructions is at the right address. The hardware provides one word, one instruction for each location. Now if you never expect to ever have any of these exceptions, you dont have to have a branch at address zero for example you can just have your program start, there is nothing magic about the memory at these addresses. If you expect to have these exceptions, then you have two choices for instructions that are one word and can jump out of the way of the exception that follows. One is a branch the other is a load pc. There are pros and cons to each.