임베디드 리눅스 커널 프로그래밍(2) - 커널 데이터타입, 커널 인터페이스 함수
커널 Data Type
커널에서는 C언어의 원래 자료형 대신에 typedef로 정의된 자료형이 많이 사용된다.
커널에서 여러 종류의 값을 나타나는 데에 int나 long 등을 사용하는 대신 접미사 _t로 끝나는 자료형을 많이 사용한다.
- pid_t, uid_t, gid_t, dev_t, size_t, ...
- <linux/types.h>에 정의되어 있음
데이터의 크기를 명시적으로 표현한 자료형도 사용한다.
- u8, u16, u32, s8, s16, s32 (커널 코드에서만 사용 가능)
u -> unsigned / s -> signed - 사용자 프로그램에서는 __u8, __s8과 같이 _를 두 개 붙여서 사용함
- <asm/types.h>에 정의되어 있음
Kernel Interface 함수
커널 프로그램은 일반적인 라이브러리를 사용하지 못하고 커널에서 export한 함수들만 사용이 가능하다.
커널 인터페이스 함수의 분류는 아래와 같다.
- I/O port, I/O memory
- Interrupt
- Memory
- Synchoronization
- Kernel Message 출력
- Device Driver register
Kernel Interface 함수 - port I/O
1. I/O에 대한 가상주소 맵핑
void *ioremap(unsigned long phys_addr, unsigned long size); //physical주소를 가상주소로 맵핑
void *ioremap_nocache(unsigned long phys_addr, unsigned long size);//캐시에 복제하지 말란 뜻
void iounmap(void * addr); //맵핑한거 해제
2. I/O memory 읽기
unsigned int ioread8(void *addr); //8비트 읽기
unsigned int ioread16(void *addr); //16비트 읽기
unsigned int ioread32(void *addr); //32비트 읽기
3. I/O memory 쓰기
void iowrite8(u8 value, void *addr); //8비트 쓰기
void iowrite16(u16 value, void *addr); //16비트 쓰기
void iowrite32(u32 value, void *addr); //32비트 쓰기
4. I/O port 입출력 (x86)
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
Kernel Interface 함수 - Interrupt
1. 인터럽트 비활성화/활성화 (macro)
local_irq_disable();
local_irq_enable();
2. 인터럽트 비활성화/활성화 시 status register 저장/복원 (macro)
unsigned long flags;
local_irq_save(flags);
local_irq_restore(flags);
3. 인터럽트 핸들러 등록/해제
//등록
int request_irq(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void* device);
//해제
void free_irq(unsigned int irq, void *devid);
Kernel Interface 함수 - Memory
1. 커널 물리적 메모리 동적 할당/해제
void *kmalloc(size_t size, int flags); //할당
void kfree(void *obj); //해제
- 커널 메모리 할당 : 최대 크기 제한 있음. (초기 128KB, 현재 증가함)
- 물리적 주소 공간에서 연속적인 메모리를 할당한다.
- flags : GFP_USER(사용자 프로그램용 메모리 할당), GFP_KERNEL(커널용 메모리 할당, sleep가능), GFP_ATOMIC(인터럽트 핸들러 등에서 사용, sleep불가) 등
2. 커널 가상 메모리 동적 할당/해제
void *vmalloc(unsigned int len)
- 커널 메모리 할당, 크기 제한 없음
- 가상 주소 공간에서 연속적인 메모리 영역을 할당
void vmfree(void *addr)
- vmalloc()에서 할당받은 커널 메모리를 반납
Kernel Interface 함수 - 데이터 복사
1. 사용자 공간과 커널 공간 사이에 데이터 복사
unsigned long copy_from_user(void *to, const void *from, unsigned long n);
unsigned long copy_to_user(void *to, const void *from, unsigned long n);
put_user(data, ptr);
get_user(ptr) (macro);
- ptr이 가리키는 사용자 공간에 data를 전달(put)하거나 가져옴(get)
- ptr의 타입에 따라서 복사할 데이터 크기를 인식함.
- 커널 공간에서 사용자 공간의 메모리를 읽고 쓰는데 접근할 수 있는지를 검사하는 동작을 포함
2. 메모리 값 설정
void *memset(void *s, char c, size_t count); //메모리에 s에 c를 count만큼 복사
Kernel Interface 함수 - Synchronization
동기화 관련 함수들
void sleep_on(struct wait_queue **q); // deprecate
void sleep_in_interruptible(struct wait_queue **q); // deprecate
//q의 번지를 event로 sleep하며, uninterruptible/interruptible
wait_event(queue, condition);//(macro)
wait_event_interruptible(queue, condition);
/*condition이 1일 때까지 wait, queue번지를 event로 하여 sleep하며
uninterruptible/interruptible*/
void wake_up(struct wait_queue **q);
void wake_up_interruptible(struct wait_queue **q);
//sleep_on, wait_event에 의해 sleep한 task를 깨움
Kernel Interface 함수 - 메시지 출력
표준 출력으로는 printk 함수를 사용한다.
printk(const char *fmt, ...);
printk(LOG_LEVEL message);
//예시
printk("<1>Hello, World!");
printk(KERN_WARNING "warning...\n"); //<4>
LOG_LEVEL은 <linux/kernel.h>를 참조하자.
=> KERN_EMERG, KERN_ALERT, KERN_ERR, KERN_WARNING, KER_INFO, KERN_DEBUG
Kernel Interface 함수 - device driver 관련
디바이스 드라이버 관련해서는 상당히 중요한데, 등록/해체하는 함수들은 아래와 같다.
1. 등록
int register_xxxdev(unsigned int major, const char *name, struct file_operations *fops);
- character / block driver를 xxxdev[major]에 등록한다.
- xxx : chr 또는 blk
2. 해제
int unregister_xxxdev(unsigned int major, const char *name);
- xxxdev[major]에 등록되어 있는 디바이스 드라이버를 제거한다.
3. 네트워크 디바이스 드라이버의 경우 등록/해제
int register_netdev(struct net_device *dev);
int unregister_netdev(struct net_device *dev);
4. 장치번호 dev로부터 major/minor 번호 구하는 함수
MAJOR(kdev_t dev);
MINOR(kdev_t dev);
Kernel Interface 함수 - signal 함수
디바이스 드라이버에서 사용자 프로그램에 signal을 보내는 함수.
//예시
int kill_proc(pid_t pid, int signum, int priv);
pid (process id)
- current : 현재 프로세스 task_struct에 대한 ptr(macro)
- current -> pid : 현재 프로세스의 pid
- cureent -> ppid : 현재 프로세스의 부모 프로세스의 pid
사용자 프로그램에서 signal handler 등록하는 함수
void (*signal(int signum, void(*handler)(int)) (int);
'Computer Engineering > 임베디드 시스템' 카테고리의 다른 글
리눅스 디바이스 드라이버 프로그래밍(1) - 디바이스 드라이버 개요, 디바이스 드라이버 종류 (0) | 2019.06.12 |
---|---|
임베디드 리눅스 커널 프로그래밍(3) - 시스템 호출 함수 구현 (0) | 2019.06.12 |
임베디드 리눅스 커널 프로그래밍(1) - application 프로그래밍과 커널프로그래밍의 차이점, 커널프로그래밍 시 주의사항 (2) | 2019.06.11 |
ABI와 EABI (0) | 2019.06.11 |
툴체인(Tool Chain)이란 (0) | 2019.06.11 |
댓글
이 글 공유하기
다른 글
-
리눅스 디바이스 드라이버 프로그래밍(1) - 디바이스 드라이버 개요, 디바이스 드라이버 종류
리눅스 디바이스 드라이버 프로그래밍(1) - 디바이스 드라이버 개요, 디바이스 드라이버 종류
2019.06.12 -
임베디드 리눅스 커널 프로그래밍(3) - 시스템 호출 함수 구현
임베디드 리눅스 커널 프로그래밍(3) - 시스템 호출 함수 구현
2019.06.12 -
임베디드 리눅스 커널 프로그래밍(1) - application 프로그래밍과 커널프로그래밍의 차이점, 커널프로그래밍 시 주의사항
임베디드 리눅스 커널 프로그래밍(1) - application 프로그래밍과 커널프로그래밍의 차이점, 커널프로그래밍 시 주의사항
2019.06.11 -
ABI와 EABI
ABI와 EABI
2019.06.11