Linux Kernel Module Parameters
1. Module Parameter가 왜 필요한가요?
이전 글에서 만든 Hello 모듈은 동작이 고정되어 있었습니다.
인사 횟수를 바꾸거나 이름을 바꾸려면 코드를 수정하고 다시 빌드해야 했죠.
실제 드라이버에서는 이런 상황이 자주 생깁니다.
- GPIO 핀 번호를 하드코딩하지 않고 로드 시 지정하고 싶다.
- 디버그 로그를 켜고 끄고 싶다
- 디바이스 개수나 버퍼 크기를 유연하게 조정하고 싶다
이럴 때 Module Parameter를 씁니다.
# 파라미터 없이 로드 - 기본값 사용
sudo insmode params.ko
# 파라미터 지정해서 로드
sudo insmode params.ko count=3 name="Hoon" debug=1
코드 수정 없이 동작을 바꿀 수 있습니다.
2. module_param() 기본 문법
module_param(변수명, 타입, 권한);
세 가지만 기억하면 됩니다.
/* ① 변수 선언 — 기본값도 여기서 설정 */
static int count = 1;
static char *name = "OnePaperHoon";
static bool debug = false;
/* ② module_param()으로 외부에 노출 */
module_param(count, int, 0644);
module_param(name, charp, 0644);
module_param(debug, bool, 0644);
변수를 먼저 선언하고 기본값을 설정한 뒤,`module_param()`으로 커널에 등록하는 구조입니다.
`insmod`시 파라미터를 넘기지 않으면 선언 시의 기본값이 그대로 사용됩니다.
3. 파라미터 타입 종류
`module_param()`의 두 번째 인자로 쓸 수 있는 타입들입니다.
| 타입 | C 변수 타입 | 설명 |
| int | int | 정수 |
| long | long | 긴 정수 |
| short | short | 짧은 정수 |
| uint | unsigned int | 부호 없는 정수 |
| ulong | unsigned long | 부호 없는 긴 정수 |
| bool | bool | true / false (1 / 0) |
| charp | char * | 문자열 포인터 |
이 코드에서 쓴 타입은 세 가지입니다.
static int count = 1; /* int — 정수 */
static char *name = "..."; /* charp — 문자열 */
static bool debug = false; /* bool — true/false */
문자열은 `char`가 아니라 반드시 `charp`를 씁니다. `char`로 쓰면 컴파일 에러가 납니다.
4. 권한 (Permission) 설정
`module_param()`의 세 번쨰 인자는 sysfs에서의 접근 권한입니다. Linux 파일 권한과 동일한 8진수 표기법을 씁니다.
module_param(count, int, 0644);
/* ↑
* 0 = 특수 권한 없음
* 6 = owner: read(4) + write(2)
* 4 = group: read(4)
* 4 = other: read(4)
*/
| 권한값 | sysfs 노출 | 읽기 | 쓰기 | 용도 |
| `0000` | 노출 안 됨 | - | - | 로드 시에만 설정 가능 |
| `0444` | 노출 | 가능 | 불가 | 읽기 전용 파라미터 |
| `0644` | 노출 | 가능 | 가능 | 런타임 변경 가능 |
이 코드는 세 파라미터 모두 `0644`로 설정했습니다. 즉 모듈 로드 후에도 sysfs를 통해 값을 읽고 쓸 수 있습니다.
커널 코드에서 권한값을 쓸 때는 `S_IRUGO`,`S_IWUSR` 같은 매크로를 쓰는 것이 더 명확합니다.
`S_IRUGO`는 모든 사용자 읽기 허용, `S_IWUSR`은 owner 쓰기 허용입니다.
`0644`는 `S_IRUGO | S_IWUSR`과 동일합니다.
5. MODULE_PARM_DESC()
파라미터에 설명을 붙입니다.
MODULE_PARM_DESC(count, "Number of greetings (default=1)");
MODULE_PARM_DESC(name, "Name to greet (default=OnePaperHoon)");
MODULE_PARM_DESC(debug, "Enable debug mode (default=false)");
이렇게 해두면 `modinfo` 명령으로 파라미터 설명을 볼 수 있습니다.
$ modinfo params.ko
filename: params.ko
description: Kernel Module with Parameters - Week 5 Day 2
author: OnePaperHoon
license: GPL
version: 1.0
parm: count:Number of greetings (default=1) (int)
parm: name:Name to greet (default=OnePaperHoon) (charp)
parm: debug:Enable debug mode (default=false) (bool)
협업하거나 나중에 다시 볼 때 `modinfo` 한 방으로 파라미터 목록과 의미를 확인할 수 있어서 반드시 작성하는 습관을 들이는 게 좋습니다.
6. sysfs를 통한 런타임 변경
`0644` 권한으로 등록한 파라미터는 모듈 로드 후에도 stsfs를 통해 값을 바꿀 수 있습니다.
# 파라미터 위치
/sys/module/<모듈명>/parameters/<파라미터명>
# 현재 값 읽기
$ cat /sys/module/params/parameters/count
1
# 런타임에 값 변경
$ echo 5 | sudo tee /sys/module/params/parameters/count
5
# 변경 확인
$ cat /sys/module/params/parameters/count
5
단, sysfs로 값을 바꿔도 이미 실행된 Init 함수는 다시 실행되지 않습니다.
런타임 변경이 의미 있으려면 모듈 내부 로직이 파라미터 변수를 주기적으로 참조하거나, 변경 시 콜백을 처리하는 구조여야 합니다.
7. 실습 - Raspberry Pi에서 직접 확인하기
파일 구성
params_module/
├── params.c
└── Makefile
Makefile
# Week 5 Day 2: Module Parameters
# Makefile for params module
obj-m := params.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
@echo "========================================="
@echo "Building params.ko kernel module..."
@echo "========================================="
$(MAKE) -C $(KDIR) M=$(PWD) modules
@echo ""
@echo "Build complete! Generated files:"
@ls -lh params.ko 2>/dev/null || echo "Build failed!"
clean:
@echo "Cleaning build files..."
$(MAKE) -C $(KDIR) M=$(PWD) clean
@echo "Clean complete!"
# 파라미터 없이 로드
load:
@echo "========================================="
@echo "Loading module (default parameters)..."
@echo "========================================="
sudo insmod params.ko
@echo ""
@echo "Kernel log:"
dmesg | tail -15
# 파라미터와 함께 로드
load-custom:
@echo "========================================="
@echo "Loading module with custom parameters..."
@echo "========================================="
sudo insmod params.ko count=3 name="Hoon" debug=true
@echo ""
@echo "Kernel log:"
dmesg | tail -15
# 언로드
unload:
@echo "========================================="
@echo "Unloading module..."
@echo "========================================="
sudo rmmod params
@echo ""
@echo "Kernel log:"
dmesg | tail -10
# 모듈 정보
info:
@echo "========================================="
@echo "Module Information:"
@echo "========================================="
modinfo params.ko
# /sys 확인
sysfs:
@echo "========================================="
@echo "Module parameters in /sys:"
@echo "========================================="
@ls -la /sys/module/params/parameters/ 2>/dev/null || echo "Module not loaded"
@echo ""
@echo "Parameter values:"
@cat /sys/module/params/parameters/* 2>/dev/null || echo "Module not loaded"
# 파라미터 런타임 변경
change-param:
@echo "========================================="
@echo "Changing parameters at runtime..."
@echo "========================================="
@echo "Before:"
@cat /sys/module/params/parameters/count
@echo ""
@echo "Changing count to 5..."
@echo 5 | sudo tee /sys/module/params/parameters/count
@echo ""
@echo "After:"
@cat /sys/module/params/parameters/count
help:
@echo "Available targets:"
@echo " make - Build module"
@echo " make clean - Clean build files"
@echo " make load - Load with default params"
@echo " make load-custom - Load with custom params"
@echo " make unload - Unload module"
@echo " make info - Show module info"
@echo " make sysfs - Check /sys parameters"
@echo " make change-param - Change parameter at runtime"
.PHONY: all clean load load-custom unload info sysfs change-param help
| 명령어 | 동작 |
| `make` | 모듈 빌드 -> `params.ko` 생성 |
| `make load` | 기본 파라미터로 로드 |
| `make load-custom` | `const=3 name="Hoon" debug=true`로 로드 |
| `make unload` | 모듈 언로드 |
| `make info` | `modinfo`로 파라미터 목록 확인 |
| `make sysfs` | `/sys`경로에서 현재 파라미터 값 확인 |
| `make change-param` | 런타임에 `count`를 5로 변경 |
| `make clean` | 빌드 파일 정리 |
params.c 전체
/*
*
* params.c - Kernel Module with Parameters
* Week 5 Day 2: Module Parameters
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
/*
* 모듈 파라미터 선언
*/
static int count = 1;
static char *name = "OnepaperHoon";
static bool debug = false;
/*
* module_param(변수명, 타입, 권한)
* 권한:
* 0000 - /sys에 나타나지 않음
* 0444 - 읽기 전용
* 0644 - 읽기 / 쓰기
*/
module_param(count, int, 0644);
MODULE_PARM_DESC(count, "Number of greetings (default=1)");
module_param(name, charp, 0644);
MODULE_PARM_DESC(name, "Name to greet (default=OnePaperGoon)");
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Enable debug mode (default=false)");
/*
* 모듈 초기화
*/
static int __init params_init(void) {
int i;
printk(KERN_INFO "=======================================\n");
printk(KERN_INFO "Module Parameters Demo\n");
printk(KERN_INFO "=======================================\n");
if (debug) {
printk(KERN_DEBUG "[DEBUG] Module loaded with:\n");
printk(KERN_DEBUG " count = %d\n", count);
printk(KERN_DEBUG " name = %s\n", name);
printk(KERN_DEBUG " debug = %s\n", debug ? "true" : "false");
}
// count만큼 인사 출력
for (i = 0; i < count; i++) {
printk(KERN_INFO "Hello, %s", name);
}
printk("====================================\n");
return 0;
}
static void __exit params_exit(void) {
printk(KERN_INFO "======================================\n");
printk(KERN_INFO "GoodBye, %s!\n", name);
printk(KERN_INFO "Module unloaded\n");
printk(KERN_INFO "======================================\n");
}
module_init(params_init);
module_exit(params_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("OnePaperHoon");
MODULE_DESCRIPTION("Kernel Module with Parameters - Week 5 Day 2");
MODULE_VERSION("1.0");
빌드 및 실행
$ make
=========================================
Building params.ko kernel module...
=========================================
make -C /lib/modules/6.1.21+/build M=/home/pi/params modules
CC [M] params.o
LD [M] params.ko
Build complete! Generated files:
-rw-r--r-- 1 pi pi 7.2K params.ko
$ make load-custom
=========================================
Loading module with custom parameters...
=========================================
sudo insmod params.ko count=3 name="Hoon" debug=true
Kernel log:
[DEBUG] count = 3
[DEBUG] name = Hoon
[DEBUG] debug = true
Hello, Hoon!
Hello, Hoon!
Hello, Hoon!
$ make sysfs
=========================================
Module parameters in /sys:
=========================================
-rw-r--r-- 1 root root 4096 /sys/module/params/parameters/count
-rw-r--r-- 1 root root 4096 /sys/module/params/parameters/debug
-rw-r--r-- 1 root root 4096 /sys/module/params/parameters/name
Parameter values:
3
true
Hoon
8. 마치며
Module Parameter는 드라이버를 유연하게 만드는 핵심 도구입니다.
`module_param(변수, 타입, 권한)`으로 파라미터를 등록한다.
`MODULE_PARM_DESC()`로 설명을 반드시 붙인다.
`0644` 권한이면 sysfs로 런타임 변경도 가능하다.
실제 드라이버 코드를 보면 GPIO 핀 번호, 디바이스 주소, 디버그 레벨 같은 값들이 대부분 `module_param()`으로 노출되어 있습니다.
이제 그 코드가 낯설지 않을 겁니다.
다음 글에서는 `/proc`파일 시스템을 통해 커널 내부 정보를 유저 스페이스에서 읽는 방법을 다룰 예정입니다.
참고 자료
- Linux Kernel Documentation: `Documetation/driver-api/basics.rst`
- `linux/moduleparam.h` 커널 소스
- `modinfo`,`sysfs` man page