이번에는 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 <디버깅을 통해 배우는 리눅스 커널의 구조와 원리> 저자

최근 덧글