C & Docker & LINUX

리눅스 커널) 모듈 프로그래밍(간단한 Char Device 모듈 구현)

로픽 2017. 5. 1. 22:30
300x250

간단한 Char Device 모듈 구현 - 커널 모듈 프로그래밍

** 리눅스 커널 2.6.36 버전에서 간단한 character device와 그 device driver를 만드는 커널 모듈을 제작한다.


1. 루트 권한을 획득한다.


2. 홈 디렉터리 밑에 module 이라는 디렉토리를 생성하고 그 디렉토리로 이동한다.


3. #yum install -y module-init-tools를 수행한다.


4. #vi minibuf.c를 수행하여 아래와 같이 코딩한다.


#include
#include
#include
#include
#include
#include
#include

#define DEVICE_NAME "Minibuf"
#define BUFFER_LEN 1024
#define DEV_MAJOR 254
#define DEV_MINOR 5

static int s_bDeviceOpen = 0;
static char s_strBuf[BUFFER_LEN];
static int s_nBufPos = 0, s_nBufEnd=0;

static int device_open(struct inode *inode, struct file *filp);
static int device_release(struct inode *inode, struct file *filp);
static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset);
static ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset);
static int is_buffer_empty(void);
static int is_buffer_full(void);
static int read_buffer_char(char *buffer);
static int write_buffer_char(char *buffer);

struct file_operations device_fops={
	read:	device_read,
	write: device_write,
	open: device_open,
	release:	device_release
};

static struct cdev minibuf_cdev={
	.owner = THIS_MODULE,
	.ops = &device_fops
};

dev_t dev_num = -1;
struct cdev *dev_ptr = NULL;

int __init init_minibuf(void)
{
	printk("Loading Mini Buffer Module\n");
	
	dev_num = MKDEV(DEV_MAJOR, DEV_MINOR);
	register_chrdev_region(dev_num, 1, DEVICE_NAME);
	dev_ptr = cdev_alloc();
	cdev_init(dev_ptr, &device_fops);
	cdev_add(dev_ptr, dev_num, 1);

	strcpy(s_strBuf, "Hello World\n");
	s_nBufEnd = strlen(s_strBuf)+1;
	return 0;
}

void __exit exit_minibuf(void)
{
	printk("Unloading Mini Buffer Module\n");
	unregister_chrdev_region(dev_num, 1);
}

int device_open(struct inode *inode, struct file *filp)
{
	printk(DEVICE_NAME ": Device open(%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
	if(s_bDeviceOpen)
	{
		printk(DEVICE_NAME ": Device already open\n");
		return -EBUSY;
	}
	++s_bDeviceOpen;
	return 0;
}

int device_release(struct inode *inode, struct file *filp)
{
	printk(DEVICE_NAME ":Device release(%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
	if(!s_bDeviceOpen)
	{
		printk(DEVICE_NAME ": Device has not opened\n");
		return -EINVAL;
	}

	--s_bDeviceOpen;
	return 0;
}

ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
	int count = 0;
	if(is_buffer_empty())
	{
		printk(DEVICE_NAME ": Read return EOF\n");
		return 0;
	}
	
	while(!is_buffer_empty()&&length>1)
	{
		read_buffer_char(buffer);
		++buffer;
		--length;
		++count;
	}

	put_user(0, buffer);
	++count;

	printk(DEVICE_NAME ": Read %d bytes\n", count);
	return count;
}

ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset)
{
	return -ENOSYS;
}

int is_buffer_empty(void)
{
	return(s_nBufPos == s_nBufEnd) ? 1 : 0;
}

int is_buffer_full(void)
{
	int pos = s_nBufEnd + 1;
	if(pos == BUFFER_LEN)
		pos = 0;
	return (pos == s_nBufPos) ? 1 : 0;
}

int read_buffer_char(char *buffer)
{
	if(is_buffer_empty())
		return -1;

	put_user(s_strBuf[s_nBufPos], buffer);

	if(++s_nBufPos == BUFFER_LEN)
		s_nBufPos =0;
	return 0;
}

int write_buffer_char(char *buffer)
{
	if(is_buffer_full())
		return -1;
	get_user(s_strBuf[s_nBufEnd], buffer);

	if(++s_nBufEnd == BUFFER_LEN)
		s_nBufEnd = 0;

	return 0;
}

module_init(init_minibuf);
module_exit(exit_minibuf);
MODULE_LICENSE("GPL");


5. #vi Makefile 을 수행하여 아래와 같이 코딩한다.

KERNELDIR = /lib/modules/$(shell uname -r)/build

obj-m = minibuf.o

KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:
    rm -rf  *.ko
    rm -rf  *.mod.*
    rm -rf  .*.cmd
    rm -rf  *.o


6. #make를 수행하여 커널 모듈을 생성한다.


7. #/sbin/insmod  minibuf.ko를 수행하여 모듈을 로드시킨다.


8. #/sbin/lsmod를 수행하여 로드된 모듈을 확인한다.


9. #mknod /dev/minibuf  c  254  5 를 수행하여 가상 디바이스를 생성한다.


10. #cat /dev/minibuf를 수행하여 가상 디바이스에 저장된 문자열을 읽어 화면에 출력한다.


11. #/sbin/rmmod minibuf를 수행하여 로드된 모듈을 언로드한다. 


12. #rm/dev/minibuf를 수행하여 가상 디바이스를 삭제한다.


13. #dmesg로 커널 로그를 확인한다.

반응형