ARM Cortex-A Context Switch — Mode 전환·SVC·Banked Registers
#한 줄 요약
Cortex-A는 7개의 모드와 모드별 banked register를 갖습니다. Cortex-M의 2 SP(MSP/PSP) 구조와는 차원이 다른 복잡도입니다.
#Cortex-A의 7 모드
| 모드 | 비트 | 용도 |
|---|---|---|
| User (USR) | 10000 | Application |
| FIQ | 10001 | Fast IRQ |
| IRQ | 10010 | 일반 IRQ |
| Supervisor (SVC) | 10011 | OS kernel |
| Abort (ABT) | 10111 | Memory fault |
| Undefined (UND) | 11011 | Undef instruction |
| System (SYS) | 11111 | Privileged user mode |
모드에 진입하면 CPSR.M[4:0]이 해당 모드 값으로 자동 설정됩니다.
#Banked Registers
User: R0 R1 R2 ... R7 R8 R9 R10 R11 R12 R13 R14 PC CPSRFIQ: R0 R1 R2 ... R7 R8_fiq R9_fiq R10_fiq R11_fiq R12_fiq R13_fiq R14_fiq SPSR_fiqIRQ: R0 R1 R2 ... R7 R8 R9 R10 R11 R12 R13_irq R14_irq SPSR_irqSVC: R0 R1 R2 ... R7 R8 R9 R10 R11 R12 R13_svc R14_svc SPSR_svcR13(SP)과 R14(LR)는 모드별로 별도 레지스터를 갖습니다. 모드 진입 시 자동으로 banked 레지스터가 활성화됩니다. FIQ는 R8부터 R12까지도 추가로 banked되어 있어서 context save를 빠르게 끝낼 수 있습니다.
#Mode 진입 시
User mode 실행 중 → IRQ 발생1. CPSR → SPSR_irq 복사 (이전 상태 보존)2. LR_irq = return address3. CPSR.M = IRQ mode4. PC = vector table[IRQ]User mode의 R13과 R14는 banked되어 있으므로 그대로 보존됩니다. IRQ mode에서는 R13_irq와 R14_irq를 사용합니다.
#Context Switch 흐름
Cortex-A용 RTOS(FreeRTOS Cortex-A port, Zephyr Cortex-A)의 context switch는 다음과 같습니다.
@ 현재 task 저장 (SVC mode에서)stmfd sp!, {r0-r12, lr} @ banked R13_svc 사용mrs r0, spsrstmfd sp!, {r0} @ SPSR (user의 CPSR) 보존
@ FPU 사용 시vstmdb sp!, {d0-d15}vstmdb sp!, {d16-d31}fmrx r0, fpscrstmfd sp!, {r0}
@ TCB->sp 갱신ldr r1, =pxCurrentTCBldr r1, [r1]str sp, [r1]
@ schedulerbl vTaskSwitchContext
@ 새 task 로드ldr r1, =pxCurrentTCBldr r1, [r1]ldr sp, [r1] @ 새 SP
@ FPU 복원 (lazy 가능)ldmfd sp!, {r0}vmsr fpscr, r0vldmia sp!, {d16-d31}vldmia sp!, {d0-d15}
@ SPSR + 일반 regs 복원ldmfd sp!, {r0}msr spsr_cxsf, r0ldmfd sp!, {r0-r12, lr}subs pc, lr, #0 @ exception return → user mode코드가 훨씬 길고 모두 수동입니다. Cortex-M의 HW automation에 해당하는 기능이 없기 때문입니다.
#SVC — 시스템 콜 entry
User mode에서 SVC 명령을 실행하면 SVC mode로 진입합니다. RTOS의 API entry point 역할을 합니다.
// Usersyscall(SYSCALL_YIELD);
// asmsvc #0 @ SVC handler로 trapSVC handler가 들어온 번호에 맞춰 OS API를 호출합니다. Linux의 system call이 같은 메커니즘으로 동작합니다.
#MMU·Cache 영향
Cortex-A는 MMU를 가지므로 context switch 시 다음 작업이 추가됩니다.
- 필요할 때 TLB를 invalidate합니다.
- 잘못된 cache content가 남지 않도록 cache를 flush 또는 invalidate합니다.
- ASID(Address Space ID)를 갱신합니다.
__asm("dsb ish");__asm("tlbi vmalle1is");__asm("dsb ish");__asm("isb");이 과정만으로도 수십 µs가 추가됩니다. 같은 process 안의 thread switch는 가볍지만, process 자체를 바꿀 때는 비용이 크게 늘어납니다.
#NEON / VFP
Cortex-A의 SIMD/FP unit입니다. context에 D0부터 D31까지 256 byte가 추가됩니다. lazy save를 사용하는 편이 좋습니다.
#TrustZone — Secure/Non-secure World
Cortex-A는 두 개의 world를 갖습니다. context switch가 world 사이에서도 일어날 수 있습니다.
NS world task → SMC → Secure world (OP-TEE)SMC 명령은 EL3 Monitor로 trap합니다. world switch는 모든 GP 레지스터, FP 레지스터, S/NS state를 함께 저장합니다.
#비용 — Cortex-M vs Cortex-A
| Cortex-M3 (168MHz) | Cortex-A53 (1.5GHz) | |
|---|---|---|
| Context switch | ~70 cycle (0.4 µs) | ~300 cycle + cache/TLB (수 µs) |
| FPU lazy save | 0 (사용 안 한 task) | 작음 |
| Process switch | (없음) | TLB flush 10 µs + cold cache 100 µs+ |
Cortex-A의 process switch 비용은 thread switch에 비해 훨씬 큽니다. 그래서 RTOS는 보통 single process에 여러 thread를 두는 모델을 택합니다.
#Zephyr Cortex-A Port
z_arm_pendsv: /* ... */ stmfd sp!, {r0-r12, lr} /* ... */FreeRTOS는 FreeRTOS-Plus의 Cortex-A 포트로 대응합니다. NXP, ST, Xilinx는 자체 BSP를 제공합니다.
#자주 하는 실수
⚠️ Mode를 잘못 잡습니다
User mode에서 privileged 명령을 시도하면 Undef trap이 발생합니다. RTOS 코드는 SVC mode에서 동작한다는 가정 위에서 짜야 합니다.
⚠️ TLB invalidate를 빠뜨립니다
MMU 매핑을 바꾼 뒤 기존 translation을 그대로 쓰면 잘못된 메모리에 접근하게 됩니다.
⚠️ Cache 일관성을 놓칩니다
DMA 동작 후에는 cache invalidate가 필요합니다. coherent cache는 비싸기 때문에 명시적으로 관리하는 경우가 많습니다.
#정리
- Cortex-A는 7개의 모드와 모드별 banked R13/R14를 갖습니다. Cortex-M의 2 SP 구조보다 복잡합니다.
- Context switch가 완전히 SW로 처리됩니다. HW automation이 없습니다.
- MMU, cache, TLB 처리로 수 µs 단위의 비용이 듭니다.
- Process switch는 thread switch보다 훨씬 비쌉니다.
다음 편은 RISC-V context switch입니다. ECALL, mret, CSR을 다룹니다.
#관련 항목
Practical RTOS Internals · 17 of 53
- 1Practical RTOS Internals — 실시간 커널 내부 분석 시리즈 소개
- 2RTOS가 필요한 이유 — 일반 OS와의 결정적 차이
- 3Task와 Thread 개념 — TCB·상태 머신·생명 주기 분석
- 4실시간 스케줄링 알고리즘 비교 — RR·Priority·EDF·RMS
- 5Preemption과 Cooperation — 강제 전환 vs 자발 양보
- 6인터럽트와 RTOS — ISR Context·Deferred Processing·FromISR API
- 7동기화 기초 분석 — Critical Section·Mutual Exclusion·Race Condition
- 8Semaphore 개념 분해 — Counting·Binary·P/V 연산
- 9Mutex 개념 분해 — Ownership·Recursive·Priority Inheritance
- 10큐와 메시지 패싱 — Producer-Consumer·Ring Buffer·전달 의미
- 11실시간성 분석 — Latency·Jitter·Deadline·WCET·RMA
- 12Ready List 자료구조 분석 — Linked List·Bitmap·O(1) Scheduler
- 13Blocked List 자료구조 — Timeout 정렬·Delta List·Two-List Scheme
- 14Scheduler 알고리즘 구현 추적 — Next-Task Selection 로직
- 15Context Switch 원리 분석 — 레지스터 저장·복원·Stack Frame
- 16ARM Cortex-M Context Switch — PendSV·MSP/PSP 어셈블리 추적
- 17ARM Cortex-A Context Switch — Mode 전환·SVC·Banked Registers
- 18RISC-V Context Switch 분석 — ECALL·mret·CSR
- 19RTOS Tick과 타이머 — SysTick·Generic Timer·configTICK_RATE_HZ
- 20Tickless 모드 구현 — Idle Tick Suppression·Sleep·Wake 보정
- 21Scheduler Latency 측정 기법 — GPIO Toggle·DWT·ftrace·cyclictest
- 22RTOS Tracing과 Observability — Tracealyzer·SystemView·ITM/ETM
- 23Critical Section 구현 비교 — IRQ Disable·BASEPRI·Spinlock
- 24Semaphore 내부 구현 추적 — Counter·Wait List·ISR-Safe Variant
- 25Mutex 내부 구현 추적 — Owner·Recursion Count·ISR 금지
- 26Priority Inversion 문제 — Mars Pathfinder 사례·Bounded vs Unbounded
- 27Priority Inheritance 구현 — Inherit·Disinherit·Chain
- 28Priority Ceiling Protocol — Immediate vs Original 비교
- 29Queue 내부 구현 추적 — Ring Buffer·2 Wait Lists·Atomic Send/Receive
- 30Event Group 분석 — Bit Flag·AND/OR Wait·Sync Barrier
- 31ISR-Safe API 설계 — FromISR 패턴·Higher Priority Wake·Deferred Work
- 32Deadlock 분석 — 4 조건·Wait-for Graph·Lock Ordering·Timeout
- 33Stream Buffer와 Message Buffer — FreeRTOS 10의 Lock-Free SPSC
- 34실시간 메모리 요구사항 — Determinism·Fragmentation·WCET
- 35FreeRTOS Heap_1~5 분석 — 5종 Allocator의 구조와 트레이드오프
- 36TLSF Allocator 분석 — Two-Level Segregated Fit O(1)
- 37Static Allocation — 컴파일 타임으로 동적 위험 제거하기
- 38Memory Pool — Fixed-Size Block Allocator의 단순함과 강력함
- 39Stack Overflow 탐지 — Canary·MPU·Watermark 3중 방어
- 40SMP RTOS 설계 — Ready List·Affinity·IPI·Load Balancing
- 41SMP Spinlock 구현 — LDREX/STREX·Ticket Lock·MCS·WFE/SEV
- 42Software Timer 분석 — Daemon Task·자료구조·ISR-Safe API
- 43RTOS System Call — SVC·ECALL·User/Kernel 분리·FreeRTOS-MPU
- 44TrustZone과 TF-M — Secure/Non-Secure·NSC Veneer·PSA
- 45AMP와 OpenAMP — Heterogeneous SoC·RPMsg·remoteproc
- 46C++ in RTOS — RAII·std::thread·ETL·Coroutine
- 47FreeRTOS 소스 분석 — tasks.c·queue.c·port.c 추적
- 48Zephyr 커널 분석 — k_thread·k_sem·Driver Model
- 49RT-Thread 분석 — Object 모델·Components·Smart·Studio
- 50RTOS 포팅 가이드 — 새 아키텍처에 옮기는 절차
- 51RTOS 선택 가이드 — Footprint·License·Certification·Ecosystem
- 52Apache NuttX 분석 — POSIX·PX4·NASA Ingenuity
- 53PREEMPT_RT Linux — Mainline 6.12·Xenomai 4·EVL
관련 글
RTOS System Call — SVC·ECALL·User/Kernel 분리·FreeRTOS-MPU
MPU/MMU로 user task와 kernel을 분리하는 RTOS의 syscall 구조를 정리합니다. Cortex-M의 SVC trap, RISC-V의 ECALL, FreeRTOS-MPU와 Zephyr USERSPACE의 차이, capability 검사, syscall overhead 측정까지 다룹니다.
ARM Cortex-M Context Switch — PendSV·MSP/PSP 어셈블리 추적
Cortex-M context switch는 PendSV 예외와 dual-stack 모델로 압축됩니다. FreeRTOS port의 PendSV 핸들러 어셈블리를 한 줄씩 따라가며 EXC_RETURN, BASEPRI, lazy FPU까지 풀어봅니다.
PREEMPT_RT Linux — Mainline 6.12·Xenomai 4·EVL
2024년 9월 Linux 6.12 mainline에 합류한 PREEMPT_RT의 핵심 변경을 정리하고, Xenomai 4·EVL과 함께 RTOS와의 선택 기준을 비교합니다. threaded IRQ·sleeping spinlock·cyclictest까지 한 지도에 모읍니다.
이 글을 참조하는 글 (5)
- ARM64 Secondary Core Bring-up — PSCI CPU_ON 호출부터 EL1 진입까지— Bootloader Internals
- PSCI와 SMCCC ABI — ARM 표준 SMC 호출 규약 분석— Bootloader Internals
- RISC-V Context Switch 분석 — ECALL·mret·CSR— Practical RTOS Internals
- ARM Cortex-M Context Switch — PendSV·MSP/PSP 어셈블리 추적— Practical RTOS Internals
- Context Switch 원리 분석 — 레지스터 저장·복원·Stack Frame— Practical RTOS Internals