Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

9465
557
421925


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

이번에는 EL0에서 코드가 실행하는 도중에 ARM 프로세서 입장에서 어떤 방식으로 처리되는지 알아보고, 이어서 el0_sync 레이블을 분석하겠습니다.

EL0에서 Synchronous 익셉션 벡터 코드

익셉션 벡터 테이블의 시작 주소 기준으로(VBAR_ELn + 0x400) 바이트에 Synchronous 익셉션의 코드가 위치합니다.

이번 포스트에서 분석할 익셉션 벡터 테이블의 시작 주소는 ffffff8008082000이므로,
EL0에서 Synchronous 익셉션이 발생하면 다음 코드 기준으로 ffffff8008082400(ffffff8008082000 + 0x400) 주소로 프로그램 카운터가 브랜치합니다.

다음은 EL0의 Synchronous 익셉션 벡터 코드입니다.

ffffff8008082400:   d503201f    nop
ffffff8008082404:   d503201f    nop
ffffff8008082408:   d10503ff    sub sp, sp, #0x140
ffffff800808240c:   8b2063ff    add sp, sp, x0
ffffff8008082410:   cb2063e0    sub x0, sp, x0
ffffff8008082414:   37700080    tbnz    w0, #14, ffffff8008082424 <vectors+0x424>
ffffff8008082418:   cb2063e0    sub x0, sp, x0
ffffff800808241c:   cb2063ff    sub sp, sp, x0
ffffff8008082420:   14000428    b   ffffff80080834c0 <el0_sync>
ffffff8008082424:   d51bd040    msr tpidr_el0, x0
ffffff8008082428:   cb2063e0    sub x0, sp, x0
ffffff800808242c:   d51bd060    msr tpidrro_el0, x0
ffffff8008082430:   d0006060    adrp    x0, ffffff8008c90000 <overflow_stack+0xd50>
ffffff8008082434:   910ac01f    add sp, x0, #0x2b0
ffffff8008082438:   d538d080    mrs x0, tpidr_el1
ffffff800808243c:   8b2063ff    add sp, sp, x0
ffffff8008082440:   d53bd040    mrs x0, tpidr_el0
ffffff8008082444:   cb2063e0    sub x0, sp, x0
ffffff8008082448:   f274cc1f    tst x0, #0xfffffffffffff000
ffffff800808244c:   54001c61    b.ne    ffffff80080827d8 <__bad_stack>
ffffff8008082450:   cb2063ff    sub sp, sp, x0
ffffff8008082454:   d53bd060    mrs x0, tpidrro_el0
ffffff8008082458:   1400041a    b   ffffff80080834c0 <el0_sync>
ffffff800808245c:   d503201f    nop

위 코드의 핵심은 "예외 처리 루틴을 체크한 다음에 el0_sync 레이블로 브랜치하는 동작"입니다.

el0_sync 레이블의 코드 분석

다음은 el0_sync 레이블 코드의 구현부입니다.

https://elixir.bootlin.com/linux/v5.4.30/source/arch/arm64/kernel/entry.S
01 el0_sync:
02     kernel_entry 0
03     mrs x25, esr_el1            // read the syndrome register
04     lsr x24, x25, #ESR_ELx_EC_SHIFT // exception class
05     cmp x24, #ESR_ELx_EC_SVC64      // SVC in 64-bit state
06     b.eq    el0_svc
07     cmp x24, #ESR_ELx_EC_DABT_LOW   // data abort in EL0
08     b.eq    el0_da
09     cmp x24, #ESR_ELx_EC_IABT_LOW   // instruction abort in EL0
10    b.eq    el0_ia
11    cmp x24, #ESR_ELx_EC_FP_ASIMD   // FP/ASIMD access
12    b.eq    el0_fpsimd_acc
13    cmp x24, #ESR_ELx_EC_SVE        // SVE access
14    b.eq    el0_sve_acc
15    cmp x24, #ESR_ELx_EC_FP_EXC64   // FP/ASIMD exception
16    b.eq    el0_fpsimd_exc
17    cmp x24, #ESR_ELx_EC_SYS64      // configurable trap
18    ccmp    x24, #ESR_ELx_EC_WFx, #4, ne
19    b.eq    el0_sys
20    cmp x24, #ESR_ELx_EC_SP_ALIGN   // stack alignment exception
21    b.eq    el0_sp
22    cmp x24, #ESR_ELx_EC_PC_ALIGN   // pc alignment exception
23    b.eq    el0_pc
24    cmp x24, #ESR_ELx_EC_UNKNOWN    // unknown exception in EL0
25    b.eq    el0_undef
26    cmp x24, #ESR_ELx_EC_BREAKPT_LOW    // debug exception in EL0
27    b.ge    el0_dbg
28    b   el0_inv

먼저 03번째 줄을 분석해봅시다.

03     mrs x1, esr_el1         // read the syndrome register

