ARM Exception Vector

ARM에서 Exception이 발생하면 CPU는 지정된 벡터테이블(low/high)로 강제 jump되고 해당 엔트리에는 각 exception을 처리할 수 있는 코드로의 branch 코드가  수행된다.

 

아래 그림은 8개의 exception vector entry 중 5개 엔트리의 경우 각각 16개의 모드 테이블을 갖고 있고 exception 되기 전의 모드를 인덱스로 하여 해당 루틴으로 이동하는 것을 보여준다.

arm-exception-vector-1a

 

Vector 선언

__vectors_start

arch/arm/kernel/entry-armv.S

        .section .vectors, "ax", %progbits
__vectors_start:
        W(b)    vector_rst
        W(b)    vector_und
        W(ldr)  pc, __vectors_start + 0x1000
        W(b)    vector_pabt
        W(b)    vector_dabt
        W(b)    vector_addrexcptn
        W(b)    vector_irq
        W(b)    vector_fiq
  • 8개의 exception vector 엔트리에는 각각을 처리할 수 있는 stub 코드로 이동할 수 있는 branch 코드로 되어 있다.
  • 3번 째 엔트리의 경우 벡터위치+0x1000에 담겨있는 주소로 이동하는 코드가 있는데 해당 위치는 vector_swi 루틴을 담고 있다.

 

Vector가 저장되는 섹션 위치

        _etext = .;                     /* End of text and rodata section */

#ifndef CONFIG_XIP_KERNEL
# ifdef CONFIG_ARM_KERNMEM_PERMS
        . = ALIGN(1<<SECTION_SHIFT);
# else
        . = ALIGN(PAGE_SIZE);
# endif
        __init_begin = .;
#endif
        /*
         * The vectors and stubs are relocatable code, and the
         * only thing that matters is their relative offsets
         */
        __vectors_start = .;
        .vectors 0 : AT(__vectors_start) {
                *(.vectors)
        }
        . = __vectors_start + SIZEOF(.vectors);
        __vectors_end = .;

        __stubs_start = .;
        .stubs 0x1000 : AT(__stubs_start) {
                *(.stubs)
        }
        . = __stubs_start + SIZEOF(.stubs);
        __stubs_end = .;

        INIT_TEXT_SECTION(8)
        .exit.text : {
                ARM_EXIT_KEEP(EXIT_TEXT)
        }
  • 벡터 테이블의 원본 데이터는 _etext 다음인 .vector 섹션에 위치하고 stub 코드들은 .stubs 섹션에 위치한다.

 

Vector 설치

exception 벡터 및 stub 코드들은 아래의 루틴에서 설치된다.

  • paging_init()->devicemaps_init()->early_trap_init()

 

Vector 핸들러

vector_stub

arch/arm/kernel/entry-armv.S

/*
 * Vector stubs.
 *
 * This code is copied to 0xffff1000 so we can use branches in the
 * vectors, rather than ldr's.  Note that this code must not exceed
 * a page size.
 *
 * Common stub entry macro:
 *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
 *
 * SP points to a minimal amount of processor-private memory, the address
 * of which is copied into r0 for the mode specific abort handler.
 */
        .macro  vector_stub, name, mode, correction=0
        .align  5

