2023.11.22 TIL
Armv8 Exception Level
Exception Level의 정의
D1.1 Exception levels
The ARMv8-A architecture defines a set of Exception levels, EL0 to EL3, where:
- If ELn is the Exception level, increased values of n indicate increased software execution privilege.
- Execution at EL0 is called unprivileged execution.
- EL2 provides support for virtualization of Non-secure operation.
- EL3 provides support for switching between two Security states, Secure state and Non-secure state.
An implementation might not include all of the Exception levels. All implementations must include EL0
and EL1. EL2 and EL3 are optional.
|| Arm Architecture Reference Manual Armv8, for A-profile architecture https://developer.arm.com/documentation/ddi0487/gb
Exception Level의 쓰임
D1.1.1 Typical Exception level usage model
The architecture does not specify what software uses which Exception level. Such choices are outside
the scope of the architecture. However, the following is a common usage model for the Exception levels:
- EL0 Applications.
- EL1 OS kernel and associated functions that are typically described as privileged.
- EL2 Hypervisor.
- EL3 Secure monitor.
Exception Level과 Privilege Level
PL → 실행 권한
- EL0, PL0
- User application이 실행
- Unprivileged level 혹은 PL0로 실행 (privileged → hardware resource에 직접 접근할 수 있는 권한)
- EL0에서는 Interrupt, MMU, Cache 기능을 설정할 수 없음
- EL1, PL1
- EL1은 PL1 권한이 있는 level
- Linux kernel에서는 Interrupt, MMU, Cache 설정과 같이 시스템을 설정 가능
- EL2 PL2
- PL2는 EL2에게 부여되는 권한 level로 guest OS끼리 switching하고 guest OS의 시스템 리소스에 접근 가능
- 일반적으로 EL2에서 hypervisor가 실행되며, hypervisor는 PL2로 실행됨
- EL3 PL3
- PL3는 EL3에게 부여되는 권한 level로 highest privileged level
- 시스템을 모두 설정할 수 있고, exception level에 존재하는 모든 register에 접근할 수 있어 booting 과정에서 EL3로 설정
Armv8 Exception
Exception 관련 Log
-
Kernel Panic Log
- 함수가 아래에서 위 방향으로 호출됨
- Exception 발생시 특정 entry 주소로 jump, subroutine 실행
-
Kernel Log
ESR
: Exception Syndrome Register
EC
: Exception Class
- current EL
-
ftrace message
- 함수가 아래에서 위 방향으로 호출됨
- Interrupt 발생시 특정 entry 주소로 jump, subroutine 실행
- Interrupt를 exception의 한 종류로 관리하기 때문 (
IRQ
, Interrupt Request)
System Call
SVC
명령어 실행, 특정 entry 주소로 jump
Armv8 Architecture에서 Exception을 처리하는 방식
- Arm core가 exception이 발생했다고 감지하면 exception 종류별로 이미 정해놓은 주소(Exception Vector)로 jump(branch)
- Exception vector 주소에는 exception을 handling하는 코드가 있음
Armv8 Exception Vector Table
- Current Exception Level with
SP_ELx
, x>0 → EL1(Linux Kernel)
- Lower Exception Level, where the implemented level immediately lower than the target level is using AArch64 → EL0(User Application)
Synchronous
, IRQ
를 중점적으로 분석
- Offset → Base 주소에 더해서 PC branch
FIQ
는 Linux Kernel에서 지원안됨
SError
는 자주 유발되지 않음
- Interrupt가 유발되면 어느 주소로 PC가 바뀌는지
- 논리적 오류가 있는 명령어를 실행해 memory abort가 유발되면 어느 주소로 PC가 바뀌는지
- System call이 유발되면 처리되는 Exception Vector는 어디인지
- Kernel Crash 가 유발되면 어떤 흐름으로 로그를 출력하는지
Exception이 처리되는 흐름
- EL0의 Application에서 exception 발생 → EL1 Switching → Exception의 종류별로 정의된 entry 주소(VBAR_EL1)로 jump → EL0에서 발생한 Exception을 처리하는 Exception Vector 주소로 jump
- EL0의 Application에서 System Call, Null Pointer access, Segment Fault 유발의 경우에도 마찬가지로 실행
- EL1의 Linux Kernel에서 exception 발생 → EL1 Switching → Exception의 종류별로 정의된 entry 주소(VBAR_EL1)로 jump → EL1에서 발생한 Exception을 처리하는 Exception Vector 주소로 jump
Exception의 종류와 유발 인자
User Application에서 Exception 처리
Linux Kernel에서 Exception 처리
Armv8 Architecture Register & Linux Kernel
General Purpose Register
Special Register
SPSR_ELx
: Program Status Register, 이전 pstate의 값을 저장하고 있음
- 함수 실행해서 stack pointer update →
SP_ELx
register update
ELR_ELx
→ Exception Level Register, Exception 흐름 제어하는 용도
Kernel Log에서 본 Register
w0
→ 4Byte 단위 data를 담고 있는 register
IRQ Interrupt Exception이 유발될 때
User Space 복귀
ret_to_user
EL0
→ EL1
msr
: register에 있는 값을 ELR
에 update
eret
→ ELR의 주소가 PC로 바뀜
thread_struct
구조체
- Process가 실행된 register set와 같은 정보 저장
- Context: Register set
struct task_struct.thread
- Context switching → Scheduling으로 CPU core에서 쫓겨난 process → 걔들이 실행했던 register set를 이 field에 저장해놓음
AAPCS 관련 Register (Procedure Call Standard for ARM Architecture
Register | 역할 |
---|
X0 ~ X7 | 함수로 전달되는 인수값을 저장 |
X9~ X15 | 함수를 호출할 때 지역 변수를 저장 |
X29 | Frame Pointer Register로 이전 SP 주소를 저장 |
X30 | Link Register (Subroutine으로 branch한 다음에 복귀할 주소를 저장) |
cpu_switch_to
Label
<cpu_switch_to>
→ 전달되는 인자 2개 : x0
, x1
register
- 새롭게 CPU core를 점유하며 실행될 Process 입장에서,
task_struct.thread
에 저장된 값들이 Arm core register에 load가 되며 context switching이 일어남
Virtualization & TrustZone
TrustZone
- Arm에서 제공하는 security 기능이자 software architecture
- 대부분의 Arm processor에 적용되는 기술
- CPU 내부에 보안 관점으로 SW/HW적으로 신뢰할 수 있는 실행 영역을 제공하자는 것
전체 실행 흐름
SMC
: Secure Monitor Call
- Secure한 상태에서만 접근할 수 있는 memory space에 접근 (비밀번호 등)
FIQ
: Secure Interrupt (스마트폰으로 지문인식 사용 등)
Nonsecure World (Normal World)
- Linux System programming으로 작성된 코드 실행
- Linux Kernel driver 코드 실행
Exception Handler의 구현
- Exception Handler는 EL1 Kernel에 위치
SMC
→ EL3의 Exception Vector 주소로 PC jump
TrustZone : Hardware 기능
- Security Extension
- Arm Core 내부의 Secure World를 분리
- GIC (Generic Interrupt Controller)
- 외부 peripheral interrupt를 Arm core로 routing
- Interrupt를 Non-Secure(Interrupt Group 1)와 Secure(Interrupt Group 0)로 구분(routing)
- TZASC (TrustZone Address Space Controller)
- DRAM에 지정한 영역을 Secure 영역을 만들고 Non-Secure 접근을 filter
- TZOC (TrustZone Program Controller)
- CPU가 아닌 HW master의 register나 memory에 접근할 때 Secure와 Non-Secure 분리
- TZMA (TrustZone Memory Adapter)
- Chipset 내부의 memory 영역을 Secure와 Non-Secure로 구분
Hypervisor
- 2개 이상의 운영체제를 동시에 실행할 수 있는 architecture 혹은 platform
- Virtual computer 기법으로 x86 계통의 CPU에서 꾸준히 개발됨
- 전기자동차의 infotainment 분야에서 Armv8 기반의 hypervisor 활용
- 자동차 고객사는 자사의 운영체제와 더불어 hypervisor를 개발
Hypervisor Type
- 굉장히 많다.
- 기본 개념: Guest OS를 load, Guest OS resource 관리
- CPU Core를 Guest OS에 dynamic하게 할당
Infotainment System 기준 Hypervisor
Exception Model : Abort
- Memory Abort 유발 명령어 실행시 EL2의 Hypervisor에 존재하는 Exception Handler로 이동
HCR_EL2
→ Hypervisor Configuration Register를 구성하는 field를 설정
Exception Model : IRQ
- EL2의 Exception Handler에서 먼저 inturrupt을 받아서 처리한 후 Guest OS에 분배
Virtualization 대상
관련 Register
- HCR_EL2
- SCR_EL3
_ELx
: 최소 접근 Level
- Booting시 설정
Linux Kernel Debugging
Kernel Debugging 기법의 종류
- Brain
- printk, dump_stack
- debugfs
- ftrace
- QEMU
- TRACE32
- Crash utility
- GDB
printk
- printf와 같은 kernel printing function
- 어느 kernel code, driver에서도 사용 가능
- 낮은 log level → 더 적은 메세지 출력
- 높은 log level → 더 많은 메세지 출력
- KERN_WARNING : Default level (4)
- 주의사항
- printk는 오버헤드가 걸리는 동작
- printk를 추가한 함수가 자주 호출될 때 주의해야함
Log Level
- Level 0 ~ 7
- Log level 확인 :
cat /proc/sys/kernel/printk
→ [current, default, minimum, boot-time-default]
- Terminal로 Log level 설정 :
dmsg -n 5
→ current log level을 5로 변경
- Device Tree로 Log Level 설정 :
loglevel
을 설정
- Kernel config로 Log Level 설정
printk_ratelimit()
함수
dump_stack()
함수
- Stack trace를 kernel log로 출력
- 예외 처리나 심각한 오류가 있는 조건에서 사용
#include <linux/kernel.h>
- PID 정보가 출력돼서 좋음
Magic SysRq key
- Freeze에서 복귀, 컴퓨터를 reboot 하기 위해 사용
echo -<magic> > /proc/sysrq-trigger
→ CONFIG_MAGIC_SYSRQ
- Magic Keys
s
: Sync (dirty page를 disk로 flush)
u
: Read-only로 remount
t
: 현재 task 출력
c
: Kernel crash 유발
b
: Reboot
- SysRq magic key 종류 출력 :
echo -h > /proc/sysrq-trigger
+++