이 코드는 신드롬 레지스터를 읽어서 x1 레지스터에 저장하는 기능인데, 컴파일이 되면 다음과 같은 명령어로 변환됩니다.

mrs     x1,#0x3,#0x0,c5,c2,#0x0   ; x1, ESR_EL1 // mrs x1, esr_el1

---
여기서 신드롬 레지스터는 익셉션이 발생한 세부 원인(Reason)을 담고 있는데, ARM 스팩 문서에는 다음과 같이 명시돼 있습니다.

출처: DEN0024A_v8_architecture_PG.pdf
10.2.6 The Exception Syndrome Register
The Exception Syndrome Register, ESR_ELn, contains information which allows the exception handler to determine the reason for the exception. It is updated only for synchronous exceptions and SError.

신드롬 레지스터에 대해서는 다른 포스트에서 집중 분석할 예정입니다.
---

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

04     lsr x24, x1, #ESR_ELx_EC_SHIFT  // exception class

신드롬 레지스터의 값을 저장한 x1 레지스터를 왼쪽으로 ESR_ELx_EC_SHIFT 만큼 비트 쉬프트해서 x24 레지스터에 저장합니다.
ESR_ELx_EC_SHIFT은 10진수로 26인데, x1 레지스터를 26만큼 왼쪽으로 비트 쉬프트를 해서 x24 레지스터에 저장하는 동작입니다.

이해를 돕기 위해 04번째 줄이 컴파일된 명령어를 다음과 같이 소개합니다.

lsr     x24,x1,#0x1A     ; x24,x1,#26

위 코드로 보아 #ESR_ELx_EC_SHIFT는 26임을 알 수 있는데, 주석과 같이 x24 레지스터는 익셉션 클래스를 저장하게 됩니다.

코드의 오른쪽을 보면 exception class란 주석이 보이는데, 이는 익셉션의 세부 원인(Exception Cause)을 뜻합니다.

---
exception class에 대한 내용은 역시 ARM 스팩 문서에서 확인할 수 있습니다.

출처: DEN0024A_v8_architecture_PG.pdf
10.2.6 The Exception Syndrome Register
...
• Bits [31:26] of ESR_ELn indicate the exception class which allows the handler to distinguish between the various possible exception causes (such as unallocated
instruction, exceptions from MCR/MRC to CP15, exception from FP operation, SVC, HVC or SMC executed, Data Aborts, and alignment exceptions).

익셉션이 발생한 세부 원인(distinguish between the various possible exception causes)에 대한 정보를 Bits [31:26]에 담고 있다는 내용입니다.
---

역시 ARMv8 아키텍처 스팩 문서에 명시된 대로 구현돼 있다는 사실을 알 수 있습니다.


>>>>

05     cmp x24, #ESR_ELx_EC_SVC64      // SVC in 64-bit state
06     b.eq    el0_svc

cmp     x24,#0x15        ; x24,#21 // 010101
b.eq    0xFFFFFF8008083800   ; el0_svc

010101 SVC instruction execution in AArch64 state

EC == 010101, Exception from HVC or SVC instruction execution

This value is valid for all described registers.
SVC executed in AArch64 state.
See ISS encoding for an exception from HVC or SVC instruction execution.


07     cmp x24, #ESR_ELx_EC_DABT_LOW   // data abort in EL0
08     b.eq    el0_da

cmp     x24,#0x24        ; x24,#36  // 100100
b.eq    0xFFFFFF8008083284   ; el0_da

100100 Data Abort from a lower Exception levelh

EC == 100100, Exception from a Data abort

This value is valid for all described registers.
Data Abort that caused entry from a lower Exception level, where that Exception level
could be using AArch64 or using AArch32.
Used for MMU faults generated by data accesses, alignment faults other than those
caused by the Stack Pointer misalignment, and synchronous external aborts, including
synchronous parity or ECC errors. Not used for debug related exceptions.
See ISS encoding for an exception from a Data abort.

09     cmp x24, #ESR_ELx_EC_IABT_LOW   // instruction abort in EL0
10    b.eq    el0_ia

cmp     x24,#0x20        ; x24,#32 // 100000
b.eq    0xFFFFFF80080832A8   ; el0_ia

100000 Instruction Abort from a lower Exception levelg

EC == 100000, Exception from an Instruction abort
This value is valid for all described registers.
Instruction Abort that caused entry from a lower Exception level, where that Exception
level could be using AArch64 or using AArch32.
Used for MMU faults generated by instruction accesses and synchronous external
aborts, including synchronous parity or ECC errors. Not used for debug related
exceptions.
See ISS encoding for an exception from an Instruction abort.

11    cmp x24, #ESR_ELx_EC_FP_ASIMD   // FP/ASIMD access
12    b.eq    el0_fpsimd_acc

cmp     x24,#0x7         ; x24,#7  // 000111
b.eq    0xFFFFFF80080832C4   ; el0_fpsimd_acc

