디바이스 드라이버를 위한 커널 서비스
1. 변수와 메모리 할당
1.1 디바이스 드라이버에서 변수의 사용
- 지역 변수와 전역 변수 중에 지역 변수를 사용하는 것이 좋다.
-> 디바이스 드라이버는 다중 프로세스 환경에서 동작.
프로세스 간 변수 사용에 따른 경쟁 문제를 해결하기 위해 가급적 지역 변수를 사용하는 편이 좋다. - 변수 명 사용시 static을 주로 사용
-> 커널 소스는 방대한 함수와 전역 변수가 있으므로 이것이 서로 중복되지 않도록 static으로 선언
cf. 함수 안에 static을 쓰면 전역 변수처럼 되기 때문에 함수 안에 쓰지 않는다.
1.2 이식성과 데이터 형
- 데이터 형
다른 플랫폼에서 문제없이 수행되려면 변수의 데이터 형을 명확히 해야한다.
특히, int 형의 경우, "CPU의 레지스터와 동일한 크기를 가지는 타입"이다.
이 말은 int의 실제 크기는 플랫폼마다 달라진다는 얘기이다.
따라서 커널에서 제공하는 데이터형을 사용하는 것이 바람직하다.
#include <asm/types.h>에서 제공하는 데이터형 |
|||
부호 있는 정수 |
부호 없는 정수 |
||
__s8, s8 |
8 bits (byte) |
__u8, u8 |
8 bits (byte) |
__s16, s16 |
16 bits (word) |
__u16, u16 |
16 bits (word) |
__s32, s32 |
32 bits |
__u32, u32 |
32 bits |
__s64, s64 |
64 bits |
__u64, u64 |
64 bits |
- 구조체의 실제 저장
typedef struct { u16 index; u16 data; u8 data2; }__attribute__ ((packed)) testctl_t; |
- 바이트 순서
다른 플랫폼에 이식할 경우, 정수 바이트 순서에 주의해야 한다.
프로세스에 따라 바이트 순서를 처리하는 헤더는 include/linux/byteorder/ 디렉토리에 있다.
#include <asm/byteorder.h>의 헤더를 포함시켜 사용한다.
리틀엔디언 방식인지, 빅엔디언 방식인지에 따라 __LITTLE_ENDIAN , __BIG_ENDIAN 이 정의된다. - 동적 데이터 접근
소스 코드에 정의 된 데이터 구조는 아키텍처에 따라 다르게 컴파일될 수 있다.
예를 들어, 소스 코드에 int char int 순서로 정의를 해놨다고 해도 컴파일하고 나면 아키텍처에 따라 순서가 바뀌어 char int int 혹은 int int char 로 정렬되어 컴파일 될 수 있다.
크기가 정해져 있지 않은 데이터를 액세스해야하는 경우 예외 처리기에서 처리되어 정렬된 데이터에 접근해야 하기 때문에 성능이 크게 저하된다.
따라서 크기가 정해져 있지 않은 데이터에 액세스해야하는 경우 다음 매크로를 사용해야 한다.
#include <asm/unaligned.h> |
|
get_unaligned (ptr) | ptr 주소에서 값을 읽는다. |
put_unaligned (val, ptr) | ptr 주소에 val 값을 쓴다. |
- I/O 메모리 접근 변수 처리
메모리 번지를 이용하는 I/O처리는 최적화 등에 의해 의도되지 않은 형태로 변할 수 있으므로 주의를 기울인다.
(예시)
0xE0000300 번지 (센서 입력)이 바뀌는 것을 대기하기 위해
u32 *ptr = (u32 *) 0xE0000300; while (*ptr = *ptr); |
위 코드는 컴파일러에 의한 최적화로 다음과 같이 변할 수 있다.
u32 *ptr = (u32 *) 0xE0000300; while(1); |
이 때는 voltaile를 이용하여 최적화되지 않도록 한다.
volatile u32 *ptr = (u32 *) 0xE0000300; |
1.3 커널에서의 동적 메모리 관리
커널에서는 malloc()이나 free()를 이용해 동적 메모리를 사용할 수 없다. 디바이스 드라이버는 커널 메모리를 사용하므로 물리적 접근이 가능하며 MMU를 고려한 처리가 필요하다.
* 가상 메모리 (Virtual Memory)
- 프로그램이 실행될 때 반드시 프로그램 전체가 실제 메모리에 있을 필요는 없으므로 현재 실행되어야 하는 부분만이 실제 메모리에 옮겨 쓰는 것이 가상 메모리
- 이 가상 메모리를 사용하기 위해 주소 변환을 하는 장치가 필요한 데 이 장치가 MMU
커널에서의 동적메모리 할당 함수
함수 |
특징 |
kmalloc(), kfree() |
malloc(), free()와 유사하며 디바이스 드라이버에서 많이 사용 할당 속도가 빠른 것이 특징 |
vmalloc(), vfree() |
할당하려는 크기 외에는 매개변수를 주지 않음 크기 제한이 없음 가상 메모리 관리 루틴이 수행되기 때문에 kmalloc보다 속도가 느림 인터럽트 서비스 함수 안에서는 사용 불가 |
__get_free_pages(), free_pages() |
페이지 단위 할당 함수 |
출처
https://ko.wikipedia.org/wiki/Volatile_변수
https://dojang.io/mod/page/view.php?id=432
http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=968
http://l2men.tistory.com/21
http://www.xml.com/ldd/chapter/book/ch10.html
http://young3276.tistory.com/4
'Linux Driver' 카테고리의 다른 글
캐릭터 디바이스 드라이버 (Character Device Driver) (0) | 2018.08.30 |
---|---|
디바이스 드라이버 (Device Driver) - 1. 개요 (1) | 2018.08.29 |
커널 모듈 (Kernel Module) (0) | 2018.08.29 |
디바이스 드라이버를 위한 커널 서비스 (Kernel Service for Device Driver) - 2. 인터럽트 처리 (0) | 2018.08.29 |
리눅스 커널 (linux kernel) (2) | 2018.08.29 |