FSTWikiRev. 1.86 KernelApi
Login:
Password:
Join
E D R S I H P RSS
FrontPage|FindPage|TitleIndex|RecentChanges

Kernel API #

-- 김도집 2005-09-22 14:20:31

Kernel API에 대한 첫번째 문서이다. 두번째 문서는 Kernel API 2이다.

Contents

1 Kernel API 1 - Core (1/2)
1.1 서론
1.2 기본 자료형
1.3 주요 헤더 파일들
1.4 비트 연산
1.4.1 set_bit
1.4.2 clear_bit
1.4.3 change_bit
1.4.4 test_and_set_bit
1.4.5 test_and_clear_bit
1.4.6 test_and_change_bit
1.4.7 test_bit(nr,p)
1.5 initcall/exitcall
1.6 디바이스 등록 및 해제
1.6.1 struct platform_device
1.6.1.1 to_platform_device
1.6.1.2 platform_device_register
1.6.1.3 platform_device_unregister
1.6.1.4 platform_device_register_simple
1.7 드라이버 등록 및 해제
1.7.1 platform_driver
1.7.1.1 platform_driver_register
1.7.1.2 platform_driver_unregister
1.7.1.3 platform_get_drvdata/platform_set_drvdata
1.7.2 device_driver
1.7.2.1 driver_register
1.7.2.2 driver_unregister
1.7.2.3 dev_set_drvdata
1.7.2.4 dev_get_drvdata
1.8 문자 디바이스 드라이버
1.8.1 어떤 API를 사용할 것인가
1.8.2 chrdevs vs cdev_map
1.8.3 문자 디바이스 드라이버 API
1.8.3.1 struct file_operations
1.8.3.2 register_chrdev
1.8.3.3 unregister_chrdev
1.8.3.4 struct cdev
1.8.3.5 cdev_init
1.8.3.6 cdev_add
1.8.3.7 cdev_del
1.8.3.8 register_chrdev_region
1.8.3.9 alloc_chrdev_region
1.8.3.10 unregister_chrdev_region
1.9 장치 번호
1.9.1 MKDEV
1.9.2 MAJOR
1.9.3 MINOR
1.10 프로세스
1.10.1 스케줄링
1.10.1.1 schedule_timeout
1.10.1.2 set_current_state
1.10.1.3 wait_event_interruptible
1.10.1.4 wake_up_interruptible
1.11 타임(타이머)
1.11.1 ?BogoMIPS
1.11.2 loops_per_jiffy
1.11.3 jiffies
1.11.4 커널 타이머
1.11.4.1 자료 구조
1.11.4.2 TIMER_INITIALIZER
1.11.4.3 init_timer
1.11.4.4 add_timer
1.11.4.5 del_timer
1.11.4.6 mod_timer
1.11.5 High-resolution 커널 타이머
1.11.5.1 hrtimer_init
1.11.5.2 hrtimer_start
1.11.5.3 hrtimer_cacel
1.11.5.4 hrtimer_restart
1.11.5.5 hrtimer_get_remaining
1.11.5.6 hrtimer_get_res
1.11.5.7 hrtimer_active
1.11.5.8 hrtimer_forward
1.11.5.9 hrtimer_nanosleep
1.12 메모리
1.12.1 사용자/커널 공간
1.12.1.1 copy_from_user
1.12.1.2 copy_to_user
1.12.1.3 get_user
1.12.1.4 put_user
1.12.1.5 verify_area
1.12.1.6 access_ok
1.12.2 메모리 매핑
1.12.2.1 remap_page_range
1.12.2.2 remap_pfn_range
1.12.2.3 get_user_pages
1.12.3 IO 메모리 매핑
1.12.3.1 request_mem_region / release_mem_region
1.12.3.2 ioremap
1.12.3.3 iounmap
1.12.3.4 io_remap_pfn_range
1.12.3.5 readb/w/l
1.12.3.6 writeb/w/l
1.12.4 커널 메모리
1.12.4.1 kmalloc
1.12.4.2 kzalloc
1.12.4.3 vmalloc
1.12.4.4 kmem_cache_create
1.12.4.5 kmem_cache_alloc
1.12.4.6 kmem_cache_free
1.12.4.7 kmem_cache_destroy
1.12.4.8 get_zeroed_page
1.12.4.9 __get_free_page
1.12.4.10 __get_free_pages
1.12.5 유용한 매크로
1.13 MMAP
1.13.1 dma_mmap_writecombine
1.13.2 dma_free_writecombine
1.13.3 io_remap_pfn_range
2 DMA
2.1 메모리 할당
2.1.1 dma_alloc_coherent
2.1.2 dma_alloc_writecombine
2.1.3 Streaming DMA
2.1.4 dma_map_single
2.1.5 dma_unmap_single
2.1.6 dma_sync_single_for_cpu
2.1.7 dma_sync_single_for_device
2.2 DMA POOL
2.2.1 dma_pool_create
2.2.2 dma_pool_destroy
2.2.3 dma_pool_alloc
2.2.4 dma_pool_free

