1. arch/arm64/kernel/entry.s

ARM 64bit Exception Handler는 Exception level마다 분기를 하게 되어 있으며, Vector table에 의거 해서 Jump 수행

 

.macro kernel_ventry, el, label, regsize = 64
.align 7
.....
b el\()\el\()_\label
.endm

 

Vector table은 같은 파일 내에 선언.

 

.align 11
ENTRY(vectors)
    kernel_ventry 1, sync_invalid // Synchronous EL1t
    kernel_ventry 1, irq_invalid // IRQ EL1t
    kernel_ventry 1, fiq_invalid // FIQ EL1t
    kernel_ventry 1, error_invalid // Error EL1t

    kernel_ventry 1, sync // Synchronous EL1h
    kernel_ventry 1, irq // IRQ EL1h
    kernel_ventry 1, fiq_invalid // FIQ EL1h
    kernel_ventry 1, error_invalid // Error EL1h

    kernel_ventry 0, sync // Synchronous 64-bit EL0
    kernel_ventry 0, irq // IRQ 64-bit EL0
    kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0
    kernel_ventry 0, error_invalid // Error 64-bit EL0

#ifdef CONFIG_COMPAT
    kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0
    kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0
    kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0
    kernel_ventry 0, error_invalid_compat, 32 // Error 32-bit EL0
#else
    kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0
    kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0
    kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0
    kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0
#endif
END(vectors)

 

ELn Handler 역시 같은 파일 내 선언

 

/* * EL1 mode handlers. */
    .align 6
el1_sync:
    kernel_entry 1
    mrs x1, esr_el1 // read the syndrome register
    lsr x24, x1, #ESR_ELx_EC_SHIFT // exception class
    cmp x24, #ESR_ELx_EC_DABT_CUR // data abort in EL1
    b.eq el1_da
    cmp x24, #ESR_ELx_EC_IABT_CUR // instruction abort in EL1
    b.eq el1_ia
    cmp x24, #ESR_ELx_EC_SYS64 // configurable trap
    b.eq el1_undef
    cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception
    b.eq el1_sp_pc
    cmp x24, #ESR_ELx_EC_PC_ALIGN // pc alignment exception
    b.eq el1_sp_pc
    cmp x24, #ESR_ELx_EC_UNKNOWN // unknown exception in EL1
    b.eq el1_undef
    cmp x24, #ESR_ELx_EC_BREAKPT_CUR // debug exception in EL1
    b.ge el1_dbg
    b el1_inv

...

el1_da:
    /*
     * Data abort handling
     */
    mrs x3, far_el1
    enable_dbg // re-enable interrupts if they were enabled in the aborted context
    tbnz x23, #7, 1f // PSR_I_BIT
    enable_irq
1:
    clear_address_tag x0, x3
    mov x2, sp // struct pt_regs
    bl do_mem_abort

    // disable interrupts before pulling preserved data off the stack
    disable_irq
    kernel_exit 1

...

/* * EL0 mode handlers. */
    .align 6
el0_sync:
    kernel_entry 0
    mrs x25, esr_el1 // read the syndrome register
    lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class
    cmp x24, #ESR_ELx_EC_SVC64 // SVC in 64-bit state
    b.eq el0_svc
    cmp x24, #ESR_ELx_EC_DABT_LOW // data abort in EL0
    b.eq el0_da
    cmp x24, #ESR_ELx_EC_IABT_LOW // instruction abort in EL0
    b.eq el0_ia
    cmp x24, #ESR_ELx_EC_FP_ASIMD // FP/ASIMD access
    b.eq el0_fpsimd_acc
    cmp x24, #ESR_ELx_EC_FP_EXC64 // FP/ASIMD exception
    b.eq el0_fpsimd_exc
    cmp x24, #ESR_ELx_EC_SYS64 // configurable trap
    b.eq el0_sys
    cmp x24, #ESR_ELx_EC_SP_ALIGN // stack alignment exception
    b.eq el0_sp_pc
    cmp x24, #ESR_ELx_EC_PC_ALIGN // pc alignment exception
    b.eq el0_sp_pc
    cmp x24, #ESR_ELx_EC_UNKNOWN // unknown exception in EL0
    b.eq el0_undef
    cmp x24, #ESR_ELx_EC_BREAKPT_LOW // debug exception in EL0
    b.ge el0_dbg
    b el0_inv

....

el0_da:
    /*
     * Data abort handling
     */
    mrs x26, far_el1
    // enable interrupts before calling the main handler
    enable_dbg_and_irq
    ct_user_exit clear_address_tag x0, x26
    mov x1, x25
    mov x2, sp
    bl do_mem_abort
    b ret_to_user

모든 레벨에서 Data abort 발생시 do_mem_abort를 수행.

 

 

2. arch/arm64/mm/fault.c

 

fault_info structure에 선언되어 있는 엔트리를 얻어와  function을 수행.

/*
 * Dispatch a data abort to the relevant handler.
 */
asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,
                             struct pt_regs *regs)
{
    const struct fault_info *inf = esr_to_fault_info(esr);
    struct siginfo info;

    if (!inf->fn(addr, esr, regs))
        return;

    pr_alert("Unhandled fault: %s (0x%08x) at 0x%016lx\n", inf->name, esr, addr);

    mem_abort_decode(esr);

    info.si_signo = inf->sig;
    info.si_errno = 0;
    info.si_code = inf->code;
    info.si_addr = (void __user *)addr;
    arm64_notify_die("", regs, &info, esr);
}

 

같은 파일 내에 해당 구조체 선언되어 있으며, do_bad, do_translation_fault, do_page_fault, do_alignment_fault 함수가 실행.

 

static const struct fault_info fault_info[] = {
    { do_bad, SIGBUS, 0, "ttbr address size fault" },
    { do_bad, SIGBUS, 0, "level 1 address size fault" },
    { do_bad, SIGBUS, 0, "level 2 address size fault" },
    { do_bad, SIGBUS, 0, "level 3 address size fault" },
    { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" },
    { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
    { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
    { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
    { do_bad, SIGBUS, 0, "unknown 8" },
    { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
    { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
    { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
    { do_bad, SIGBUS, 0, "unknown 12" },
    { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
    { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
    { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
    { do_sea, SIGBUS, 0, "synchronous external abort" },
    ..................
}

 

+ Recent posts