O`reilly 에서 나온 LDD(Linux Device Driver) Third Edition 을 가지고 공부한 내용을 정리했다.

Hello World 모듈 작성

#include <linux/init.h>           ------ 1
#include <linux/module.h>         ------ 1
MODULE_LICENSE("Dual BSD/GPL");   ------ 2
 
static int hello_init(void)
{
 	printk(KERN_ALERT "Hello, world\n");    ------ 5
	return 0;
}
 
static void hello_exit(void)
{
	printk(KERN_ALERT "Goodbye, network world\n");
}
 
module_init(hello_init);          ------ 3
module_exit(hello_exit);          ------ 4
번호 설명
1 Driver 를 작성할 때, 항상 include 해야한다
2 해당 모듈이 오픈소스 라이선스를 따른다는 사실을 커널에게 알린다. 명시하지 않을 경우, 이후 모듈 로딩 시 오류가 발생하면서 로딩이 안될 수 있다
3 모듈 초기화시에 실행할 함수를 선언한다
4 모듈 해제시에 실행할 함수를 선언한다
5 커널은 Standard C 라이브러리를 사용하지 않기 때문에, 커널에서 구현한 별도의 함수인 printk 를 사용한다. KERN_ALERT 는 커널 메세지의 중요도를 나타낸다
ifneq ($(KERNELRELEASE),)
  	obj-m := hello.o     ------ 6
	module-objs := hello.o    ------ 7
else
 	KERNELDIR ?= /lib/modules/$(shell uname -r)/build     ------ 8
 	PWD := $(shell pwd)                                   ------ 9
 
default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules              ------ 10
endif
번호 설명
6 모듈로 만들 타겟 오브젝트 파일 지정
7 타겟 오브젝트 파일을 만들 때 필요한 소스 파일 지정
8 커널 소스 트리 경로 지정
9 모듈 타겟 오브젝트을 빌드하기 전에 makefile 이 모듈 소스 디렉토리로 돌아올 경로 지정
10 커널 소스 트리의 최상위 makefile 을 찾고, 모듈 디렉토리로 돌아와 빌드한다

빌드 및 모듈 적재와 제거

root 권한에서 실행한다.

#make 
#insmod hello.ko
#rmmod hello
#lsmod

메모리는 물리적으로 1개 혹은 하나의 종류지만, S/W 입장에서 메모리는 여러 부분으로 나뉜다. 그중에 대표적으로 커널 메모리 영역과 사용자 메모리 영역으로 나눌 수 있다.
커널 메모리 영역은 커널 그리고 드라이버 모듈이 실행되는 곳이고, 사용자 메모리 영역에 비해 상대적으로 사이즈가 작다. 사용자 메모리 영역은 사용자 프로그램이 실행된다.
사용자 프로그램이 수행 도중 시스템 콜(소프트웨어 인터럽트)이나 하드웨어 인터럽트가 발생하면, 커널 메모리 영역으로 실행된다. 인터럽트 핸들러 루틴이 끝나면 다시 사용자 메모리 영역으로 돌아와 실행한다.

비동기적인 인터럽트에 의해 둘 이상의 사용자 프로그램이 특정 드라이버를 참조할 수 있기 때문에, 드라이버 코드는 재진입이 가능해야 한다.
'__' 로 시작하는 커널 함수는 인터페이스 중에서도 낮은 단계에 속하며, 사용시 주의를 요한다.

insmod 모듈 코드와 데이터를 커널에 적재한다. 이때 모듈에서 미결정 심볼(unresolved symbols)을 커널 심볼 데이블로 링크시킨다
modprobe 커널에서 결정하지 못한 심볼이 다른 모듈에 있는지 찾는다. 찾으면, 이에 필요한 모듈을 찾아 함께 커널에 적재한다

링크한 커널 버전이 바뀔 때마다 모듈을 재빌드해야 한다. 이는 빌드 과정에서 커널 버전, 컴파일러 버전, 중요한 환경변수 설정(프로세서 환경 설정)을 포함하는 vermagic.o 파일을 링크한다.
이후 모듈을 적재할 때, 이 정보를 확인하여 일치하지 않으면, 아래와 같은 에러가 발생하면서 적재가 안된다.

#insmod hello.ko
Error inserting './hello.ko' : -1 Invalid module format

커널 소스 트리에서는 버전을 나타내는 매크로를 정의한다(linux/version.h)

  1. UTS_RELEASE
  2. LINUX_VERSION_CODE
  3. KERNEL_VERSION(major,minor,release)

드라이버 모듈화를 구현하는 데 필요한 전역 커널 아이템(함수와 변수) 주소가 들어있다. 모듈이 적재할 때 모듈이 외부로 공개한 심볼은 모두 커널 심볼 테이블의 일부가 된다.
모듈 작성 시, 다른 모듈을 위해 심볼을 외부에 공개해야 한다면 아래의 매크로를 사용한다.

  1. EXPORT_SYMBOL(name);
  2. EXPORT_SYMBOL_GPL(name);

_GPL 버전은 GPL 라이선스 아래에 있는 모듈에게만 심볼을 공개한다.

초기화 함수는 '__init' 토큰을 사용을 권장한다. 이는 초기화 때만 해당 함수를 사용하라고 커널에게 알려줌으로서 모듈로더는 모듈 적재 후 초기화 함수를 제거하여 다른 목적으로 쓸 수 있게 메모리를 풀어준다.
정리함수는 '__exit' 토큰을 사용을 권장한다.

리눅스 커널에서 오류코드는 '<linux/errno.h>' 에서 정의하는 집합에 속한 음수값이다. 별도의 오류 코드를 만들고 싶다면, '<linux/errno.h>' 를 포함한다.

'기능을 등록하자마자 커널의 다른 부분에서 등록한 기능을 사용할 수 있다. 해당 기능의 초기화가 끝나기 전까지는 기능을 등록해서는 안된다.'
'초기화가 실패라고 결정했으나 커널의 다른 부분에서 이미 모듈이 등록한 설비를 사용 중인 경우를 고려해야 한다.'

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
 
MODULE_LICENSE("Dual BSD/GPL");
 
/*                                                        
 * These lines, although not shown in the book,           
 * are needed to make hello.c run properly even when      
 * your kernel has version support enabled                
 */                                                       
 
 
/*
 * A couple of parameters that can be passed in: how many times we say
 * hello, and to whom.
 */
static char *whom = "world";
static int howmany = 1;
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);
 
static int hello_init(void)
{
	int i;
	for (i = 0; i < howmany; i++)
		printk(KERN_ALERT "(%d) Hello, %s\n", i, whom);
	return 0;
}
 
static void hello_exit(void)
{
	printk(KERN_ALERT "Goodbye, cruel world\n");
}
 
module_init(hello_init);
module_exit(hello_exit);

이후 insmod 를 사용하여 모듈 로딩 시 매개 변수를 넘겨주면 아래와 같은 결과가 출력된다.

#insmod hellop.ko howmany=10 whom="WIFI"
(0) Hello, WIFI
(1) Hello, WIFI
(2) Hello, WIFI
(3) Hello, WIFI
(4) Hello, WIFI
(5) Hello, WIFI
(6) Hello, WIFI
(7) Hello, WIFI
(8) Hello, WIFI
(9) Hello, WIFI

사용자 영역 드라이버

커널 영역이 아닌 사용자 영역에서 디바이스를 제어할 수 있는 프로그램을 작성할 수 있는데, 이런 경우에서 장점은 다음과 같다.

  1. C 라이브러리 전체를 링크할 수 있음
  2. 드라이버 코드에서 디버거를 돌릴 수 있음
  3. 드라이버 실행 도중 응답이 없으면 죽일 수 있음
  4. 메모리 스왑이 가능함
  5. 라이선스 문제를 피하는 데 용이함
  6. 드라이버를 잘 설계하면, 커널 영역의 드라이버와 마찬가지로 동시 접근을 허용할 수 있음

다음은 단점에 해당한다.

  1. 사용자 영역에서 인터럽트를 사용할 수 없다.
  2. 메모리 참조는 권한이 있는 사용자만, mmap 로 사용가능하다.
  3. 응답 시간이 느리다.
  • computer/lg/2장_-_모듈_빌드와_실행.txt
  • Last modified: 3 years ago
  • by likewind