1.1 디바이스 등록 및 해제 #

리눅스 커널 2.6에서는 kobject라는 객체 기반으로 디바이스 및 드라이버의 계층적 구조를 갖고 있다. 예를 들어 등록된 버스가 있고 버스에 새로운 장치가 장착되면 버스 드라이버가 장치를 탐지하고 이에 맞는 드라이버를 찾아 등록하게 된다.

따라서 버스 상의 디바이스와 드라이버는 기본적으로 이름으로 찾게 된다. 따라서 버스 상에 등록된 디바이스의 이름과 드라이버의 이름이 서로 다르다면 정상적으로 드라이버가 동작하지 않는다.

다음은 platform_bus_type 라는 가상의 플랫폼 버스 상에 새로운 디바이스를 등록하는 방법이다.

1.1.1 자료 구조 #

platform_bus_type 라는 가상의 플랫폼 버스 상의 디바이스를 정의하는 구조체는 <linux/device.h>에 정의되어 있다. 그 구조체는 platform_device 이다.

구조체의 원형은 다음과 같다:
struct platform_device {
  char *name;
  u32 id;
  struct device dev;
  u32 num_resources;
  struct resource *resource;
};

필드설명
name
id
dev
num_resources
resource

간단한 사용 예는 다음과 같다:
static void xxx_relese_dev(struct device *dev)
{
}

static struct platform_device xxx_device = {
  .name =           "xxx_device",
  .id   =           0,
  .dev  = {
     .release = xxx_release_dev,
  },
  .num_resources = 0,
};

1.1.2 platform_device_register #

플랫폼 디바이스를 등록한다.

함수 원형은 다음과 같다:
int platform_device_register(struct platform_device *pdev)

1.1.3 platform_device_unregister #

플랫폼 디바이스의 등록을 해제한다.

함수 원형은 다음과 같다:
void platform_device_unregister(struct platform_device *pdev)

1.2 드라이버 등록 및 해제 #

1.2.1 자료 구조 #

driver_register/device_unregister 함수에서 사용하는 자료형은 <linux/device.h>에 선언되어 있다.
struct device_driver {
  const char *name;
  struct bus_type *bus;

  struct completion unloaded;
  struct kobject kobj;
  struct klist klist_devices;
  struct klist_node knode_bus;

  struct module *owner;

  int (*probe) (struct device *dev);
  int (*remove) (struct device *dev);
  int (*shutdown) (struct device *dev);
  int (*suspend) (struct device *dev, pm_message_t state, u32 level);
  int (*resume) (struct device *dev, u32 level);
};

필드설명
name디바이스 드라이버의 이름을 문자열 형으로 지정한다 (필수)
bus보통은 &platform_bus_type으로 지정한다 (필수)
unloaded
kobj내부적으로 드라이버 객체를 관리하기 위한 것으로 직접적으로 사용하지 않는다 (임의 지정하지 않는다)
klist_devices
knode_bus
owner
probe()디바이스의 초기화 루틴이다 (필수)
remove()디바이스가 제거될 때 호출되는 루틴이다 (필수)
shutdown()
suspend()절전모드로 들어갈 때 호출된다 (필수)
resume()절전모드를 빠져나올 때 호출된다 (필수)
/!\ 위 테이블에서 foo()와 같이 ()가 붙은 필드는 함수(포인터)를 의미한다.

1.2.2 driver_register #

버스를 갖는 드라이버를 등록할 때 사용하는 함수이다. 함수의 원형은 다음과 같다:
int driver_register(struct device_driver *drv);

관련함수: driver_unregister

static struct device_driver foo_driver = {
  .name    = "foo”,
  .bus     = &platform_bus_type,
  .probe   = foo_probe,
  .remove  = foo_remove,
  .suspend = foo_suspend,
  .resume  = foo_resume,
};

static int __init foo_init(void) {
  int err;

  err = driver_register(&foo_driver);

  return err;
}

1.2.3 driver_unregister #

driver_register()를 통해 등록된 드라이버를 해제할 때 사용한다. 함수의 원형은 다음과 같다:
void driver_unregister(struct device_driver *drv)

관련함수: driver_register

1.2.4 dev_set_drvdata #

사용자 데이터를 device 구조체의 driver_data 필드를 통해 참조할 수 있도록 설정하는 wrapper 함수이다.

함수 원형은 다음과 같다:
void dev_set_drvdata(struct device *dev, void *data)

