- 모듈: 커널 관련 하위 함수, 데이터, 바이너리 이미지를 포함해 동적으로 불러 올 수 있는 커널 객체를 의미한다.
- 장치: 리눅스 커널은 장치를 블록 장치, 캐릭터 장치, 네트워크 장치 3가지로 분류한다. 모든 장치 드라이버가 물리장치를 표현하는 것은 아니며 커널 난수 생성기, 메모리 장치처럼 가상 장치도 표현한다.
-
모듈 개발은 새로운 프로그램을 짜는 것과 비슷하다.
-
각 모듈은 소스파일 내에 자신의 시작위치(
module_init()
)와 종료위치(module_exit()
)가 있다. -
아래는
‘hello, world’
를 출력하는 간단한 모듈의 코드이다.#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> static int hello_init(void) { printk(KERN_ALERT, "hello\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT, "world\n"); } module_init(hello_init); // 모듈 진입점 module_exit(hello_exit); // 모듈 종료점 MODULE_LICENSE("GPL"); // 저작권 정보 MODULE_AUTHOR("Embeddedjune"); // 모듈 제작자 정보 MODULE_DESCRIPTION("Test Hello,world"); // 모듈에 대한 정보
- 모듈 작성을 완료했다면, 모듈 소스를 패치의 형태나 커널 소스 트리에 병합한다.
- 모듈은
/drivers
의 적당한 장치 하위 디렉토리에 디렉토리를 만들고 넣는다. /drivers
의 Makefile과 방금 만든 하위 디렉토리 안의 Makefile을 수정한다.- make 명령어로 모듈을 컴파일한다.
make modules_install
명령을 이용해서 모듈을 설치한다.
depmod
명령어를 이용해서 의존성 정보를 반드시 생성한다.
insmod
로 모듈을 메모리에 추가하고 rmmod로 모듈을 제거한다.modprobe
도구는 의존성 해소, 오류 검사 및 보고 등의 고급 기능들을 제공하므로 사용을 적극 권장한다.
- 리눅스 커널 2.6 버전의 중요한 새 기능으로 ‘장치 모델(Device model)’이 추가됐다.
- 장치 모델이 추가된 이유는 ‘전원 관리(Power management) 기능 운용’을 위한 정확한 장치 트리(Device tree, 시스템의 장치 구조를 표현하는 트리)를 제공하기 위해서다.
- 플래시 드라이브가 어느 컨트롤러에 연결됐는지, 어느 장치가 어느 버스에 연결됐는지 정보를 알려주고, 커널이 전원을 차단할 때 트리의 하위 노드 장치부터 전원을 차단할 수 있도록 도와준다.
- 이러한 일련의 서비스를 정확하고 효율적으로 제공하기 위해 장치 트리 및 장치 모델이 필요하다.
- 장치 모델은
kobjects
,ksets
,ktypes
세 가지 구조체로 표현한다. (모든 구조체는<linux/kobject.h>
에 정의되어있다.)
// https://github.com/torvalds/linux/blob/f2e8a57ee9036c7d5443382b6c3c09b51a92ec7e/include/linux/kobject.h#L64
// 커널 자료구조의 기본적인 객체 속성 제공, sysfs 상의 디렉토리와 같음
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
const struct kobj_type *ktype;
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref;
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
};
...
// https://github.com/torvalds/linux/blob/f2e8a57ee9036c7d5443382b6c3c09b51a92ec7e/include/linux/kobject.h#L168C1-L173C22
// 기능상 관련된 kobject의 집합(연결리스트)
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
} __randomize_layout;
...
// https://github.com/torvalds/linux/blob/f2e8a57ee9036c7d5443382b6c3c09b51a92ec7e/include/linux/kobject.h#L116C1-L123C3
// 공동 동작을 공유하는 kobject의 집합(연결리스트)
struct kobj_type {
void (*release)(struct kobject *kobj); // `kobjects`의 참조횟수가 0이 될 때 호출되서 C++의 소멸자 역할을 한다.
const struct sysfs_ops *sysfs_ops;
const struct attribute_group **default_groups;
const struct kobj_ns_type_operations *(*child_ns_type)(const struct kobject *kobj);
const void *(*namespace)(const struct kobject *kobj);
void (*get_ownership)(const struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};
...
kobjects
구조체는 부모 객체를 멤버 포인터 객체로 가지므로 계층 구조를 가지고 있다.kobjects
를 사용하기 위해서는kobject_create()
함수를 사용한다.
- sysfs은 kobject 계층 구조를 보여주는 가상 파일시스템이다.
- sysfs는 가상 파일을 통해 다양한 커널 하위 시스템의 장치 드라이버에 대한 정보를 제공한다.
- 리눅스 2.6 커널 이상을 이용하는 모든 시스템은 sysfs를 포함하며
/sys
디렉토리에 마운트되어있다. - sysfs에는 block, bus, class, dev, devices, firmware, fs, kernel, module, power 등 최소 10개 디렉토리가 포함되어있다.
- 이 디렉토리들 중 가장 중요한 두 디렉토리는 class와 devices 디렉토리다.
- class는 시스템 장치의 상위 개념을 정리된 형태로 보여주고,
- devices는 시스템 장치의 하위 물리적 장치 연결 정보 관계를 보여준다.
- 나머지 디렉토리는 devices의 데이터를 단순히 재구성한 것에 불과하다.
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent);
void kobject_del(struct kobject *kobj);
kobject_create_and_add()
는kobject_create()
함수와kobject_add()
함수를 하나로 합친 함수다.- kobject 객체를 생성하고 sysfs에 추가한다.
- kobject 객체를 제거할 때는
kobject_del()
함수를 사용한다.
- kobject를 sysfs 계층구조에 추가해도 kobject가 가리키는 ‘파일’이 없다면 아무 의미가 없다.
- kobjects 구조체 속 ktypes 구조체는 아무런 인자가 없어도 기본적인 파일 속성을 제공한다.
default_attrs
: 이 변수를 설정해서 파일의 이름, 소유자, 속성(쓰기, 읽기, 실행)을 부여한다.sysfs_ops
: 파일의 기본적인 동작(읽기(show), 쓰기(store))을 정의한다.
- 속성을 제거하기 위해서는
sysfs_remove_file()
함수를 이용한다.
참고