
이번주는 커널 프로그래밍을 공부하였습니다.
커널은 자원을 관리하고 API를 제공하는 역할을 하는 프로그램 입니다.
직접 뭔가를 하기보다는 응용프로그램(어플리케이션)이 잘 돌아갈 수 있도록 도와준다고 보면 될 듯 합니다.
커널은 하나로 크게 만들어지기도 하지만, 모듈을 탑재하는 경우도 많습니다. 커널을 모듈화하면 커널을 빌드하는 시간을 줄일 수도 있고, 특정 모듈을 업데이트할 때도 커널 전체를 빌드하는 것이 아닌, 모듈만 바꿔 탑재하면 되기 때문에 유지 보수에서도 훨씬 편리하다는 장점이 존재합니다.
$ cd /lib/moduels/$(uname -r)
$ cat modules.dep | more
kernel/arch/arm64/crypto/sha512-ce.ko.xz: kernel/arch/arm64/crypto/sha512-arm64.ko.xz
kernel/arch/arm64/crypto/sha3-ce.ko.xz: kernel/crypto/sha3_generic.ko.xz
kernel/arch/arm64/crypto/sm3-ce.ko.xz: kernel/crypto/sm3.ko.xz
이렇게 우리는 현재 커널에 탑재되어있는 모듈을 확인할 수 있습니다. xz는 압축되어있다는 것을 의미하며, ko는 커널 오브젝트입니다. c언어에서 목적파일 .o 파일과 비슷하다고 볼 수 있습니다.
lsmod 라는 명령어를 통해 현재 탑재된 모듈을 확인할 수도 있습니다.
커널 모듈을 올리거나 내리기 위해서는 sudo modprobe <모듈명> 명령어를 사용할 수 있습니다. 내릴 때는 sudo modprobe -r <모듈명> 입니다.
혹은, 현재 폴더 위치에 있는 커널을 올리고 내린다면, sudo insmod <모듈명>, sudo rmmod <모듈명>을 입력하면 됩니다.
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static int __init hello_init(void)
{
printk(KERN_NOTICE "Hello, World#2\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_NOTICE "Goodbye\n");
}
module_init(hello_init);
module_exit(hello_exit);
우선, 모듈 프로그래밍을 하기 위해서 사용되는 헤더는 모두 linux 에 위치합니다.
또한, __init과 __exit을 적어준 뒤, module_init(), module_exit() 을 통해 등록을 해 주어야 합니다.
obj-m := hello_module.o
KDIR := /usr/src/linux
default:
make ARCH=arm64 CROSS_COMPILE=aarch64=linux-gnu- -C$(KDIR) M=$(shell pwd) modules
clean:
make -C$(KDIR) M=$(shell pwd) clean
위와 같은 Makefile을 통해 빌드할 수 있습니다.
이렇게 만들어진 커널 프로그램은 .ko 파일로 생성되며, 이 파일만 주고받음으로써 커널 모듈을 사용할 수 있게 됩니다.
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
이 함수를 통해 장치 번호를 할당받을 수 있습니다. 하드 코딩으로 장치 번호를 사용할 수도 있지만, 그렇게 하면 다른 장치와 번호가 겹칠 수 있기 때문에 지양합니다.
void cdev_init(struct cdev *cdev, const struct file_operations *fops);
이 함수는 캐릭터 장치를 초기화하는 함수입니다. 디바이스 드라이버를 만들 때는 open(), close(), read() 등을 사용할 때 어떤 일을 해야 하는지 기술할 수 있는데 이 때 만들어진 함수들은 file_operations구조체에 저장하게 됩니다. 이 구조체에는 각 함수들을 넣을 수 있는 함수 포인터를 받습니다.
cdev와 이 file_operations 를 연결하는 함수라고 볼 수 있습니다.
int cdev_add(struct cdev *cdev, dev_t dev, unsigned int count);
이제 위에서 할당받은 메이저/마이너 번호를 연결해줍니다.
이렇게 하면 대략적인 커널 드라이버를 생성할 수 있게 됩니다.
여기까지는 init에 넣어 해당 모듈을 커널에 탑재할 때 일어날 수 있게 합니다.
void cdev_del(struct cdev *cdev);
void unregister_chrdev_region(dev_t dev, unsigned int count);
init에서 한 행동의 역순으로 exit에서 해 줍니다. 이것은 커널에서 모듈이 해제될 때 호출됩니다.
| [한화비전 VEDA 4기] 14주차 리뷰 (0) | 2026.06.28 |
|---|---|
| [한화비전 VEDA 4기] 13주차 리뷰 (0) | 2026.06.22 |
| [한화비전 VEDA 4기] 11주차 리뷰 (0) | 2026.06.07 |
| [한화비전 VEDA] 10주차 리뷰 (0) | 2026.05.31 |
| [한화비전 VEDA 4기] 9주차 리뷰 (0) | 2026.05.24 |
댓글 영역