관련함수: dev_get_drvdata

1.2.5 dev_get_drvdata #

device 구조체의 driver_data 필드의 참조 주소를 가져오는 wrapper 함수이다.

함수 원형은 다음과 같다:
void * dev_get_drvdata(struct device *dev)

관련함수: dev_set_drvdata

1.3 프로세스 #

1.3.1 스케줄링 #

1.3.1.1 schedule_timeout #

적어도 일정 시간(timeout)동안 휴면상태로 있다가 다시 실행 가능 상태가 된다. 실행 가능 상태가 된다는 말은 바로 실행된다는 것이 아니라 스케줄러에 의해 조건이 충족되면 실행된다는 의미이다. 즉, 스케줄링에 따라 일정 시간 보다 더 오랫 동안 잠정적인 휴면 상태에 있을 수도 있다.

함수 원형은 다음과 같다:
signed long __sched schedule_timeout(signed long timeout)

timeout은 jiffies 단위 값으로 적어도 timeout 동안 휴면 상태에 있게 된다.

timeout동안 휴면 상태에 있을 때 task의 상태는 다음과 같을 수 있다:
상태를 나타내는 매크로설명
TASK_UNINTERRUPTIBLEtimeout 이후에만 깨어난다
TASK_INTERRUPTIBLE시그널 받거나 timeout이 되면 깨어난다

timeout을 통해 깨어나게 되면 0을 반환하고 TASK_INTERRUPTIBLE 상태에서 시그널을 받아 깨어나게 되면 남은 jiffies 값을 반환한다.

관련함수: set_current_state

set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(2);
2 jifffies 이후에 실행 가능한 상태가 되며 그때까지 휴면 상태로 있는다. 휴면 상태에서 시그널을 받는 경우에도 깨어난다.

1.3.1.2 set_current_state #

현 task의 상태를 변경한다. 이는 <linux/sched.h>헤더 파일에 정의되어 있다.

void set_cureent_state(int state)

state 값은 다음과 같다:
state설명
TASK_RUNNING실행 가능한 상태
TASK_INTERRUPTIBLE시그널을 받거나 wakeup 조건을 만족하면 깨어날 수 있는 휴면 상태
TASK_UNINTERRUPTIBLEwakeup 조건을 만족할때만 깨어날 수 있는 휴면 상태

1.4 타임(타이머) #

1.4.1 jiffies #

커널은 필수적으로 하나의 타이머 인터럽트를 갖게 된다. 이는 스케줄링 및 타이머 등의 기준이 된다. 이때 타이머 인터럽트가 한 번 발생할 때마다 이를 tick이라 하며 하나의 tick마다 jiffies 값이 1씩 증가하게 된다.

jiffies는 커널 전역 변수로 원형은 다음과 같다:
volatile unsigned long jiffies;

1.4.2 커널 타이머 #

커널 타이머 관련 함수는 <linux/timer.h>에 정의되어 있다.

1.4.2.1 자료 구조 #

struct timer_list {
  struct list_head entry;
  unsigned long expires;

  spinlock_t lock;
  unsigned long magic;

  void (*function)(unsigned long);
  unsigned long data;

  struct tvec_t_base_s *base;
};

1.4.2.2 TIMER_INITIALIZER #

TIMER_INITIALIZER(function, expires, data)

static struct timer_list foo_timer = 
  TIMER_INITIALIZER(foo_timer_function, 0, 0);

1.4.2.3 init_timer #

void init_timer(struct timer_list *timer)

1.4.2.4 add_timer #

void add_timer(struct timer_list *timer)

1.4.2.5 del_timer #

int del_timer(struct timer_list *timer)

/!\ SMP머신에서 del_timer_sync()를 사용한다.

1.4.2.6 mod_timer #

int mod_timer(struct timer_list *timer, unsigned long expires)

1.5 메모리 #

1.5.1 사용자/커널 공간 #

메모리 영역은 사용자 영역과 커널 영역으로 나뉜다. 일반적으로 사용자 영역의 경우 page out(swap out)된 경우가 있을 수 있다. 이런 메모리 공간을 커널 영역에서 직접 접근하는 경우 page fault 등이 생길 수 있는데, 커널 공간의 일부 처리 중에는 이러한 것이 문제가 될 수 있다.

반대로 커널 영역의 메모리는 사용자 영역의 프로세스에서 직접 접근할 수 없다.

따라서 서로 다른 영역을 메모리를 접근하기 위해서는 이에 필요한 적절한 API를 이용해야 한다.

1.5.1.1 copy_from_user #

사용자 영역의 메모리에 있는 데이터를 커널 영역의 메모리 영역으로 복사할 때 사용하는 함수이다. 이 함수는 아키텍처에 의존적인 함수로 <asm/uaccess.h> 헤더 파일에 선언되어 있다.

unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)

매개변수설명
to커널 영역의 메모리 주소
from사용자 영역의 메모리 주소
n바이트 단위의 데이터 크기

성공하면 0을 반환하고 실패하면 0이 아닌 값을 반환한다.

관련함수: copy_to_user

/!\ 함수 내부적으로 access_ok를 통해 사용자의 메모리 영역을 검사하므로 별도의 access_ok를 호출할 필요는 없다.

1.5.1.2 copy_to_user #

unsigend long copy_to_user(void __user *to, const void *from, unsigned long n)

1.5.1.3 get_user #

사용자 영역의 데이터를 커널 영역으로 복사할 때 사용한다. 이는 아키텍처 의존적인 함수로 <asm/uacess.h>에 선언되어 있다.

int get_user(x, void *from)

x는 char, short, int 형으로 넘겨지는 데이터 형에 따라 복사 할 데이터의 길이(바이트 단위)가 결정된다.

1.5.1.4 put_user #

커널 영역의 데이터를 사용자 영역으로 복사한다. 이는 아키텍처 의존적인 함수로 <asm/uaccess.h>에 선언되어 있다.

int put_user(x, void *to)

x는 char, short, int 형으로 넘겨지는 데이터 형에 따라 복사 할 데이터의 길이(바이트 단위)가 결정된다.

1.5.1.5 verify_area #

다음절에서 소개하는 access_ok의 wrapper 함수이다.

int verify_area(int type, const void __user * addr, unsigned long size)

메모리가 유효하면 0을 반환하고 그렇지 않으면 -EFAULT 값을 반환한다.

/!\ acess_ok함수와 동일한 것이며 사용자는 verify_area함수를 사용하길 권한다.

1.5.1.6 access_ok #

사용자 영역의 메모리가 유효한지 검사한다. <asm/uaccess.h>에 선언되어 있다.

int access_ok(int type, void *addr, unsigned long size);

매개변수설명
type어떤 유효 검사를 할지를 결정한다. 다음 표를 참조
addr유효 검사를 시작할 주소
size유효 검사를 할 영역의 바이트 단위 크기

type 매개 변수는 매크로로 선언되어 있는데, 다음과 같다:
type설명
VERIFY_READ읽기에 대한 유효 검사
VERIFY_WRIT쓰기에 대한 유효 검사

/!\ 다른 함수와 달리 유효하다면 0이 아닌 값을 반환하고 유효하지 않다면 0을 반환한다.

/!\ 동일한 기능의 함수로 access_ok의 wrapper함수가 있는데 verify_area함수가 있다. 사용자는 이것을 사용하길 권한다.

관련함수: verify_area()

copy_from_user/copy_to_user 또는 get_user/put_user 등의 함수는 access_ok를 사용할 필요가 없다. __get_user 등과 같이 더 저 수준의 함수를 직접 호출하여 사용할 때만 사용하게 된다.

다음은 access_ok를 사용한 예이다.
static inline unsigned long copy_from_user(void *to, const void __user *from,
 unsigned long n)
{
  if (access_ok(VERIFY_READ, from, n))
    n = __arch_copy_from_user(to, from, n);
  else
    memzero(to, n);
  return n;
}

1.5.2 IO 메모리 #

io 메모리와 관련된 함수는 <asm/io.h>에 선언되어 있다.

1.5.2.1 ioremap #

void __iomem *ioremap(unsigned long offset, unsigned long size)

1.5.2.2 iounmap #

void iounmap(volatile void __iomem *addr)

1.5.2.3 readb #

unsigned char readb(const volaltile void __iomem *addr)

1.5.2.4 readw #

unsigned short readw(const volaltile void __iomem *addr)

1.5.2.5 readl #

unsigned int readl(const volaltile void __iomem *addr)

1.5.2.6 writeb #

void writeb(unsigned char b, const volaltile void __iomem *addr)

1.5.2.7 writew #

void writew(unsigned short b, const volaltile void __iomem *addr)

1.5.2.8 writel #

void writel(unsigned int b, const volaltile void __iomem *addr)

1.6 사운드(Sound) #

리눅스에서는 두가자 형태의 사운드 드라이버를 제공한다. OSS와 ALSA가 그것이다. OSS는 리눅스의 오래된 사운드 아키텍처이다. 리눅스의 사운드는 ALSA 기반으로 바뀌고 있다.

ALSA에 대한 것은 ALSA를 참고하라.

last modified 2007-03-11 13:55:12
ShowPage|FindPage|DeletePage|LikePages Valid XHTML 1.0! Valid CSS! powered by MoniWiki
3.1487 sec