Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

11105
637
415734


[ARMv8] EL0: el0_irq - 익셉션 벡터 코드와 ARM 스팩 문서 분석 Arm: Exception Overview

이번 포스트에서는 EL0에서 익셉션이 발생할 때의 익셉션 벡터 핸들러 코드에 대해 분석합니다.

익셉션 벡터 테이블 분석하기

먼저 다음 익셉션 벡터 테이블을 봅시다.

위에서 보이는 표는 리눅스 커널이 구동되는 EL1 기준으로 작성된 익셉션 벡터 테이블입니다.

EL0, 즉 유저 애플리케이션이 실행하는 도중 IRQ 타입 익셉션이 발생하면 테이블의 볼드체로 표기된 주소로 ARM 프로세서의 프로그램 카운터가 브랜치됩니다.

간단히 익셉션 벡터 테이블을 리뷰했으니, 이제 코드를 분석하겠습니다.

익셉션 벡터 핸들러 코드 분석하기

익셉션 벡터 테이블의 베이스 주소가 0xffffff8008082000라고 가정하고 익셉션 벡터 핸들러의 코드를 분석하겠습니다.

ffffff8008082480:   d503201f    nop
ffffff8008082484:   d503201f    nop
ffffff8008082488:   d10503ff    sub sp, sp, #0x140
ffffff800808248c:   8b2063ff    add sp, sp, x0
ffffff8008082490:   cb2063e0    sub x0, sp, x0
ffffff8008082494:   37700080    tbnz    w0, #14, ffffff80080824a4 <vectors+0x4a4>
ffffff8008082498:   cb2063e0    sub x0, sp, x0
ffffff800808249c:   cb2063ff    sub sp, sp, x0
ffffff80080824a0:   140005c8    b   ffffff8008083bc0 <el0_irq>
ffffff80080824a4:   d51bd040    msr tpidr_el0, x0
ffffff80080824a8:   cb2063e0    sub x0, sp, x0
ffffff80080824ac:   d51bd060    msr tpidrro_el0, x0
ffffff80080824b0:   d0006060    adrp    x0, ffffff8008c90000 <overflow_stack+0xd50>
ffffff80080824b4:   910ac01f    add sp, x0, #0x2b0
ffffff80080824b8:   d538d080    mrs x0, tpidr_el1
ffffff80080824bc:   8b2063ff    add sp, sp, x0
ffffff80080824c0:   d53bd040    mrs x0, tpidr_el0
ffffff80080824c4:   cb2063e0    sub x0, sp, x0
ffffff80080824c8:   f274cc1f    tst x0, #0xfffffffffffff000
ffffff80080824cc:   54001861    b.ne    ffffff80080827d8 <__bad_stack>
ffffff80080824d0:   cb2063ff    sub sp, sp, x0
ffffff80080824d4:   d53bd060    mrs x0, tpidrro_el0
ffffff80080824d8:   140005ba    b   ffffff8008083bc0 <el0_irq>
ffffff80080824dc:   d503201f    nop

EL0에서 IRQ 익셉션이 발생하면 ARM 프로세서는 0xffffff8008082000+0x480 주소로 프로그램 카운터를 브랜치합니다. 이를 다른 관점으로 설명하면, ffffff8008082480 주소로 프로그램 카운터가 브랜치한다라고 볼 수 있습니다. 프로그램 카운터가 ffffff8008082480로 브랜치하면 ffffff8008082480 주소에 있는 명령어를 실행합니다.

ffffff8008082480 주소에 보이는 여러 명령어가 있는데, 핵심 동작은 다음과 같이 요약할 수 있습니다.

   * 스택 공간 확보
   * tpidrro_el0 레지스터를 x0레지스터에 저장
   * el0_irq 레이블로 브랜치

이어서, 사실 상 EL0에서 인터럽트가 발생할 때의 익셉션 벡터 핸들러인 el0_irq 레이블의 코드를 분석하겠습니다.

el0_irq 레이블 코드 분석

el0_irq 레이블의 구현부는 다음과 같습니다.

01 el0_irq:
02     kernel_entry 0
03 el0_irq_naked:
04     gic_prio_irq_setup pmr=x20, tmp=x0
05     ct_user_exit_irqoff
06     enable_da_f
07 
08 #ifdef CONFIG_TRACE_IRQFLAGS
09     bl  trace_hardirqs_off
10 #endif
11
12 #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
13    tbz x22, #55, 1f
14    bl  do_el0_irq_bp_hardening
15 1:
16 #endif
17    irq_handler
18
19 #ifdef CONFIG_TRACE_IRQFLAGS
20    bl  trace_hardirqs_on
21 #endif
22    b   ret_to_user
23 ENDPROC(el0_irq)

01~06번째 줄을 보겠습니다.

01 el0_irq:
02     kernel_entry 0
03 el0_irq_naked:
04     gic_prio_irq_setup pmr=x20, tmp=x0
05     ct_user_exit_irqoff
06     enable_da_f

인터럽트 핸들러를 처리하기 전에 전처리를 하는 동작인데, 06번째 줄은 PSTATE 레지스터의 DA_F 플래그들을 클리어하는 동작을 수행합니다. 

이어서 17번째 줄을 봅시다.

17    irq_handler

리눅스 커널의 IRQ 서브시스템을 호출하는데, 이후 서브 루틴에서 인터럽트 핸들러가 호출됩니다.

마지막으로 22번째 줄을 보겠습니다.

22    b   ret_to_user

EL0(유저 애플리케이션)에서 인터럽트(익셉션)이 발생했으니, 이제 유저 공간을 복귀하기 위해 ret_to_user 레이블을 호출합니다.

Written by <디버깅을 통해 배우는 리눅스 커널의 구조와 원리> 저자






덧글

댓글 입력 영역