리눅스는 모놀리틱 커널로서 모듈 독립적이지 않고 한 개 수정하면 전체를 재 build 해야 하는 system이다.
다음은 insmod / rmmod 하는 과정이다.
| pic1 |
insmod / rmmod는 user app인데실행시에는 ko를 user 영역에 copy를한후 kernel 영역에넣는다.
mknod: 장치 driver에 접근하기 위해서 VFS에 node
--> /dev/SK dentry를 찾아서 inode를 만든다. 이 때는 file가 만들어지지 않았기 때문에 &def_cur_fops를 가리키고 있다. 이 때 open()을 하면, files에 비어있는 fd[3]에 객체를 만들면서 f_dentry, f_op 등을 매핑한다. 그런 후에 device reg 할 때 넣은 &SK_fops를 불러다가 open을 하게 됨!! 그 이후에는 직접 SK_open()으로 간다!
/proc/devices에서 정보를 확인할 수 있다.
device module이란?
--> device들을 character device로 등록하자니.. 많아지니깐 관리가 힘들어짐.
--> 그래서 VFS(Virtual File System)가 만들어짐. charicter device / block device / network device를 접근할 수 있음.
--> 장치 유형은 다음과 같다.
- Blkdevs, 블록 장치 - HDD
- Cdevs, 캐릭터 장치 - 키보드, 마우스
- Network devices, 네트워크 장치 - 이더넷 장치
hello world device driver:
static int hello_init(void)
{
pr_info("Hello world!");
return 0;
}
static void hello_exit(void)
{
pr_info("Goodbye world!");
}
module_init(hello_init); //시작지점 hello_init 등록
module_exit(hello_exit); //모듈이 메모리에서 제거될 때 호출
MODULE_LICENSE("GPL");
MODULE_AUTHOR("author");
MODULE_DESCRIPTION("Hello world, module");
모듈 만들기 - Makefile에 추가
모듈 설치
- 위치: /lib/module/버전/kerne/drivers/xxxx/helloworld.ko
- # make modules_install //설치
모듈 의존성 생성
- # depmod -A
- /lib/module/버전/modules.dep //모듈 의존성 정보
모듈 적재
- # insmod helloworld.ko //모듈을 메모리에 추가
- # rmmod helloworld //삭제
- # modprobe helloworld [모듈인자] //해당 모듈이 필요로 하는 다른 모듈도 설치
- # modprobe -r helloworld //삭제
설정 옵션 관리 - Kconfig
모듈 인자
- module_param(name, type, perm); //이름, 형, 권한
- module_param_named(name, variable, type, perm); //외부 노출 이름, 내부 변수, 형, 권한
- module_param_string(name, string, len, perm); //이름, 내부 변수(string은 문자열임), 형, 권한
- module_param_array(name, type, nump, perm); //이름, 형, 배열에 저장할 항목 개수, 권한
- moduel_param_array_named(name, array, type, nump, perm);
- MODULE_PARM_DESC(): 설명 추가
- <linux/module.h>에 위 함수에 대한 설명 있음
노출 심볼
- EXPORT_SYMBOL()
- EXPORT_SYMBOL_GPL() //EXPORT_LICENSE("GPL")만
- 장치 모델
- <linux/kobject.h> kobjects(kernel object type)
- <linux/kobject.h> struct kobject
- <linux/cdev.h> struct cdev에 struct kobject가 들어가면 kobject가 제공하는 표준 함수를 쓸 수 있음.
- Struct ktype: kobject의 기본 속성을 정의함. 소멸 동작, sysfs 동작 등 기본 동작, 쉽게는 공유 동작의 집합임.
- Struct kset:
- 묶여있는 kobject는 한 묶음의 기본 클래스로 동작함
- 연관이 있는 kobject를 모아줌
- Struct kobject * kobject_create(void);
|
- 참조 횟수 증감
- struct kobject *kobject_get(struct kobject *kobj);
- void kobject_put(struct kobject *kobj);
- 확인은
의 kref_get() 사용 - Sysfs에 추가/제거
- int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...); //추가
- void kobject_del(struct kobject *kobj); //제거
- /proc에 파일 만드는 법 -insmod하면 /proc에 파일을 하나 만드는거다!
- create_proc_entry() / remove_proc_entry() 이용하면 됨.
- 예제 /06.FileSystem/03.proc_my 확인할 것
- /sys (참고)
- 2.6 이전에는 /sys (systfs)가 없었음. 디바이스 모델과 함께 추가된 것이라고 생각하면 됨.
- /sys는 그렇지 않지만 /proc은 맘대로 만들어도 된다.
- /sys/class는 논리적인 장치
- /sys/bus에 device들이 붙어있음.
- 덧
- module_init() 주소 보다 module_exit()가 낮은 주소값을 가지고 있다.
- 웃긴건 /proc/modules에 나오는 주소가 module_exit()와 동일한 주소를 가지고 있다. 즉 module_exit가 함수들 처음이고 이 모듈의 첫 주소랑 동일하다고 보면 된다.
- kernel 시작 주소는 #define TASK_SIZE 0xBF000000로 설정 가능함.
- application이 open()을 호출하면,
- 'swi5' system call 하여 kernel mode(svc)로 변경됨. sys_open()을 호출함.
- sys_open()이 inode의 file_operations의 i_rdev에서 major/minor 정보를 확인함
- struct file 생성한 후 위에 로드한 file_operations를 멤버에 load함.
- .open = mydrv_open()을 호출함.
- 앱의 fd = open()의 open()은 mydrv_open()의 return이 아닌 sys_open()의 return 값임. 즉 file의 pointer 값임.
- read()를 호출하면
- 바로 file_operations에 접근할 수 있음.
- close()를 호출하면
- 'swi6' system call 하여 kernel mode(svc)로 변경
- sys_close() 호출
- mydrv_close() 호출
- file_operations 삭제
- LDM에 대해서…
- 목적: PnP/Power 통합관리
- 내부 구조: 객체(kobj), sysfs node 생성.
- 구현 방법: (TBC)
- 모든 드라이버에는 kobj를 등록해야 한다.
- 윈도우의 WDM을 따라했음
- 장치파일/디바이스 네임/모듈 네임
- 장치파일: mknod 명령으로 생성, 응용프로그램이 사용
- 디바이스 네임:
- # cat /proc/devices 실행시 출력
- 드라이버소스에서 설정하여 커널에 등록
- 모듈네임:
- lsmod 실행시 출력
- 드라이버 소스 빌드시 결정
- /dev 폴더에 대해서..
- Android는 부팅 전에는 /dev가 없다. init process 하면서 device 들을 확인하여 하나씩 넣는다.
- desktop은 kernel 부팅시 /dev가 만들어짐. package에서 동적으로 만들어줌.
댓글 없음:
댓글 쓰기