이 코드는 어떤 문제를 푸나요?
EL0 프로그램의 시스템 호출은 일반 함수 호출보다 준비할 일이 많습니다. 하드웨어의 예외 상태 저장 다음에 Linux가 pt_regs를 만들고 C 처리 환경을 준비합니다. 이 단원은 v6.18.37의 el0_svc 전체를 읽어 원본 entry.S 분석과 C 단계가 이어지는 지점을 설명합니다.
읽을 범위: v6.18.37 · arch/arm64/kernel/entry-common.c · el0_svc 743–752행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.
먼저 알아둘 개념
EL0와 EL1
일반 사용자 실행과 운영체제의 권한 수준을 구분합니다. VHE 등의 구성 설명과 함께 읽되 모든 예외를 단순히 한 단계 상승이라고 외우지는 않습니다.
하드웨어 저장과 소프트웨어 저장
ELR/SPSR 저장만으로 범용 레지스터가 보존되는 것은 아닙니다. 진입 어셈블리의 추가 저장이 필요합니다.
사용자 복귀 준비
시그널·재스케줄 등의 작업을 처리한 뒤 어셈블리 복귀 경로가 저장 상태로 돌아갑니다.
처음 읽을 때
SVC 전에 사용자가 가진 레지스터 값이 어디에 보관되는지 표시하십시오.
더 깊이 살펴볼 때
noinstr 구간, erratum, FP 상태, DAIF 복원의 순서와 계측 가능 시점을 검토하십시오.
그림으로 보는 변화
EL0 SVC의 어셈블리→C 인계 지점
다음은 v6.18.37의 64비트 EL0 동기 예외 중 SVC64로 분류되는 길입니다. 각 상자는 실제 코드의 호출·분기 경계를 표시합니다.
- entry.S · 벡터동기 벡터
kernel_ventry 0,t,64,sync가 EL0 64비트 동기 예외용 진입점입니다. - entry.S · 저장
pt_regs준비스택에 공간을 확보하고kernel_entry가 범용 레지스터와 ELR/SPSR를 저장합니다. - entry.S → C호출 경계
entry_handler 0,t,64,sync전개에서x0=sp뒤bl el0t_64_sync_handler로 저장 프레임을 건넵니다. - entry-common.c · CSVC64 선택
el0t_64_sync_handler()가ESR_ELx_EC(esr)을 검사하고SVC64에서el0_svc(regs)를 호출합니다. - C → syscall.c시스템 호출 처리로
el0_svc()가 진입 처리를 거쳐do_el0_svc(regs)를 호출하고,syscall.c가regs->regs[8]을 전달합니다.
이 도식은 EL0 AArch64 SVC64의 진입·C 호출만 펼칩니다. 같은 동기 벡터의 다른 예외 분기, AArch32 호환 경로, C 함수 뒤의 복귀 처리와 최종 예외 복귀 명령은 여기서 추적하지 않습니다.
| 파일·단계 | 직접 확인한 코드 | 다음 단계로 넘기는 것 |
|---|---|---|
entry.S 벡터·저장 | 530행 벡터, 57행 PT_REGS_SIZE 공간, 197–304행 kernel_entry | 스택의 pt_regs 프레임 |
entry.S 호출 | 570–597행 entry_handler 정의·EL0 64비트 sync 인스턴스 | x0=sp로 C el0t_64_sync_handler 호출 |
entry-common.c 분기 | 762–769행 ESR의 SVC64 선택 | el0_svc(regs)로 전달 |
entry-common.c·syscall.c | el0_svc() 743–752행, do_el0_svc() 149–152행 | regs->regs[8]의 syscall 번호로 공통 처리 호출 |

el0_svc() C 함수의 내부 순서를 단순화합니다. 위 도식·표는 그 앞의 entry.S 저장·C 호출 경계를 따로 보입니다.1. pt_regs 완성
어셈블리에서 C에 넘길 저장 프레임을 만듭니다.
화살표는 사용자 상태의 보존입니다.
2. 커널 서비스 실행
el0_svc가 진입 준비 후 do_el0_svc로 넘깁니다.
화살표는 C 함수 호출 관계입니다.
3. C 쪽 종료 준비
el0_svc()의 끝에서 사용자 모드 종료 작업과 FP 상태 처리를 호출합니다.
최종 예외 복귀 명령은 이 함수와 위 진입 도식의 범위 밖에 있습니다.
el0_svc를 한 줄씩 읽기
줄 번호는 v6.18.37 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.
static void noinstr el0_svc(struct pt_regs *regs)
{
arm64_enter_from_user_mode(regs);
cortex_a76_erratum_1463225_svc_handler();
fpsimd_syscall_enter();
local_daif_restore(DAIF_PROCCTX);
do_el0_svc(regs);
arm64_exit_to_user_mode(regs);
fpsimd_syscall_exit();
}static void noinstr el0_svc(struct pt_regs *regs)EL0에서 온 AArch64 시스템 호출의 C 진입 함수입니다. regs에는 어셈블리에서 준비한 사용자 상태가 들어 있습니다. noinstr는 이 민감한 구간의 계측을 제한합니다.
arm64_enter_from_user_mode(regs);사용자 실행에서 커널 실행으로 들어왔음을 커널의 진입 상태 관리에 반영합니다. 원래 레지스터 값을 새로 저장하는 함수 호출로 읽지 않습니다.
cortex_a76_erratum_1463225_svc_handler();Cortex-A76의 특정 erratum을 위한 SVC 진입 보완 경로를 호출합니다. 영향을 받지 않는 시스템까지 같은 추가 동작을 한다고 가정하지 않습니다.
fpsimd_syscall_enter();시스템 호출 경계에서 FP·벡터 상태와 mode를 정리합니다. 일반 정수 인수만 전달하는 단계와 구분합니다.
local_daif_restore(DAIF_PROCCTX);프로세스 문맥에 맞는 DAIF 상태를 복원해 정상 커널 처리에 필요한 예외 허용 상태를 갖춥니다.
do_el0_svc(regs);실제 syscall 번호 해석과 공통 진입 작업을 담당하는 do_el0_svc로 넘깁니다.
arm64_exit_to_user_mode(regs);사용자 복귀 전에 처리해야 할 일을 수행합니다. 시그널이나 스케줄 작업 등으로 단순히 즉시 복귀하지 않을 수 있습니다.
fpsimd_syscall_exit();시스템 호출 종료에 필요한 FP·벡터 상태 처리를 수행합니다. 최종 ERET는 이 함수 밖의 어셈블리 복귀 경로에 있습니다.
함께 생각해 볼 질문
ESR을 읽으면 모든 레지스터가 저장됩니까?
아닙니다. ESR은 예외 원인 정보입니다.
noinstr는 코드가 실행되지 않는다는 뜻입니까?
아닙니다. 민감한 경로에 일반적인 계측을 제한하는 표시입니다.
시스템 호출마다 FP 레지스터 전체를 복사합니까?
구체적인 FP/SVE/SME 상태와 helper의 조건을 따라야 하며 항상 전체 복사라고 단정할 수 없습니다.
출처와 읽은 범위
진입 도식의 추가 근거: entry.S 벡터 매크로 39–68행, 저장 매크로 197–304행, EL0 64비트 동기 벡터 530행, 호출 매크로·인스턴스 570–597행 · entry-common.c SVC64 분기 762–769행 · syscall.c 149–152행. 이는 아래 el0_svc() 줄별 분석 범위의 앞뒤 경계를 표시합니다.
Linux stable v6.18.37 · arch/arm64/kernel/entry-common.c
해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고