000111 Access to Advanced SIMD or floating-point registers when CPACR_EL1.FPEN !== 0b11
or CPTR_ELx.TFP == 1, excluding (HCR_EL2.TGE==1) routing

EC == 000111, Exception from an access to an Advanced SIMD or floating-point register,
resulting from CPACR_EL1.FPEN or CPTR_ELx.TFP
This value is valid for all described registers.
Exceptions from an access to an Advanced SIMD or Floating Point register as a result
of CPACR_EL1.FPEN, CPTR_EL2.TFP, or CPTR_EL3.TFP.
Excludes exceptions resulting from an HCR_EL2.TGE value of 1 that are reported with
EC value 0b000000 as described in EC encodings when routing exceptions to EL2 on
page D1-1445.
See ISS encoding for an exception from an access to an Advanced SIMD or
floating-point register, resulting from CPACR_EL1.FPEN or CPTR_ELx.TFP.


13    cmp x24, #ESR_ELx_EC_SVE        // SVE access
14    b.eq    el0_sve_acc

cmp     x24,#0x19        ; x24,#25  //011001
b.eq    0xFFFFFF80080832D8   ; el0_sve_acc

Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, CPTR_EL2.TZ, or CPTR_EL3.EZ, that is not reported using EC 0b000000.

https://developer.arm.com/docs/ddi0595/h/aarch64-system-registers/esr_el1

15    cmp x24, #ESR_ELx_EC_FP_EXC64   // FP/ASIMD exception
16    b.eq    el0_fpsimd_exc

cmp     x24,#0x2C        ; x24,#44  // 101100
b.eq    0xFFFFFF80080832EC   ; el0_fpsimd_exc

101100 Floating-point exception, if supported, from AArch64 state

EC == 101100, Exception from a trapped Floating-point exception
This value is valid for all described registers.
Exceptions as a result of Floating-point exception from AArch64.
Whether this Exception class is supported is IMPLEMENTATION DEFINED.
See ISS encoding for an exception from a trapped Floating-point exception.

17    cmp x24, #ESR_ELx_EC_SYS64      // configurable trap
18    ccmp    x24, #ESR_ELx_EC_WFx, #4, ne
19    b.eq    el0_sys

cmp     x24,#0x18        ; x24,#24  // 011000
b.eq    0xFFFFFF800808332C   ; el0_sys

011000 MSR, MRS, or System instruction
execution, that is not reported
using EC 0x00, 0x01, or 0x07

EC == 011000, Exception from MSR, MRS, or System instruction execution in AArch64 state
This value is valid for all described registers.
Exceptions from MSR, MRS, or System AArch64 instructions as a result of
configurable traps, enables, or disables, except those reported using EC values 000000,
000001, or 000111.
This include all instructions that cause exceptions that are part of the encoding space
defined in System instruction class encoding overview on page C5-245, except for those
exceptions reported using EC values 0b000000, 0b000001, or 0b000111.
See ISS encodin

20    cmp x24, #ESR_ELx_EC_SP_ALIGN   // stack alignment exception
21    b.eq    el0_sp

cmp     x24,#0x26        ; x24,#38  // 100110
b.eq    0xFFFFFF8008083300   ; el0_sp_pc

100110 Stack Pointer Alignment exception

EC == 100110, Exception from an Illegal execution state, or a PC or SP alignment fault
This value is valid for all described registers.
SP alignment fault.

22    cmp x24, #ESR_ELx_EC_PC_ALIGN   // pc alignment exception
23    b.eq    el0_pc

cmp     x24,#0x22        ; x24,#34  // 100010
b.eq    0xFFFFFF8008083300   ; el0_sp_pc

100010 Misaligned PC exception

24    cmp x24, #ESR_ELx_EC_UNKNOWN    // unknown exception in EL0
25    b.eq    el0_undef

cmp     x24,#0x0         ; x24,#0
b.eq    0xFFFFFF800808331C   ; el0_undef

EC == 100010, Exception from an Illegal execution state, or a PC or SP alignment fault
This value is valid for all described registers.
PC alignment fault.

000000 Unknown reason

EC == 000000, Exceptions with an unknown reason
This value is valid for all described registers.
Unknown or Uncategorized Reason - generally used for exceptions as a result of
erroneous execution.
See ISS encoding for exceptions

26    cmp x24, #ESR_ELx_EC_BREAKPT_LOW    // debug exception in EL0
27    b.ge    el0_dbg

cmp     x24,#0x30        ; x24,#48  // 110000
b.ge    0xFFFFFF8008083340   ; el0_dbg

110000 Breakpoint exception from a
lower Exception level

EC == 110000, Exception from a Breakpoint or Vector Catch debug event
This value is valid for ESR_EL1 and ESR_EL2.
Breakpoint debug event that caused entry from a lower Exception level.

28    b   el0_inv

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





덧글

댓글 입력 영역