vector_\name:
        .if \correction
        sub     lr, lr, #\correction
        .endif

        @
        @ Save r0, lr_<exception> (parent PC) and spsr_<exception>
        @ (parent CPSR)
        @
        stmia   sp, {r0, lr}            @ save r0, lr
        mrs     lr, spsr
        str     lr, [sp, #8]            @ save spsr

        @
        @ Prepare for SVC32 mode.  IRQs remain disabled.
        @
        mrs     r0, cpsr
        eor     r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
        msr     spsr_cxsf, r0

        @
        @ the branch table must immediately follow this code
        @
        and     lr, lr, #0x0f
 THUMB( adr     r0, 1f                  )
 THUMB( ldr     lr, [r0, lr, lsl #2]    )
        mov     r0, sp
 ARM(   ldr     lr, [pc, lr, lsl #2]    )
        movs    pc, lr                  @ branch to handler in SVC mode
ENDPROC(vector_\name)

        .align 2
        @ handler addresses follow this label
1:
        .endm

Exception이 발생되면 8개의 exception vector 엔트리 중 해당하는 exception 위치로 jump 되는데 이 중 5개의 exception 엔트리에서 사용되는 공통 매크로 루틴에서는 exception 벡터로 점프되기 직전의 최대 16개 모드별 테이블에 해당하는 루틴을 찾아 수행하게 되어 있다.

  • correction은 루틴이 수행된 후 다시 리턴될 주소를 조정한다. exception이 발생될 때의 파이프라인 위치에 따라 보정 주소가 다르다.
    • IRQ, FIQ, Data Abort의 경우 리턴 주소-4로 보정한다.
    • Prefetch Abort의 경우 리턴 주소-8로 보정한다.
    • Undefined 및 SWI의 경우 보정 없이 리턴 주소를 사용한다.
    • Reset은 리턴하지 않으므로 해당사항 없다.

 

.stubs 섹션의 시작

        .section .stubs, "ax", %progbits
__stubs_start:
        @ This must be the first word
        .word   vector_swi
  • 시스템 콜이 호출되는 vector_swi가 벡터 stub의 처음에 위치한다.

 

vector_rst (Reset)

vector_rst:
 ARM(   swi     SYS_ERROR0      )
 THUMB( svc     #0              )
 THUMB( nop                     )
        b       vector_und

SYS_ERROR0 소프트웨어 인터럽트를 발생시켜 시스템 콜을 호출하게 한다.

 

vector_irq (IRQ)

/*
 * Interrupt dispatcher
 */
        vector_stub     irq, IRQ_MODE, 4

        .long   __irq_usr                       @  0  (USR_26 / USR_32)
        .long   __irq_invalid                   @  1  (FIQ_26 / FIQ_32)
        .long   __irq_invalid                   @  2  (IRQ_26 / IRQ_32)
        .long   __irq_svc                       @  3  (SVC_26 / SVC_32)
        .long   __irq_invalid                   @  4
        .long   __irq_invalid                   @  5
        .long   __irq_invalid                   @  6
        .long   __irq_invalid                   @  7
        .long   __irq_invalid                   @  8
        .long   __irq_invalid                   @  9
        .long   __irq_invalid                   @  a
        .long   __irq_invalid                   @  b
        .long   __irq_invalid                   @  c
        .long   __irq_invalid                   @  d
        .long   __irq_invalid                   @  e
        .long   __irq_invalid                   @  f
  • USR 모드에서 인터럽트가 발생한 경우 __irq_usr 루틴을 호출한다.
  • FIQ 및 IRQ 모드에서 인터럽트가 발생한 경우 __irq_invalid 루틴을 호출한다.
  • SVC 모드에서 인터럽트가 발생한 경우 __irq_svc 루틴을 호출한다.

 

vector_dabt (Data Abort)

/*
 * Data abort dispatcher
 * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
 */
        vector_stub     dabt, ABT_MODE, 8

        .long   __dabt_usr                      @  0  (USR_26 / USR_32)
        .long   __dabt_invalid                  @  1  (FIQ_26 / FIQ_32)
        .long   __dabt_invalid                  @  2  (IRQ_26 / IRQ_32)
        .long   __dabt_svc                      @  3  (SVC_26 / SVC_32)
        .long   __dabt_invalid                  @  4
        .long   __dabt_invalid                  @  5
        .long   __dabt_invalid                  @  6
        .long   __dabt_invalid                  @  7
        .long   __dabt_invalid                  @  8
        .long   __dabt_invalid                  @  9
        .long   __dabt_invalid                  @  a
        .long   __dabt_invalid                  @  b
        .long   __dabt_invalid                  @  c
        .long   __dabt_invalid                  @  d
        .long   __dabt_invalid                  @  e
        .long   __dabt_invalid                  @  f

 

vector_pabt (Prefetch Abort)

/*
 * Prefetch abort dispatcher
 * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
 */
        vector_stub     pabt, ABT_MODE, 4

        .long   __pabt_usr                      @  0 (USR_26 / USR_32)
        .long   __pabt_invalid                  @  1 (FIQ_26 / FIQ_32)
        .long   __pabt_invalid                  @  2 (IRQ_26 / IRQ_32)
        .long   __pabt_svc                      @  3 (SVC_26 / SVC_32)
        .long   __pabt_invalid                  @  4
        .long   __pabt_invalid                  @  5
        .long   __pabt_invalid                  @  6
        .long   __pabt_invalid                  @  7
        .long   __pabt_invalid                  @  8
        .long   __pabt_invalid                  @  9
        .long   __pabt_invalid                  @  a
        .long   __pabt_invalid                  @  b
        .long   __pabt_invalid                  @  c
        .long   __pabt_invalid                  @  d
        .long   __pabt_invalid                  @  e
        .long   __pabt_invalid                  @  f

 

vector_und (Undefined Instruction)

/*
 * Undef instr entry dispatcher
 * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
 */
        vector_stub     und, UND_MODE

        .long   __und_usr                       @  0 (USR_26 / USR_32)
        .long   __und_invalid                   @  1 (FIQ_26 / FIQ_32)
        .long   __und_invalid                   @  2 (IRQ_26 / IRQ_32)
        .long   __und_svc                       @  3 (SVC_26 / SVC_32)
        .long   __und_invalid                   @  4
        .long   __und_invalid                   @  5
        .long   __und_invalid                   @  6
        .long   __und_invalid                   @  7
        .long   __und_invalid                   @  8
        .long   __und_invalid                   @  9
        .long   __und_invalid                   @  a
        .long   __und_invalid                   @  b
        .long   __und_invalid                   @  c
        .long   __und_invalid                   @  d
        .long   __und_invalid                   @  e
        .long   __und_invalid                   @  f

        .align  5

 

vector_addrexcptn (Address Exception Handler)

/*=============================================================================
 * Address exception handler
 *-----------------------------------------------------------------------------
 * These aren't too critical.
 * (they're not supposed to happen, and won't happen in 32-bit data mode).
 */

vector_addrexcptn:
        b       vector_addrexcptn

 

vector_fiq (FIQ)

/*=============================================================================
 * FIQ "NMI" handler
 *-----------------------------------------------------------------------------
 * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
 * systems.
 */
        vector_stub     fiq, FIQ_MODE, 4

        .long   __fiq_usr                       @  0  (USR_26 / USR_32)
        .long   __fiq_svc                       @  1  (FIQ_26 / FIQ_32)
        .long   __fiq_svc                       @  2  (IRQ_26 / IRQ_32)
        .long   __fiq_svc                       @  3  (SVC_26 / SVC_32)
        .long   __fiq_svc                       @  4
        .long   __fiq_svc                       @  5
        .long   __fiq_svc                       @  6
        .long   __fiq_abt                       @  7
        .long   __fiq_svc                       @  8
        .long   __fiq_svc                       @  9
        .long   __fiq_svc                       @  a
        .long   __fiq_svc                       @  b
        .long   __fiq_svc                       @  c
        .long   __fiq_svc                       @  d
        .long   __fiq_svc                       @  e
        .long   __fiq_svc                       @  f

        .globl  vector_fiq_offset
        .equ    vector_fiq_offset, vector_fiq

 

참고

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.