이 파일은 왜 필요한가요?
C 함수가 구조체로 표현한 요청을 펌웨어의 레지스터 호출 규약으로 바꾸는 중간 코드입니다. 펌웨어는 C 구조체 이름을 알지 못합니다. 약속된 레지스터에 값을 넣어 SMC 또는 HVC를 실행하고, 돌아온 레지스터 값을 다시 구조체에 담아 줍니다.
명령·지시문·라벨을 원본 줄 번호에 맞춰 설명합니다. 주석과 빈 줄을 포함한 전체 원문은 아래에 따로 두었습니다. 매크로 정의와 조건부 코드는 모두 차례대로 실행되는 명령 목록이 아닙니다.
기존 코드 분석과 함께 읽기 · 원본 파일 · 설명 원고
먼저 알아둘 개념: 호출 규약, 호출 주소와 복귀 주소, 레지스터와 값, SP와 스택 공간, 예외 레벨과 복귀
처음 읽을 때
args 포인터 자체와 args가 가리키는 값은 다릅니다. x0를 인자 값으로 덮어쓰기 전에 구조체 주소를 x19에 옮기는 이유를 확인하세요.
더 깊이 살펴볼 때
기본 SMCCC와 1.2 형식의 레지스터 범위, AAPCS64의 스택 인자, callee-saved x19 보존, Qualcomm quirk를 서로 구분해 보세요.
한 줄씩 레지스터와 메모리 상태 보기
각 코드 아래의 ‘행 그림’을 펼치면, 그 줄에서 읽는 값과 실행 전·후의 상태를 나란히 볼 수 있습니다. 여기서 ‘명령 직전’은 지금 보고 있는 명령이 실행되기 바로 전을 뜻합니다. 함수 진입 때나 소스의 바로 윗줄을 가리키는 말은 아닙니다. 앞서 실행한 명령이 값을 바꿨다면 그 결과가 들어 있습니다.
소스로 정해지는 상수, 호출자가 넘기는 값, 실제 실행에서 정해지는 주소를 구분해서 읽어야 합니다. 주소 숫자를 몰라도 무엇을 가리키는지와 어디서 받아 오는지는 설명할 수 있습니다. ‘명령 직전 x0의 값’처럼 일반 표기로 남은 곳은 한 명령의 동작을 나타내며, 특정 호출 경로의 값까지 확인했다는 뜻은 아닙니다.
일반 명령은 그 한 줄의 효과를, 매크로는 여러 명령을 묶은 주요 결과를 표시합니다. 함수 호출은 호출 직후의 PC와 LR까지만 나타냅니다. 메모리 접근은 정상적으로 끝나는 경우를 가정합니다. 생략된 항목까지 모두 보존된다는 뜻은 아닙니다.
화살표 →는 같은 항목의 전후 비교입니다. 메모리 칸에는 주소와 크기를 따로 적었습니다. SP가 줄어들면 낮은 주소 쪽을 사용하며, 화면의 위아래와 메모리 주소 방향은 별개입니다. 전처리·어셈블·링크 지시문은 CPU 실행과 구분합니다.
‘이전·다음 행’은 소스에 적힌 순서입니다. 분기·반복·호출이 있으므로 파일 위에서 아래로 실제 실행된다고 가정하지 않습니다. 값이 여러 줄에 걸쳐 이어지는 모습은 cpu-reset.S의 단계별 예제에서 보실 수 있습니다.
총 59개 줄에 그림을 붙였습니다. 기존 코드와 설명은 그 아래에서 이어집니다.
먼저 그림으로 살펴보기
기본 SMCCC 매크로
#include <linux/linkage.h>C에서 호출할 어셈블리 함수의 심볼 선언과 모듈 공개에 필요한 linkage 정의를 가져옵니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
5행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <linux/arm-smccc.h>SMCCC는 커널과 펌웨어·하이퍼바이저 사이의 서비스 호출 규약입니다. 이 헤더에서 결과 구조체, 1.2 확장 레지스터 구조체와 Qualcomm A6 quirk 식별값을 정의합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
6행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <asm/asm-offsets.h>C의 SMCCC 결과·입력·quirk 구조체 필드 위치를 어셈블리에서 사용할 오프셋으로 가져옵니다. 커널 빌드가 offsetof로 생성하므로 구조체 배치와 별도로 숫자를 추측할 필요가 없습니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
8행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <asm/assembler.h>ARM64 공통 어셈블리 매크로와 필요한 하위 헤더 정의를 포함합니다. 실제 서비스 요청·결과 이동은 아래의 SMCCC와 SMCCC_1_2 매크로 본문에 구현됩니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
9행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.macro SMCCC instrSMC와 HVC에 공통인 SMCCC 호출 코드를 만듭니다. x0~x7에는 서비스 번호와 인자가 이미 들어 있으며, 9·10번째 C 인자인 결과 구조체와 선택적 quirk 구조체는 스택에서 가져옵니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
11행 그림 · 어셈블·링크 단계
매크로 본문: SMCCC
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
\instr #0매크로 인자에 따라 SMC 또는 HVC를 실행해 펌웨어·하이퍼바이저 서비스에 요청합니다. 실제 서비스 번호는 x0에 있으며 명령의 #0은 그 서비스 번호가 아닙니다. 돌아오면 x0~x3에 서비스 결과가 들어 있습니다. 일반 함수 호출처럼 BL로 이동하는 대신 동기 예외를 통해 요청을 전달합니다.
instr는 smc/hvc로 치환됩니다. 함수 번호는 즉시값 #0이 아니라 x0입니다.
12행 그림 · 예외 처리기로 제어 전달
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 허용된 정상 예외 진입을 나타냅니다. 사용이 금지되거나 해당 EL이 없으면 예외 결과가 달라집니다. x0 등의 요청 인자는 처리기가 규약에 따라 읽으며 HVC/SMC 자체가 메모리로 복사하지는 않습니다.
- 서비스를 처리한 뒤의 반환 레지스터는 서비스 규약에 따릅니다. 여기서는 진입까지만 표시합니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldr x4, [sp]호출자가 스택에 넘긴 9번째 인자 res를 x4에 읽습니다. 레지스터 인자 x0~x7은 서비스 호출에 썼으므로 결과 저장 위치를 이때 스택에서 가져옵니다. 실제로 sp 주소의 메모리 8바이트를 x4에 읽습니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
AAPCS64에서 앞의 8개 정수 인자가 x0–x7을 차지해 아홉 번째 결과 포인터가 [SP]에 있습니다.
13행 그림 · 메모리 읽기
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]서비스가 돌려준 x0·x1을 res의 a0·a1 필드에 저장합니다. 이 래퍼의 C 반환형은 void이고 실제 결과는 구조체로 전달됩니다. 메모리에서는 x4 + (ARM_SMCCC_RES_X0_OFFS) 위치가 첫 레지스터 x0에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x1에 대응합니다. 이 주소 형식은 기준 레지스터 x4 자체를 갱신하지 않습니다.
14행 그림 · 메모리 쓰기
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]나머지 표준 결과 x2·x3도 res의 a2·a3에 저장하여 호출자가 네 레지스터 결과를 읽을 수 있게 합니다. 메모리에서는 x4 + (ARM_SMCCC_RES_X2_OFFS) 위치가 첫 레지스터 x2에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x3에 대응합니다. 이 주소 형식은 기준 레지스터 x4 자체를 갱신하지 않습니다.
15행 그림 · 메모리 쓰기
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldr x4, [sp, #8]10번째 인자인 quirk 포인터를 스택의 다음 8바이트 자리에서 읽습니다. 특정 펌웨어의 비표준 반환값을 추가로 보존할 때 사용합니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
열 번째 인자인 quirk 포인터는 [SP+8]입니다.
16행 그림 · 메모리 읽기
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
cbz x4, 1f /* no quirk structure */quirk 포인터가 NULL이면 제조사별 추가 처리가 필요 없으므로 바로 복귀합니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
17행 그림 · 조건별 실행 위치
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 조건이 맞는 한 경로만 실행합니다. 이 분기 명령은 NZCV를 새로 계산하지 않습니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]quirk 구조체의 식별값을 읽습니다. 어떤 예외 처리를 요청했는지 확인한 뒤 해당하는 경우에만 추가 레지스터를 보존합니다. 실제로 x4 + (ARM_SMCCC_QUIRK_ID_OFFS) 주소의 메모리 8바이트를 x9에 읽습니다. 이 주소 형식은 기준 레지스터 x4 자체를 갱신하지 않습니다.
18행 그림 · 메모리 읽기
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6Qualcomm의 A6 예외 처리를 요청했는지 비교합니다. 이 값은 일반 SMCCC 결과 x0~x3 외에 호출 후 x6 값도 돌려받아야 하는 경우를 식별합니다. CMP는 두 피연산자의 뺄셈 결과로 NZCV 조건 플래그만 갱신하고 원래 레지스터 값은 유지합니다.
19행 그림 · 조건 플래그 계산
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 일반 레지스터에 연산 결과를 쓰지 않고 조건 플래그만 바꿉니다.
- N은 결과의 부호 비트, Z는 결과가 0인지 나타냅니다. C는 빌림이 없으면 1, V는 부호 있는 뺄셈의 오버플로를 나타냅니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
b.ne 1fQualcomm A6 quirk가 아니면 x6를 저장하지 않고 복귀합니다. 앞서 계산한 NZCV 중 Z=0 조건으로 분기합니다. 이 줄은 두 값을 새로 비교하지 않으며 조건이 맞지 않으면 다음 명령으로 진행합니다.
20행 그림 · 조건별 실행 위치
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 조건이 맞는 한 경로만 실행합니다. 이 분기 명령은 NZCV를 새로 계산하지 않습니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]호출 후 x6를 quirk->state.a6에 보관합니다. x6가 표준 결과 구조체에 포함되지 않으므로 이 별도 경로로 호출자에게 전달합니다. 실제로 x4 + (ARM_SMCCC_QUIRK_STATE_OFFS) 주소의 메모리 8바이트를 x6의 값으로 씁니다. 이 주소 형식은 기준 레지스터 x4 자체를 갱신하지 않습니다.
해당 Qualcomm 우회에서만 x6을 추가 결과로 보존합니다.
21행 그림 · 메모리 쓰기
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
1: ret표준 결과와 필요한 추가 결과를 메모리에 저장한 뒤 C 호출자로 돌아갑니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
22행 그림 · 호출과 실행 위치
매크로 본문: SMCCC
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
- 매크로 SMCCC의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
23행 그림 · 어셈블·링크 단계
매크로 본문: SMCCC
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SMC와 HVC 함수 생성
SYM_FUNC_START(__arm_smccc_smc)SMC를 사용해 SMCCC 서비스를 부르는 C 호출 진입점입니다. x0~x7의 요청 인자와 스택의 결과 포인터를 공통 매크로가 처리합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
31행 그림 · 어셈블·링크 단계
함수·코드 범위: __arm_smccc_smc
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
SMCCC smc공통 호출 본문의 명령을 SMC로 선택합니다. 보안 모니터 경로에 요청하고 돌아온 x0~x3 및 선택적 Qualcomm x6 결과를 저장합니다. 결과는 호출자가 넘긴 C 구조체의 필드에 기록되므로 C 코드가 레지스터 값을 직접 읽을 필요가 없습니다.
32행 그림 · 매크로 전체의 주요 상태
함수·코드 범위: __arm_smccc_smc
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- QCOM_A6 quirk이면 x6도 quirk 구조체에 기록합니다. x4·x9와 NZCV는 결과 저장·조건 검사에서 사용합니다. 서비스가 정상적으로 반환하는 경우의 전체 흐름입니다.
- 여러 명령과 조건부 경로를 묶은 그림입니다. 이 목록이 모든 임시 레지스터의 변경을 열거하는 것은 아닙니다. 아래 매크로 본문에서 각 단계를 확인하실 수 있습니다.
SMCCC 매크로 본문 · 11행
arch/arm64/kernel/smccc-call.S · Linux v6.18.37
.macro SMCCC instr
\instr #0
ldr x4, [sp]
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
ldr x4, [sp, #8]
cbz x4, 1f /* no quirk structure */
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
b.ne 1f
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
1: ret
.endmSYM_FUNC_END(__arm_smccc_smc)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
33행 그림 · 어셈블·링크 단계
함수·코드 범위: __arm_smccc_smc
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
EXPORT_SYMBOL(__arm_smccc_smc)__arm_smccc_smc를 모듈에서도 참조할 수 있도록 커널 심볼 공개 정보를 생성합니다. 드라이버 모듈이 SMC 서비스를 요청할 수 있게 하는 빌드 메타데이터이며 여기서 서비스를 실행하지는 않습니다.
34행 그림 · 어셈블·링크 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(__arm_smccc_hvc)HVC를 사용해 SMCCC 서비스를 부르는 C 호출 진입점입니다. SMC 진입점과 인자·결과 배치는 같고 요청을 전달하는 통로만 다릅니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
42행 그림 · 어셈블·링크 단계
함수·코드 범위: __arm_smccc_hvc
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
SMCCC hvc공통 본문에서 HVC 통로를 선택합니다. 하이퍼바이저 경로에 요청하고 결과를 호출자의 구조체로 옮깁니다.
43행 그림 · 매크로 전체의 주요 상태
함수·코드 범위: __arm_smccc_hvc
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- QCOM_A6 quirk이면 x6도 quirk 구조체에 기록합니다. x4·x9와 NZCV는 결과 저장·조건 검사에서 사용합니다. 서비스가 정상적으로 반환하는 경우의 전체 흐름입니다.
- 여러 명령과 조건부 경로를 묶은 그림입니다. 이 목록이 모든 임시 레지스터의 변경을 열거하는 것은 아닙니다. 아래 매크로 본문에서 각 단계를 확인하실 수 있습니다.
SMCCC 매크로 본문 · 11행
arch/arm64/kernel/smccc-call.S · Linux v6.18.37
.macro SMCCC instr
\instr #0
ldr x4, [sp]
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
ldr x4, [sp, #8]
cbz x4, 1f /* no quirk structure */
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
b.ne 1f
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
1: ret
.endmSYM_FUNC_END(__arm_smccc_hvc)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
44행 그림 · 어셈블·링크 단계
함수·코드 범위: __arm_smccc_hvc
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
EXPORT_SYMBOL(__arm_smccc_hvc)__arm_smccc_hvc를 모듈에서도 참조할 수 있도록 커널 심볼 공개 정보를 생성합니다. 드라이버 모듈이 HVC 서비스를 요청할 수 있게 하는 빌드 메타데이터이며 여기서 서비스를 실행하지는 않습니다.
45행 그림 · 어셈블·링크 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SMCCC 1.2의 구조체 교환
.macro SMCCC_1_2 instrSMCCC 1.2에서 사용하는 x0~x17 전체를 입력·결과 구조체와 주고받는 매크로입니다. 처음의 x0는 args 포인터, x1은 res 포인터이며 곧 레지스터를 요청 값으로 채우므로 두 포인터를 먼저 보존해야 합니다. 이 줄은 어셈블러 매크로 정의의 시작입니다. 본문은 매크로를 사용하는 위치에 펼쳐지며, 정의 자체가 런타임 함수 호출은 아닙니다.
47행 그림 · 어셈블·링크 단계
매크로 본문: SMCCC_1_2
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 뒤의 본문은 이 이름을 사용하는 위치에 펼쳐집니다. 정의 위치를 CPU가 함수처럼 호출하지 않습니다.
stp x1, x19, [sp, #-16]!결과 구조체 포인터 x1과 호출자의 x19를 16바이트 스택 공간에 저장합니다. 결과 포인터는 서비스 이후까지, x19는 C 호출 규약에 맞춰 복귀할 때까지 보존합니다. 메모리에서는 sp + (-16) 위치가 첫 레지스터 x1에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x19에 대응합니다. 대괄호 뒤의 !는 주소 갱신을 뜻합니다. sp에 오프셋 -16을 더한 주소로 접근하고 그 주소를 sp에도 남깁니다.
x1의 결과 포인터를 보존하고 x19도 스택에 저장합니다. 총 16바이트를 확보합니다.
49행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- !는 전위 갱신입니다. 오프셋을 더한 주소로 접근하고 그 주소를 기준 레지스터에도 남깁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
mov x19, x0입력 구조체 주소를 x19에 옮깁니다. x0부터 요청 값으로 덮어쓰므로 주소를 x0에 그대로 두면 뒤의 인자들을 읽을 수 없습니다. MOV는 x19의 기존 값을 대체합니다. 원본이 주소값이어도 그 주소의 메모리를 읽거나 복사하지 않습니다.
x0를 이후 인자 값으로 덮어써도 구조체를 계속 읽도록 기준을 x19에 둡니다.
52행 그림 · 값 복사
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 화살표는 값의 변화를 뜻합니다. 주소값을 옮겨도 그 주소의 메모리 내용은 복사하지 않습니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]입력 구조체 args의 a0·a1을 x0·x1에 넣습니다. a0는 요청할 SMCCC 서비스 번호이고 a1은 그 서비스가 정의한 인자입니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X0_OFFS) 위치가 첫 레지스터 x0에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x1에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
55행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]입력 구조체 args의 a2·a3을 x2·x3에 넣습니다. 각 값의 구체적인 의미는 a0의 서비스 번호가 정한 호출 규약에 따릅니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X2_OFFS) 위치가 첫 레지스터 x2에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x3에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
56행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]입력 구조체 args의 a4·a5을 x4·x5에 넣습니다. 각 값의 구체적인 의미는 a0의 서비스 번호가 정한 호출 규약에 따릅니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X4_OFFS) 위치가 첫 레지스터 x4에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x5에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
57행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]입력 구조체 args의 a6·a7을 x6·x7에 넣습니다. 각 값의 구체적인 의미는 a0의 서비스 번호가 정한 호출 규약에 따릅니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X6_OFFS) 위치가 첫 레지스터 x6에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x7에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
58행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]입력 구조체 args의 a8·a9을 x8·x9에 넣습니다. 각 값의 구체적인 의미는 a0의 서비스 번호가 정한 호출 규약에 따릅니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X8_OFFS) 위치가 첫 레지스터 x8에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x9에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
59행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]입력 구조체 args의 a10·a11을 x10·x11에 넣습니다. 각 값의 구체적인 의미는 a0의 서비스 번호가 정한 호출 규약에 따릅니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X10_OFFS) 위치가 첫 레지스터 x10에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x11에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
60행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]입력 구조체 args의 a12·a13을 x12·x13에 넣습니다. 각 값의 구체적인 의미는 a0의 서비스 번호가 정한 호출 규약에 따릅니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X12_OFFS) 위치가 첫 레지스터 x12에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x13에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
61행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]입력 구조체 args의 a14·a15을 x14·x15에 넣습니다. 각 값의 구체적인 의미는 a0의 서비스 번호가 정한 호출 규약에 따릅니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X14_OFFS) 위치가 첫 레지스터 x14에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x15에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
62행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]입력 구조체 args의 a16·a17을 x16·x17에 넣습니다. 각 값의 구체적인 의미는 a0의 서비스 번호가 정한 호출 규약에 따릅니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X16_OFFS) 위치가 첫 레지스터 x16에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x17에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
63행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
\instr #0구조체에서 채운 x0~x17을 사용해 SMC 또는 HVC를 실행합니다. SMCCC 1.2의 더 넓은 인자·결과 레지스터 집합을 사용하는 호출이며, 실제 요청 의미는 x0의 서비스 번호에 따릅니다. 일반 함수 호출처럼 BL로 이동하는 대신 동기 예외를 통해 요청을 전달합니다.
65행 그림 · 예외 처리기로 제어 전달
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 허용된 정상 예외 진입을 나타냅니다. 사용이 금지되거나 해당 EL이 없으면 예외 결과가 달라집니다. x0 등의 요청 인자는 처리기가 규약에 따라 읽으며 HVC/SMC 자체가 메모리로 복사하지는 않습니다.
- 서비스를 처리한 뒤의 반환 레지스터는 서비스 규약에 따릅니다. 여기서는 진입까지만 표시합니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldr x19, [sp]스택에 보관한 res 포인터를 x19에 읽습니다. 서비스가 반환한 x0~x17을 손상시키지 않으면서 결과를 저장하기 위한 기준 주소입니다. 실제로 sp 주소의 메모리 8바이트를 x19에 읽습니다. 이 주소 형식은 기준 레지스터 sp 자체를 갱신하지 않습니다.
첫 스택 슬롯에 남긴 res 포인터를 x19로 읽습니다.
68행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]서비스가 반환한 x0·x1을 결과 구조체 res의 a0·a1에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X0_OFFS) 위치가 첫 레지스터 x0에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x1에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
71행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]서비스가 반환한 x2·x3을 결과 구조체 res의 a2·a3에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X2_OFFS) 위치가 첫 레지스터 x2에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x3에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
72행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]서비스가 반환한 x4·x5을 결과 구조체 res의 a4·a5에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X4_OFFS) 위치가 첫 레지스터 x4에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x5에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
73행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]서비스가 반환한 x6·x7을 결과 구조체 res의 a6·a7에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X6_OFFS) 위치가 첫 레지스터 x6에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x7에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
74행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]서비스가 반환한 x8·x9을 결과 구조체 res의 a8·a9에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X8_OFFS) 위치가 첫 레지스터 x8에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x9에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
75행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]서비스가 반환한 x10·x11을 결과 구조체 res의 a10·a11에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X10_OFFS) 위치가 첫 레지스터 x10에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x11에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
76행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]서비스가 반환한 x12·x13을 결과 구조체 res의 a12·a13에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X12_OFFS) 위치가 첫 레지스터 x12에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x13에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
77행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]서비스가 반환한 x14·x15을 결과 구조체 res의 a14·a15에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X14_OFFS) 위치가 첫 레지스터 x14에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x15에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
78행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
stp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]서비스가 반환한 x16·x17을 결과 구조체 res의 a16·a17에 저장합니다. SMCCC 1.2에서 이 레지스터 쌍까지 결과로 전달할 수 있도록 빠짐없이 보관합니다. 메모리에서는 x19 + (ARM_SMCCC_1_2_REGS_X16_OFFS) 위치가 첫 레지스터 x16에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x17에 대응합니다. 이 주소 형식은 기준 레지스터 x19 자체를 갱신하지 않습니다.
79행 그림 · 메모리 쓰기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
ldp xzr, x19, [sp], #16스택의 결과 포인터 자리는 xzr로 버리고 호출자의 원래 x19를 복원합니다. SP도 16바이트 되돌려 래퍼가 만든 저장 공간을 해제합니다. 메모리에서는 sp 위치가 첫 레지스터 xzr에 대응하고, 그보다 8바이트 높은 위치가 두 번째 레지스터 x19에 대응합니다. 대괄호 밖의 오프셋 16은 후위 갱신입니다. 기존 sp 주소로 접근한 뒤 sp에 이 값을 더합니다.
res 포인터 저장 슬롯은 버리고 원래 x19를 되살립니다. SP는 16 증가합니다.
82행 그림 · 메모리 읽기
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 대괄호 밖의 오프셋은 후위 갱신입니다. 이전 주소로 접근한 뒤 기준 레지스터를 갱신합니다.
- 메모리 칸은 낮은 주소부터 나열했습니다. SP를 줄이면 더 낮은 주소의 공간을 사용합니다. 화면의 아래쪽이 곧 낮은 주소라는 뜻은 아닙니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
retx0~x17 결과를 res에 저장한 뒤 C 호출자로 돌아갑니다. 호출자는 함수의 직접 반환값 대신 res 구조체를 확인합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
83행 그림 · 호출과 실행 위치
매크로 본문: SMCCC_1_2
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
- 매크로 SMCCC_1_2의 본문입니다. \이름은 호출 위치에서 실제 레지스터나 인수로 바뀝니다.
.endm공통 작업의 정의를 여기서 마칩니다. RET가 아니라 빌드 도구가 읽는 경계입니다.
84행 그림 · 어셈블·링크 단계
매크로 본문: SMCCC_1_2
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
2 함수 두 개
SYM_FUNC_START(arm_smccc_1_2_hvc)입력·결과 구조체를 받는 SMCCC 1.2 HVC 진입점입니다. 두 구조체의 a0~a17이 실제 요청·반환 레지스터와 대응합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
90행 그림 · 어셈블·링크 단계
함수·코드 범위: arm_smccc_1_2_hvc
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
SMCCC_1_2 hvcSMCCC 1.2 공통 본문을 HVC 방식으로 펼칩니다. 입력 구조체를 레지스터로 옮기고 하이퍼바이저 요청 결과를 다시 구조체에 저장합니다.
91행 그림 · 매크로 전체의 주요 상태
함수·코드 범위: arm_smccc_1_2_hvc
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 이 행은 매크로 전체가 정상 반환한 결과입니다. 중간에는 SP를 16바이트 낮추고 x19를 구조체 포인터로 사용합니다. 입출력 버퍼를 구분하며 반환 숫자를 임의로 정하지 않습니다.
- 여러 명령과 조건부 경로를 묶은 그림입니다. 이 목록이 모든 임시 레지스터의 변경을 열거하는 것은 아닙니다. 아래 매크로 본문에서 각 단계를 확인하실 수 있습니다.
SMCCC_1_2 매크로 본문 · 47행
arch/arm64/kernel/smccc-call.S · Linux v6.18.37
.macro SMCCC_1_2 instr
/* Save `res` and free a GPR that won't be clobbered */
stp x1, x19, [sp, #-16]!
/* Ensure `args` won't be clobbered while loading regs in next step */
mov x19, x0
/* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */
ldp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
ldp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
ldp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
ldp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
ldp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
ldp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
ldp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
ldp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
ldp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
\instr #0
/* Load the `res` from the stack */
ldr x19, [sp]
/* Store the registers x0 - x17 into the result structure */
stp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
stp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
stp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
stp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
stp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
stp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
stp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
stp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
stp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
/* Restore original x19 */
ldp xzr, x19, [sp], #16
ret
.endmSYM_FUNC_END(arm_smccc_1_2_hvc)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
92행 그림 · 어셈블·링크 단계
함수·코드 범위: arm_smccc_1_2_hvc
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
EXPORT_SYMBOL(arm_smccc_1_2_hvc)arm_smccc_1_2_hvc를 모듈에서도 참조할 수 있도록 커널 심볼 공개 정보를 생성합니다. 드라이버 모듈이 SMCCC 1.2 HVC 서비스를 요청할 수 있게 하는 빌드 메타데이터이며 여기서 서비스를 실행하지는 않습니다.
93행 그림 · 어셈블·링크 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(arm_smccc_1_2_smc)입력·결과 구조체를 받는 SMCCC 1.2 SMC 진입점입니다. 통로가 SMC라는 점 외에는 HVC 함수와 같은 구조체 배치를 사용합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
99행 그림 · 어셈블·링크 단계
함수·코드 범위: arm_smccc_1_2_smc
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
SMCCC_1_2 smcSMCCC 1.2 공통 본문을 SMC 방식으로 펼쳐 보안 모니터 경로에 요청합니다. 요청을 마치면 x0~x17을 결과 구조체에 보관합니다.
100행 그림 · 매크로 전체의 주요 상태
함수·코드 범위: arm_smccc_1_2_smc
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 이 행은 매크로 전체가 정상 반환한 결과입니다. 중간에는 SP를 16바이트 낮추고 x19를 구조체 포인터로 사용합니다. 입출력 버퍼를 구분하며 반환 숫자를 임의로 정하지 않습니다.
- 여러 명령과 조건부 경로를 묶은 그림입니다. 이 목록이 모든 임시 레지스터의 변경을 열거하는 것은 아닙니다. 아래 매크로 본문에서 각 단계를 확인하실 수 있습니다.
SMCCC_1_2 매크로 본문 · 47행
arch/arm64/kernel/smccc-call.S · Linux v6.18.37
.macro SMCCC_1_2 instr
/* Save `res` and free a GPR that won't be clobbered */
stp x1, x19, [sp, #-16]!
/* Ensure `args` won't be clobbered while loading regs in next step */
mov x19, x0
/* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */
ldp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
ldp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
ldp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
ldp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
ldp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
ldp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
ldp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
ldp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
ldp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
\instr #0
/* Load the `res` from the stack */
ldr x19, [sp]
/* Store the registers x0 - x17 into the result structure */
stp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
stp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
stp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
stp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
stp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
stp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
stp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
stp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
stp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
/* Restore original x19 */
ldp xzr, x19, [sp], #16
ret
.endmSYM_FUNC_END(arm_smccc_1_2_smc)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
101행 그림 · 어셈블·링크 단계
함수·코드 범위: arm_smccc_1_2_smc
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
EXPORT_SYMBOL(arm_smccc_1_2_smc)arm_smccc_1_2_smc를 모듈에서도 참조할 수 있도록 커널 심볼 공개 정보를 생성합니다. 드라이버 모듈이 SMCCC 1.2 SMC 서비스를 요청할 수 있게 하는 빌드 메타데이터이며 여기서 서비스를 실행하지는 않습니다.
102행 그림 · 어셈블·링크 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
설명한 뒤 함께 생각해 볼 질문
SMC #0의 0이 요청 함수 번호인가요?
아닙니다. 요청 식별자는 호출 규약에 따라 x0에 담깁니다. #0은 SMC/HVC 명령의 즉시값입니다.
기본 래퍼에서 결과 포인터가 왜 스택에 있나요?
앞의 정수 인자 8개가 x0–x7을 사용합니다. 아홉 번째 결과 포인터는 AAPCS64 규약에 따라 스택으로 전달됩니다.
1.2 래퍼가 원래 x19를 저장하는 이유는 무엇인가요?
래퍼 내부에서는 주소 계산에 사용하지만 x19는 호출자에게 보존해 줘야 하는 레지스터이기 때문입니다.
주석을 포함한 전체 원문
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3* Copyright (c) 2015, Linaro Limited4*/5#include <linux/linkage.h>6#include <linux/arm-smccc.h>78#include <asm/asm-offsets.h>9#include <asm/assembler.h>1011.macro SMCCC instr12\instr #013ldr x4, [sp]14stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]15stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]16ldr x4, [sp, #8]17cbz x4, 1f /* no quirk structure */18ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]19cmp x9, #ARM_SMCCC_QUIRK_QCOM_A620b.ne 1f21str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]221: ret23.endm2425/*26* void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,27* unsigned long a3, unsigned long a4, unsigned long a5,28* unsigned long a6, unsigned long a7, struct arm_smccc_res *res,29* struct arm_smccc_quirk *quirk)30*/31SYM_FUNC_START(__arm_smccc_smc)32SMCCC smc33SYM_FUNC_END(__arm_smccc_smc)34EXPORT_SYMBOL(__arm_smccc_smc)3536/*37* void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,38* unsigned long a3, unsigned long a4, unsigned long a5,39* unsigned long a6, unsigned long a7, struct arm_smccc_res *res,40* struct arm_smccc_quirk *quirk)41*/42SYM_FUNC_START(__arm_smccc_hvc)43SMCCC hvc44SYM_FUNC_END(__arm_smccc_hvc)45EXPORT_SYMBOL(__arm_smccc_hvc)4647.macro SMCCC_1_2 instr48/* Save `res` and free a GPR that won't be clobbered */49stp x1, x19, [sp, #-16]!5051/* Ensure `args` won't be clobbered while loading regs in next step */52mov x19, x05354/* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */55ldp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]56ldp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]57ldp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]58ldp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]59ldp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]60ldp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]61ldp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]62ldp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]63ldp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]6465\instr #06667/* Load the `res` from the stack */68ldr x19, [sp]6970/* Store the registers x0 - x17 into the result structure */71stp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]72stp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]73stp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]74stp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]75stp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]76stp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]77stp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]78stp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]79stp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]8081/* Restore original x19 */82ldp xzr, x19, [sp], #1683ret84.endm8586/*87* void arm_smccc_1_2_hvc(const struct arm_smccc_1_2_regs *args,88* struct arm_smccc_1_2_regs *res);89*/90SYM_FUNC_START(arm_smccc_1_2_hvc)91SMCCC_1_2 hvc92SYM_FUNC_END(arm_smccc_1_2_hvc)93EXPORT_SYMBOL(arm_smccc_1_2_hvc)9495/*96* void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args,97* struct arm_smccc_1_2_regs *res);98*/99SYM_FUNC_START(arm_smccc_1_2_smc)100SMCCC_1_2 smc101SYM_FUNC_END(arm_smccc_1_2_smc)102EXPORT_SYMBOL(arm_smccc_1_2_smc)

