이 파일은 왜 필요한가요?
프로그램의 계산 상태는 x0 같은 정수 레지스터에만 있지 않습니다. 소수 연산과 벡터 연산에도 별도 레지스터가 있습니다. 다른 태스크가 CPU를 쓰거나 커널이 이 기능을 사용할 때 원래 계산 상태를 잃지 않도록 저장하고 복원해야 합니다. 이 파일의 짧은 매크로 한 줄 안에는 여러 저장 명령이 들어 있습니다.
명령·지시문·라벨을 원본 줄 번호에 맞춰 설명합니다. 주석과 빈 줄을 포함한 전체 원문은 아래에 따로 두었습니다. 매크로 정의와 조건부 코드는 모두 차례대로 실행되는 명령 목록이 아닙니다.
기존 코드 분석과 함께 읽기 · 원본 파일 · 설명 원고
먼저 알아둘 개념: 레지스터와 값, 실행 상태의 저장과 복원, 매크로와 실제 CPU 명령, 주소와 주소가 가리키는 내용, 벡터 레지스터
처음 읽을 때
q0 하나는 16바이트입니다. 정수 레지스터 두 개를 저장하는 STP와 q 레지스터 두 개를 저장하는 STP의 바이트 수가 같지 않다는 점부터 확인하세요.
더 깊이 살펴볼 때
SVE와 SME는 현재 벡터 길이에 따라 상태 크기가 달라집니다. 포인터의 기준 위치, FFR을 다룰 수 있는 모드, ZA 이후에 놓이는 ZT 상태를 구분해 보세요.
한 줄씩 레지스터와 메모리 상태 보기
각 코드 아래의 ‘행 그림’을 펼치면, 그 줄에서 읽는 값과 실행 전·후의 상태를 나란히 볼 수 있습니다. 여기서 ‘명령 직전’은 지금 보고 있는 명령이 실행되기 바로 전을 뜻합니다. 함수 진입 때나 소스의 바로 윗줄을 가리키는 말은 아닙니다. 앞서 실행한 명령이 값을 바꿨다면 그 결과가 들어 있습니다.
소스로 정해지는 상수, 호출자가 넘기는 값, 실제 실행에서 정해지는 주소를 구분해서 읽어야 합니다. 주소 숫자를 몰라도 무엇을 가리키는지와 어디서 받아 오는지는 설명할 수 있습니다. ‘명령 직전 x0의 값’처럼 일반 표기로 남은 곳은 한 명령의 동작을 나타내며, 특정 호출 경로의 값까지 확인했다는 뜻은 아닙니다.
일반 명령은 그 한 줄의 효과를, 매크로는 여러 명령을 묶은 주요 결과를 표시합니다. 함수 호출은 호출 직후의 PC와 LR까지만 나타냅니다. 메모리 접근은 정상적으로 끝나는 경우를 가정합니다. 생략된 항목까지 모두 보존된다는 뜻은 아닙니다.
화살표 →는 같은 항목의 전후 비교입니다. 메모리 칸에는 주소와 크기를 따로 적었습니다. SP가 줄어들면 낮은 주소 쪽을 사용하며, 화면의 위아래와 메모리 주소 방향은 별개입니다. 전처리·어셈블·링크 지시문은 CPU 실행과 구분합니다.
‘이전·다음 행’은 소스에 적힌 순서입니다. 분기·반복·호출이 있으므로 파일 위에서 아래로 실제 실행된다고 가정하지 않습니다. 값이 여러 줄에 걸쳐 이어지는 모습은 cpu-reset.S의 단계별 예제에서 보실 수 있습니다.
총 63개 줄에 그림을 붙였습니다. 기존 코드와 설명은 그 아래에서 이어집니다.
먼저 그림으로 살펴보기
고정 크기 FP/SIMD 상태
#include <linux/linkage.h>SYM_FUNC_START·SYM_CODE_START·SYM_INNER_LABEL 등의 심볼 선언 규칙을 가져옵니다. 함수인지 코드 내부 라벨인지, 다른 오브젝트에 보일 이름인지와 정렬·크기 정보를 빌드 도구에 전달하는 데 필요합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
9행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <asm/assembler.h>ARM64의 큰 주소 구성, CPU별 값 조회, 시스템 레지스터 처리, 동기화 등에 쓰는 어셈블리 매크로를 가져옵니다. 각 사용 위치에서 일반 명령 여러 개로 펼쳐지는 작업입니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
11행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
#include <asm/fpsimdmacros.h>FP/SIMD·SVE·SME 레지스터 저장 형식과 명령 인코딩 매크로를 가져옵니다. 어떤 상태를 어느 offset에 저장하는지, 임시 레지스터 인수가 무엇인지가 여기에 정의됩니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
12행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(fpsimd_save_state)이 위치부터 (fpsimd_save_state)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
19행 그림 · 어셈블·링크 단계
함수·코드 범위: fpsimd_save_state
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
fpsimd_save x0, 8x0가 가리키는 저장 영역에 q0~q31의 SIMD/FP 값과 FPSR·FPCR을 보존합니다. 8은 주소나 벡터 수가 아니라 임시 x8/w8을 고르는 매크로 인수입니다. task 전환·시그널 등에서 계산 상태를 잃지 않으려는 저장이며 매크로 내부에서 x0도 이동합니다.
원래 x0=B라면 q0은 B, q31은 B+496에 저장됩니다. FPSR은 B+512, FPCR은 B+516입니다.
20행 그림 · 벡터·부동소수점 상태
함수·코드 범위: fpsimd_save_state
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 전체의 주요 데이터 이동입니다. 버퍼 포인터와 임시 레지스터가 중간에 바뀔 수 있으므로 아래 본문에서 실제 순서를 확인합니다.
fpsimd_save 매크로 본문 · 11행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro fpsimd_save state, tmpnr
stp q0, q1, [\state, #16 * 0]
stp q2, q3, [\state, #16 * 2]
stp q4, q5, [\state, #16 * 4]
stp q6, q7, [\state, #16 * 6]
stp q8, q9, [\state, #16 * 8]
stp q10, q11, [\state, #16 * 10]
stp q12, q13, [\state, #16 * 12]
stp q14, q15, [\state, #16 * 14]
stp q16, q17, [\state, #16 * 16]
stp q18, q19, [\state, #16 * 18]
stp q20, q21, [\state, #16 * 20]
stp q22, q23, [\state, #16 * 22]
stp q24, q25, [\state, #16 * 24]
stp q26, q27, [\state, #16 * 26]
stp q28, q29, [\state, #16 * 28]
stp q30, q31, [\state, #16 * 30]!
mrs x\tmpnr, fpsr
str w\tmpnr, [\state, #16 * 2]
mrs x\tmpnr, fpcr
str w\tmpnr, [\state, #16 * 2 + 4]
.endm retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
21행 그림 · 호출과 실행 위치
함수·코드 범위: fpsimd_save_state
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(fpsimd_save_state)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
22행 그림 · 어셈블·링크 단계
함수·코드 범위: fpsimd_save_state
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(fpsimd_load_state)이 위치부터 (fpsimd_load_state)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
29행 그림 · 어셈블·링크 단계
함수·코드 범위: fpsimd_load_state
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
fpsimd_restore x0, 8x0의 메모리 사본에서 q0~q31과 FPSR·FPCR을 CPU에 복원합니다. 임시 레지스터는 x8/w8이며 FPCR은 기존 값과 같으면 불필요한 쓰기를 피합니다. 저장 때와 같은 레이아웃의 버퍼가 필요합니다.
30행 그림 · 벡터·부동소수점 상태
함수·코드 범위: fpsimd_load_state
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 전체의 주요 데이터 이동입니다. 버퍼 포인터와 임시 레지스터가 중간에 바뀔 수 있으므로 아래 본문에서 실제 순서를 확인합니다.
fpsimd_restore 매크로 본문 · 47행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro fpsimd_restore state, tmpnr
ldp q0, q1, [\state, #16 * 0]
ldp q2, q3, [\state, #16 * 2]
ldp q4, q5, [\state, #16 * 4]
ldp q6, q7, [\state, #16 * 6]
ldp q8, q9, [\state, #16 * 8]
ldp q10, q11, [\state, #16 * 10]
ldp q12, q13, [\state, #16 * 12]
ldp q14, q15, [\state, #16 * 14]
ldp q16, q17, [\state, #16 * 16]
ldp q18, q19, [\state, #16 * 18]
ldp q20, q21, [\state, #16 * 20]
ldp q22, q23, [\state, #16 * 22]
ldp q24, q25, [\state, #16 * 24]
ldp q26, q27, [\state, #16 * 26]
ldp q28, q29, [\state, #16 * 28]
ldp q30, q31, [\state, #16 * 30]!
ldr w\tmpnr, [\state, #16 * 2]
msr fpsr, x\tmpnr
ldr w\tmpnr, [\state, #16 * 2 + 4]
fpsimd_restore_fpcr x\tmpnr, \state
.endm retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
31행 그림 · 호출과 실행 위치
함수·코드 범위: fpsimd_load_state
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(fpsimd_load_state)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
32행 그림 · 어셈블·링크 단계
함수·코드 범위: fpsimd_load_state
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SVE 저장과 벡터 길이
#ifdef CONFIG_ARM64_SVESVE는 기본 128비트 SIMD보다 긴 Z 벡터, P predicate와 FFR 상태를 추가하는 확장입니다. 이 설정을 켜야 아래 저장·복원·길이 조정 코드를 커널에 포함하여 지원 CPU의 task 상태를 관리할 수 있습니다. 꺼지면 아래 SVE 함수들은 빌드되지 않습니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
34행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(sve_save_state)이 위치부터 (sve_save_state)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
43행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
sve_save 0, x1, x2, 3x0를 SVE 저장 레이아웃의 FFR 기준 위치로 사용해 Z0~Z31과 P0~P15를 정해진 음수 offset에 저장합니다. 첫 인수 0은 주소 0이 아니라 x0 레지스터 번호입니다. x1은 FPSR/FPCR 저장 위치, x2는 FFR 보존 여부, 3은 임시 x3 번호입니다. x2=0이면 저장 이미지의 FFR은 0으로 만듭니다. 저장 공간의 크기와 Z·P·FFR 사이 오프셋은 현재 SVE 벡터 길이에 따라 달라집니다. 고정 크기인 FPSIMD 저장 형식과 구분해야 합니다.
0은 레지스터 번호 x0를 뜻합니다. x1은 FPSR/FPCR 저장 위치, x2는 FFR 저장 여부, 3은 임시 x3 번호입니다.
44행 그림 · 벡터·부동소수점 상태
함수·코드 범위: sve_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 전체의 주요 데이터 이동입니다. 버퍼 포인터와 임시 레지스터가 중간에 바뀔 수 있으므로 아래 본문에서 실제 순서를 확인합니다.
- 현재 벡터 길이가 저장 레이아웃을 정합니다. FFR을 저장하지 않는 경로에서는 버퍼의 FFR 슬롯을 0으로 채웁니다.
sve_save 매크로 본문 · 306행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sve_save nxbase, xpfpsr, save_ffr, nxtmp
_for n, 0, 31, _sve_str_v \n, \nxbase, \n - 34
_for n, 0, 15, _sve_str_p \n, \nxbase, \n - 16
cbz \save_ffr, 921f
_sve_rdffr 0
b 922f
921:
_sve_pfalse 0 // Zero out FFR
922:
_sve_str_p 0, \nxbase
_sve_ldr_p 0, \nxbase, -16
mrs x\nxtmp, fpsr
str w\nxtmp, [\xpfpsr]
mrs x\nxtmp, fpcr
str w\nxtmp, [\xpfpsr, #4]
.endm retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
45행 그림 · 호출과 실행 위치
함수·코드 범위: sve_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sve_save_state)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
46행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(sve_load_state)이 위치부터 (sve_load_state)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
55행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
sve_load 0, x1, x2, 4x0 기준의 Z·P 상태와 x1 위치의 FPSR/FPCR을 복원합니다. x2가 0이 아니면 FFR도 복원하고 0이면 FFR 로드를 생략합니다. 첫 인수 0과 마지막 4는 각각 x0 기준 주소와 임시 x4를 뜻하는 레지스터 번호입니다. 저장할 때와 같은 SVE 벡터 길이와 레이아웃을 사용해야 각 레지스터의 데이터를 올바른 위치에서 읽을 수 있습니다.
마지막 인자 4는 임시 x4 번호입니다.
56행 그림 · 벡터·부동소수점 상태
함수·코드 범위: sve_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 전체의 주요 데이터 이동입니다. 버퍼 포인터와 임시 레지스터가 중간에 바뀔 수 있으므로 아래 본문에서 실제 순서를 확인합니다.
- 현재 벡터 길이가 저장 레이아웃을 정합니다. FFR을 복원하지 않는 경로에서는 FFR 쓰기를 건너뜁니다.
sve_load 매크로 본문 · 323행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sve_load nxbase, xpfpsr, restore_ffr, nxtmp
_for n, 0, 31, _sve_ldr_v \n, \nxbase, \n - 34
cbz \restore_ffr, 921f
_sve_ldr_p 0, \nxbase
_sve_wrffr 0
921:
_for n, 0, 15, _sve_ldr_p \n, \nxbase, \n - 16
ldr w\nxtmp, [\xpfpsr]
msr fpsr, x\nxtmp
ldr w\nxtmp, [\xpfpsr, #4]
msr fpcr, x\nxtmp
.endm retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
57행 그림 · 호출과 실행 위치
함수·코드 범위: sve_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sve_load_state)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
58행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(sve_get_vl)이 위치부터 (sve_get_vl)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
60행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_get_vl
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
_sve_rdvl 0, 1RDVL 명령을 인코딩해 현재 SVE 벡터 길이의 1배를 바이트 단위로 x0에 반환합니다. 인수 0은 결과 레지스터 x0, 1은 길이 배수이며 bit 수나 저장 버퍼 주소가 아닙니다.
x0에 현재 SVE VL의 바이트 수를 반환합니다.
61행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: sve_get_vl
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
_sve_rdvl 매크로 본문 · 154행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro _sve_rdvl nx, imm
_check_general_reg \nx
_check_num (\imm), -0x20, 0x1f
.inst 0x04bf5000 \
| (\nx) \
| (((\imm) & 0x3f) << 5)
.endm retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
62행 그림 · 호출과 실행 위치
함수·코드 범위: sve_get_vl
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sve_get_vl)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
63행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_get_vl
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(sve_set_vq)이 위치부터 (sve_set_vq)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
65행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_set_vq
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
sve_load_vq x0, x1, x2x0의 VQ-1 값을 ZCR_EL1.LEN 필드에 반영하여 SVE 벡터 길이를 선택합니다. VQ는 16바이트 단위이며 0 인코딩은 128비트 길이입니다. x1·x2는 기존 제어값과 수정값을 계산할 임시 레지스터이고 같은 설정이면 레지스터 쓰기를 생략합니다.
x0는 VQ−1이며 x1/x2를 임시로 사용합니다.
66행 그림 · 벡터·부동소수점 상태
함수·코드 범위: sve_set_vq
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 값이 같으면 쓰기를 생략할 수 있으며 작업 레지스터는 매크로 내부에서 사용됩니다.
sve_load_vq 매크로 본문 · 269행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sve_load_vq xvqminus1, xtmp, xtmp2
mrs_s \xtmp, SYS_ZCR_EL1
bic \xtmp2, \xtmp, ZCR_ELx_LEN_MASK
orr \xtmp2, \xtmp2, \xvqminus1
cmp \xtmp2, \xtmp
b.eq 921f
msr_s SYS_ZCR_EL1, \xtmp2 //self-synchronising
921:
.endm retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
67행 그림 · 호출과 실행 위치
함수·코드 범위: sve_set_vq
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sve_set_vq)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
68행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_set_vq
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SVE 상위 영역 지우기
SYM_FUNC_START(sve_flush_live)이 위치부터 (sve_flush_live)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
79행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_flush_live
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
cbz x1, 1f // A VQ-1 of 0 is 128 bits so no extra Z statex1은 VQ-1입니다. 값 0이면 Z 레지스터가 기본 128비트뿐이므로 지울 상위 SVE 부분이 없어 sve_flush_z를 건너뜁니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
x1=0은 VQ=1, 즉 128비트라서 Z의 추가 부분을 지울 필요가 없습니다.
80행 그림 · 조건별 실행 위치
함수·코드 범위: sve_flush_live
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 조건이 맞는 한 경로만 실행합니다. 이 분기 명령은 NZCV를 새로 계산하지 않습니다.
sve_flush_z모든 Z 레지스터의 하위 128비트 FP/SIMD 값은 유지하고 그 위의 SVE 부분만 0으로 만듭니다. 전체 계산 상태를 버리는 것이 아니라 기본 FPSIMD에서 확장 SVE 상태로 넘어갈 때의 잔여값을 정리합니다.
81행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: sve_flush_live
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 벡터 길이가 128비트이면 지울 상위 부분이 없습니다.
sve_flush_z 매크로 본문 · 296행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sve_flush_z
_for n, 0, 31, _sve_flush_z \n
.endm1: sve_flush_pP0~P15를 모두 false로 만듭니다. predicate는 각 벡터 원소가 연산에 참여할지 정하는 마스크이므로, 이전 사용자의 predicate 상태가 확장 상태에 남지 않게 합니다. 각 predicate 레지스터에 PFALSE 명령을 적용합니다.
82행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: sve_flush_live
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
sve_flush_p 매크로 본문 · 299행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sve_flush_p
_for n, 0, 15, _sve_pfalse \n
.endm tbz x0, #0, 2fx0의 bit 0은 FFR도 정리할지 나타내는 인수입니다. 0이면 해당 작업을 생략하고, 1이면 다음 sve_flush_ffr를 실행합니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
이 함수에서는 x0의 비트 0만 FFR 초기화 여부로 검사합니다.
83행 그림 · 조건별 실행 위치
함수·코드 범위: sve_flush_live
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 조건이 맞는 한 경로만 실행합니다. 이 분기 명령은 NZCV를 새로 계산하지 않습니다.
sve_flush_ffr이미 false로 만든 P0를 FFR에 써서 first-fault 상태를 0으로 정리합니다. FFR은 fault-first load에서 어느 원소까지 유효했는지 나타내는 상태이며 일반 condition flags가 아닙니다.
84행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: sve_flush_live
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
sve_flush_ffr 매크로 본문 · 302행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sve_flush_ffr
_sve_wrffr 0
.endm2: retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
85행 그림 · 호출과 실행 위치
함수·코드 범위: sve_flush_live
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sve_flush_live)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
86행 그림 · 어셈블·링크 단계
함수·코드 범위: sve_flush_live
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
#endif /* CONFIG_ARM64_SVE */빌드 조건으로 나누었던 구간을 닫습니다. 대상:
88행 그림 · 전처리 단계
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SVE
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SME의 ZA와 ZT
#ifdef CONFIG_ARM64_SMESME는 streaming vector 실행과 2차원 행렬 누산 상태 ZA 등을 추가합니다. 이 설정을 켜면 아래 streaming 길이·ZA·선택적 ZT 저장 복원 함수를 빌드하고, 꺼지면 포함하지 않습니다. 실제 SME/SME2 사용 가능 여부와 mode 활성화는 호출자도 확인해야 합니다. 이 조건은 빌드 전처리 단계에서 포함할 코드를 고릅니다. CPU가 실행 중 전처리 조건을 검사하지는 않습니다.
90행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(sme_get_vl)이 위치부터 (sme_get_vl)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
92행 그림 · 어셈블·링크 단계
함수·코드 범위: sme_get_vl
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
_sme_rdsvl 0, 1RDSVL로 streaming vector 길이의 1배를 바이트 단위로 x0에 읽습니다. 일반 SVE VL과 SME의 SVL은 별도로 선택될 수 있으므로 sve_get_vl 대신 이 함수를 사용합니다. 매크로 인수 0은 목적 레지스터 x0의 번호이고 1은 길이에 곱할 배수입니다. 어셈블러가 이 인수로 RDSVL 인코딩을 만듭니다.
93행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: sme_get_vl
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
_sme_rdsvl 매크로 본문 · 187행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro _sme_rdsvl nx, imm
_check_general_reg \nx
_check_num (\imm), -0x20, 0x1f
.inst 0x04bf5800 \
| (\nx) \
| (((\imm) & 0x3f) << 5)
.endm retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
94행 그림 · 호출과 실행 위치
함수·코드 범위: sme_get_vl
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sme_get_vl)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
95행 그림 · 어셈블·링크 단계
함수·코드 범위: sme_get_vl
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(sme_set_vq)이 위치부터 (sme_set_vq)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
97행 그림 · 어셈블·링크 단계
함수·코드 범위: sme_set_vq
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
sme_load_vq x0, x1, x2x0의 VQ-1 인코딩을 SMCR_EL1.LEN에 반영해 streaming vector 길이를 정합니다. x1·x2는 임시 값이며 ZCR_EL1을 쓰는 일반 SVE 길이 설정과 구분합니다.
98행 그림 · 벡터·부동소수점 상태
함수·코드 범위: sme_set_vq
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 값이 같으면 쓰기를 생략할 수 있으며 작업 레지스터는 매크로 내부에서 사용됩니다.
sme_load_vq 매크로 본문 · 280행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sme_load_vq xvqminus1, xtmp, xtmp2
mrs_s \xtmp, SYS_SMCR_EL1
bic \xtmp2, \xtmp, SMCR_ELx_LEN_MASK
orr \xtmp2, \xtmp2, \xvqminus1
cmp \xtmp2, \xtmp
b.eq 921f
msr_s SYS_SMCR_EL1, \xtmp2 //self-synchronising
921:
.endm retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
99행 그림 · 호출과 실행 위치
함수·코드 범위: sme_set_vq
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sme_set_vq)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
100행 그림 · 어셈블·링크 단계
함수·코드 범위: sme_set_vq
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(sme_save_state)이 위치부터 (sme_save_state)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
108행 그림 · 어셈블·링크 단계
함수·코드 범위: sme_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
_sme_rdsvl 2, 1 // x2 = VL/8streaming vector 길이를 바이트 수로 x2에 읽습니다. ZA 한 행의 크기이자 ZA 행 개수의 기준이므로 뒤의 반복 저장에 필요합니다. 매크로 인수 2은 목적 레지스터 x2의 번호이고 1은 길이에 곱할 배수입니다. 어셈블러가 이 인수로 RDSVL 인코딩을 만듭니다.
원문 VL/8은 비트 길이를 8로 나눈 바이트 수를 뜻합니다.
109행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: sme_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
_sme_rdsvl 매크로 본문 · 187행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro _sme_rdsvl nx, imm
_check_general_reg \nx
_check_num (\imm), -0x20, 0x1f
.inst 0x04bf5800 \
| (\nx) \
| (((\imm) & 0x3f) << 5)
.endm sme_save_za 0, x2, 12 // Leaves x0 pointing to the end of ZAZA의 각 행을 x0가 가리키는 버퍼에 저장합니다. 0은 기준 x0 번호, x2는 행 크기, 12는 행 선택용 w12 번호입니다. 매 행 뒤 x0를 늘려 전체 SVL_bytes² 영역을 저장하고 끝 위치를 남깁니다.
w12로 행을 세고 행마다 x0를 x2만큼 증가시켜 ZA 전체를 저장합니다.
110행 그림 · 벡터·부동소수점 상태
함수·코드 범위: sme_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 전체의 주요 데이터 이동입니다. 버퍼 포인터와 임시 레지스터가 중간에 바뀔 수 있으므로 아래 본문에서 실제 순서를 확인합니다.
sme_save_za 매크로 본문 · 337행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sme_save_za nxbase, xvl, nw
mov w\nw, #0
423:
_sme_str_zav \nw, \nxbase
add x\nxbase, x\nxbase, \xvl
add x\nw, x\nw, #1
cmp \xvl, x\nw
bne 423b
.endm cbz x1, 1f호출자가 x1로 ZT 상태 저장 필요 여부를 전달합니다. 0이면 ZA만 저장한 뒤 반환하고, 0이 아니면 바로 뒤의 ZT 저장을 실행합니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
112행 그림 · 조건별 실행 위치
함수·코드 범위: sme_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 조건이 맞는 한 경로만 실행합니다. 이 분기 명령은 NZCV를 새로 계산하지 않습니다.
_str_zt 0현재 x0, 즉 ZA 이미지 뒤의 위치에 ZT0 상태를 저장하는 인코딩을 출력합니다. ZT0는 지원 SME 확장의 추가 상태이며 이 줄이 모든 SME CPU에서 무조건 실행된다고 가정하지 않습니다.
앞 매크로가 증가시킨 x0는 ZA 뒤의 ZT0 저장 위치입니다.
113행 그림 · 벡터·부동소수점 상태
함수·코드 범위: sme_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 전체의 주요 데이터 이동입니다. 버퍼 포인터와 임시 레지스터가 중간에 바뀔 수 있으므로 아래 본문에서 실제 순서를 확인합니다.
_str_zt 매크로 본문 · 239행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro _str_zt nx
_check_general_reg \nx
.inst 0xe13f8000 \
| (\nx << 5)
.endm1:여기에 1라는 위치 이름을 붙입니다. 다른 줄의 분기나 주소 계산이 이 위치를 찾아올 수 있습니다. 이름 자체가 CPU 작업을 추가하지는 않습니다.
114행 그림 · 위치에 이름 붙이기
함수·코드 범위: sme_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
115행 그림 · 호출과 실행 위치
함수·코드 범위: sme_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sme_save_state)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
116행 그림 · 어셈블·링크 단계
함수·코드 범위: sme_save_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(sme_load_state)이 위치부터 (sme_load_state)라는 코드가 시작한다고 도구에 알려 줍니다. 정렬과 외부 공개 여부도 정의에 포함됩니다. ARM64 함수 시작 매크로는 간접 호출의 도착점을 표시하는 BTI도 추가합니다.
124행 그림 · 어셈블·링크 단계
함수·코드 범위: sme_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
_sme_rdsvl 2, 1 // x2 = VL/8현재 streaming vector 길이를 바이트 단위로 x2에 읽어 ZA 복원 행 크기를 정합니다. 저장 버퍼의 레이아웃과 복원 시 길이가 맞아야 합니다. 매크로 인수 2은 목적 레지스터 x2의 번호이고 1은 길이에 곱할 배수입니다. 어셈블러가 이 인수로 RDSVL 인코딩을 만듭니다.
125행 그림 · 매크로 전체의 상태 변화
함수·코드 범위: sme_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
_sme_rdsvl 매크로 본문 · 187행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro _sme_rdsvl nx, imm
_check_general_reg \nx
_check_num (\imm), -0x20, 0x1f
.inst 0x04bf5800 \
| (\nx) \
| (((\imm) & 0x3f) << 5)
.endm sme_load_za 0, x2, 12 // Leaves x0 pointing to the end of ZAx0 기준 버퍼에서 ZA를 행 단위로 복원하고 x0를 ZA 이미지 끝으로 이동합니다. w12가 행 선택을 위한 임시 레지스터이며 x2가 각 행의 바이트 수입니다.
126행 그림 · 벡터·부동소수점 상태
함수·코드 범위: sme_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 전체의 주요 데이터 이동입니다. 버퍼 포인터와 임시 레지스터가 중간에 바뀔 수 있으므로 아래 본문에서 실제 순서를 확인합니다.
sme_load_za 매크로 본문 · 348행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro sme_load_za nxbase, xvl, nw
mov w\nw, #0
423:
_sme_ldr_zav \nw, \nxbase
add x\nxbase, x\nxbase, \xvl
add x\nw, x\nw, #1
cmp \xvl, x\nw
bne 423b
.endm cbz x1, 1fx1=0이면 추가 ZT 상태 복원을 생략하고, 그 외에는 저장 이미지에서 ZA 뒤의 ZT0를 읽습니다. 하드웨어 지원에 맞는 인수를 주는 것은 호출자의 책임입니다. 이 분기는 지정 레지스터의 값이나 비트를 직접 검사하며 CMP가 남긴 NZCV를 읽거나 바꾸지 않습니다. 조건이 맞지 않으면 바로 다음 명령으로 진행합니다.
128행 그림 · 조건별 실행 위치
함수·코드 범위: sme_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 조건이 맞는 한 경로만 실행합니다. 이 분기 명령은 NZCV를 새로 계산하지 않습니다.
_ldr_zt 0ZA 복원 뒤의 x0 위치에서 ZT0를 읽습니다. 첫 인수 0은 주소 상수가 아니라 x0 레지스터를 고르는 매크로 인수입니다.
129행 그림 · 벡터·부동소수점 상태
함수·코드 범위: sme_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 매크로 전체의 주요 데이터 이동입니다. 버퍼 포인터와 임시 레지스터가 중간에 바뀔 수 있으므로 아래 본문에서 실제 순서를 확인합니다.
_ldr_zt 매크로 본문 · 228행
arch/arm64/include/asm/fpsimdmacros.h · Linux v6.18.37
.macro _ldr_zt nx
_check_general_reg \nx
.inst 0xe11f8000 \
| (\nx << 5)
.endm1:여기에 1라는 위치 이름을 붙입니다. 다른 줄의 분기나 주소 계산이 이 위치를 찾아올 수 있습니다. 이름 자체가 CPU 작업을 추가하지는 않습니다.
130행 그림 · 위치에 이름 붙이기
함수·코드 범위: sme_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
retLR(x30)에 적힌 주소로 실행을 돌립니다. 그 주소가 어떻게 준비됐는지가 중요합니다. 정상 함수의 호출자일 수도 있고, 절전 복귀나 trampoline에서 별도로 기록한 재개 지점일 수도 있습니다.
131행 그림 · 호출과 실행 위치
함수·코드 범위: sme_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(sme_load_state)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
132행 그림 · 어셈블·링크 단계
함수·코드 범위: sme_load_state
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
#endif /* CONFIG_ARM64_SME */빌드 조건으로 나누었던 구간을 닫습니다. 대상:
134행 그림 · 전처리 단계
이 줄을 포함하는 조건: #ifdef CONFIG_ARM64_SME
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
설명한 뒤 함께 생각해 볼 질문
q0–q31은 총 몇 바이트인가요?
32×16=512바이트입니다. FPSR와 FPCR 필드는 그 뒤에 각각 4바이트씩 있으며 구조체의 전체 정렬 크기는 별도입니다.
fpsimd_save를 부른 뒤 x0가 그대로인가요?
마지막 쌍 저장에 writeback이 있어 상태 포인터가 바뀝니다. 인자 포인터 보존을 가정하면 안 됩니다.
SVE에서 하위 128비트를 남기는 이유는 무엇인가요?
기존 FP/SIMD 상태와 겹치는 하위 부분을 유지하면서 추가 벡터 영역을 초기화하기 위한 동작입니다.
주석을 포함한 전체 원문
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3* FP/SIMD state saving and restoring4*5* Copyright (C) 2012 ARM Ltd.6* Author: Catalin Marinas <[email protected]>7*/89#include <linux/linkage.h>1011#include <asm/assembler.h>12#include <asm/fpsimdmacros.h>1314/*15* Save the FP registers.16*17* x0 - pointer to struct fpsimd_state18*/19SYM_FUNC_START(fpsimd_save_state)20fpsimd_save x0, 821ret22SYM_FUNC_END(fpsimd_save_state)2324/*25* Load the FP registers.26*27* x0 - pointer to struct fpsimd_state28*/29SYM_FUNC_START(fpsimd_load_state)30fpsimd_restore x0, 831ret32SYM_FUNC_END(fpsimd_load_state)3334#ifdef CONFIG_ARM64_SVE3536/*37* Save the SVE state38*39* x0 - pointer to buffer for state40* x1 - pointer to storage for FPSR41* x2 - Save FFR if non-zero42*/43SYM_FUNC_START(sve_save_state)44sve_save 0, x1, x2, 345ret46SYM_FUNC_END(sve_save_state)4748/*49* Load the SVE state50*51* x0 - pointer to buffer for state52* x1 - pointer to storage for FPSR53* x2 - Restore FFR if non-zero54*/55SYM_FUNC_START(sve_load_state)56sve_load 0, x1, x2, 457ret58SYM_FUNC_END(sve_load_state)5960SYM_FUNC_START(sve_get_vl)61_sve_rdvl 0, 162ret63SYM_FUNC_END(sve_get_vl)6465SYM_FUNC_START(sve_set_vq)66sve_load_vq x0, x1, x267ret68SYM_FUNC_END(sve_set_vq)6970/*71* Zero all SVE registers but the first 128-bits of each vector72*73* VQ must already be configured by caller, any further updates of VQ74* will need to ensure that the register state remains valid.75*76* x0 = include FFR?77* x1 = VQ - 178*/79SYM_FUNC_START(sve_flush_live)80cbz x1, 1f // A VQ-1 of 0 is 128 bits so no extra Z state81sve_flush_z821: sve_flush_p83tbz x0, #0, 2f84sve_flush_ffr852: ret86SYM_FUNC_END(sve_flush_live)8788#endif /* CONFIG_ARM64_SVE */8990#ifdef CONFIG_ARM64_SME9192SYM_FUNC_START(sme_get_vl)93_sme_rdsvl 0, 194ret95SYM_FUNC_END(sme_get_vl)9697SYM_FUNC_START(sme_set_vq)98sme_load_vq x0, x1, x299ret100SYM_FUNC_END(sme_set_vq)101102/*103* Save the ZA and ZT state104*105* x0 - pointer to buffer for state106* x1 - number of ZT registers to save107*/108SYM_FUNC_START(sme_save_state)109_sme_rdsvl 2, 1 // x2 = VL/8110sme_save_za 0, x2, 12 // Leaves x0 pointing to the end of ZA111112cbz x1, 1f113_str_zt 01141:115ret116SYM_FUNC_END(sme_save_state)117118/*119* Load the ZA and ZT state120*121* x0 - pointer to buffer for state122* x1 - number of ZT registers to save123*/124SYM_FUNC_START(sme_load_state)125_sme_rdsvl 2, 1 // x2 = VL/8126sme_load_za 0, x2, 12 // Leaves x0 pointing to the end of ZA127128cbz x1, 1f129_ldr_zt 01301:131ret132SYM_FUNC_END(sme_load_state)133134#endif /* CONFIG_ARM64_SME */

