오늘은 리눅스 커널에서 시스템 콜 함수를 등록하고 호출하는 실습을 진행할 것이다.
1. 시스템 콜 함수 작성
아래와 같은 간단한 시스템 콜 함수를 생성한다.
인자가 하나인 경우의 함수인데, SYSCALL_DEFINE$ <- $가 1이면, 인자가 1개라는 뜻이다.

시스템 콜 함수 코드를 저장할 위치는 다음과 같다.
/linux/kernel/시스템콜_코드.c
2. 시스템 콜 함수 추가 시 Makefile 수정 필요
파일이 추가된 디렉터리의 Makefile을 열어 아래와 같이 추가

obj-y 변수에 추가된 항목만 커널 바이너리에 포함되게 된다.
3. 시스템 콜 함수 매크로 등록
시스템 콜 함수를 정의하기 위한 매크로를 등록해주어야 한다.
/include/uapi/asm-generic/unistd.h
위 파일을 vim으로 열어서 __NR_syscalls 라인을 찾는다.
새 시스템 콜 추가 시, __NR_syscalls 정의 앞에 하는 것이 일반적이다. __NR_syscalls는 시스템 콜의 개수를 가리키므로 1 증가시켜주어야 한다.

원래 __NR_syscalls는 468이었지만, 새 시스템 콜을 추가함으로써 +1이 되어 469가 된 것이다.
이렇게 등록 후, 저장한다.
4. 시스템 콜 호출 코드
이제 시스템 콜 함수를 등록할 유저 코드를 작성해주어야 한다.
이 코드는 어디든 작성해도 관계없다.
#include <stdio.h>
#include <unistd.h>
#define __NR_new_syscall 468
int main(){
int result = syscall(__NR_new_syscall, 10);
printf("result: %d\n", result);
return 0;
}
이제 이 코드를 일반 gcc가 아닌 툴체인을 사용하여 빌드하여야 한다.
<툴체인 디렉터리>/bin/aarch64-none-linux-gnu-gcc -o hell hell.c
5. 커널 빌드
시스템 콜을 새로 추가하였으니 이를 커널에 반영해주어야 한다.
# 커널 소스 최상위로 이동
cd ~/workspace/kernel/linux
#(선택) 깨끗한 상태 확보
make mrproper
# 크로스 컴파일 환경 변수 설정
export ARCH=arm64
export CROSS_COMPILE=/home/jiwan/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
# 기본 설정 생성(예: defconfig) 후 빌드
make defconfig
make -j$(nproc) # 혹은 make -j8
6. 새 시스템 콜 실행
빌드한 프로그램을 rootfs의 /usr/bin에 복사해야 한다.
sudo mount -o loop <빌드루트 디렉터리>/output/images/rootfs.ext4 /mnt
sudo cp hell /mnt/usr/bin/
sync
sudo umount /mnt
이제 여기까지 완료되면 QEMU를 실행하면 된다.
7. QEMU로 빌드된 커널 실행
QEMU 실행은 shell script를 작성하여 딸깍하면 실행할 수 있게 설정해두었다.

이후 실행하게 되면 아래와 같이 나온다.
하지만, hell을 실행하게 되면 아래와 같이 오류가 발생하게 된다.

8. 오류 해결
커널 버전 6.11 이상부터는 시스템 콜의 번호를 시스템 콜 테이블에 추가를 해주어야 한다.
arch/arm64/tools/syscall_64.tbl 파일에 시스템콜을 추가하였다.
새로 작성한 시스템 콜 번호를 시스템 콜 테이블에 추가 후, 커널 빌드를 다시 진행하여야 한다.
5번 과정을 다시 수행하면 된다.
빌드 후 프로그램을 실행하게 되면 아래와 같이 수행된다.

커널 버전에 따라 시스템 콜을 등록하는 방식이 다르니 참고하기 바란다.