본문 바로가기

학부_대학원/임베디드 리눅스

(임베디드)리눅스 커널 모듈 - User, Kernel 통신

SMALL
USER MODE

KERNEL MODE [.ko] == kernel object 런타임 상에 적재, 추출 가능



USER MODE 와 KERNEL MODE 의 통신이 필요하다.

USER MODE <—> KERNEL MODE 통신에 관해서 진행한다.

앱 계층과 커널 모드 통신 할 때, 리눅스 커널에서 권고 사항이 존재함  [Documnet File 참초]

4가지

     1.  Copy to User [4 바이트 이상]
  1. Copy from User [4 바이트 이상]
  2. Put User [4 바이트 이하]
  3. Get User [4 바이트 이하]

권고 사항일 뿐, Get과 Put 도 가능




tip

커널에서 구조체를 초기화 할 때, sprintf 사용하자

구조체를 만 들 때, 4 바이트 단위로 만들어서 구조체 크기를 align  만들 때가 있다.

이 때 이런것을 막기 위해서 사용하는 옵션이 __attribute__ ((packed)) 옵션을 주자 


Kernel Source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
  mydrv.c - kernel 3.0 skeleton device driver
               copy_to_user()
 */
 
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
 
#include <linux/kernel.h>   /* printk() */
#include <linux/slab.h>   /* kmalloc() */
#include <linux/fs.h>       /* everything... */
#include <linux/errno.h>    /* error codes */
#include <linux/types.h>    /* size_t */
#include <asm/uaccess.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/device.h>
 
#define DEVICE_NAME "mydrv"
static int mydrv_major = 240;
module_param(mydrv_major, int0);
 
 
/*  구조체 포맷  */
typedef struct
{
   int age;  //나이 :35
   char name[30];// 이름 : HONG KILDONG
   char address[20]; // 주소 : SUWON CITY
   int  phone_number; // 전화번호 : 1234
   char depart[20]; // 부서 : ELAYER
} __attribute__ ((packed)) mydrv_data;
 
//   sprintf(k_buf->name,"HONG KILDONG");
 
static int mydrv_open(struct inode *inode, struct file *file)
{
  printk("mydrv opened !!\n");
  return 0;
}
 
static int mydrv_release(struct inode *inode, struct file *file)
{
  printk("mydrv released !!\n");
  return 0;
}
 
static ssize_t mydrv_read(struct file *filp, char __user *buf, size_t count,
                loff_t *f_pos)
{
  mydrv_data *k_buf;
  
  k_buf = (mydrv_data*)kmalloc(count,GFP_KERNEL);
 
  
  k_buf->age = 24;
  sprintf(k_buf->name,"%s","jhong");
  sprintf(k_buf->address,"%s","busan");
  k_buf->phone_number= 777;
  sprintf(k_buf->depart,"%s","system");
 
 
  
  if(copy_to_user(buf,k_buf,count))
      return -EFAULT;
  printk("mydrv_read is invoked\n");
  kfree(k_buf);
  return 0;
 
}
 
static ssize_t mydrv_write(struct file *filp,const char __user *buf, size_t count,
                            loff_t *f_pos)
{
  mydrv_data *k_buf;
    
  k_buf = (mydrv_data*)kmalloc(count,GFP_KERNEL);
 
  if(copy_from_user(k_buf,buf,count))
      return -EFAULT;
 
  printk("age = %d\n",k_buf->age);
  printk("name = %s\n",k_buf->name);
  printk("address = %s\n",k_buf->address);
  printk("phone = %d\n",k_buf->phone_number);
  printk("depart = %s\n",k_buf->depart);
 
  printk("mydrv_write is invoked\n");
  kfree(k_buf);
  return 0;
}
 
 
/* Set up the cdev structure for a device. */
static void mydrv_setup_cdev(struct cdev *dev, int minor,
        struct file_operations *fops)
{
    int err, devno = MKDEV(mydrv_major, minor);
    
    cdev_init(dev, fops);
    dev->owner = THIS_MODULE;
    dev->ops = fops;
    err = cdev_add (dev, devno, 1);
    
    if (err)
        printk (KERN_NOTICE "Error %d adding mydrv%d", err, minor);
}
 
 
static struct file_operations mydrv_fops = {
    .owner   = THIS_MODULE,
       .read       = mydrv_read,
        .write   = mydrv_write,
    .open    = mydrv_open,
    .release = mydrv_release,
};
 
#define MAX_MYDRV_DEV 1
 
static struct cdev MydrvDevs[MAX_MYDRV_DEV];
 
static int mydrv_init(void)
{
    int result;
    dev_t dev = MKDEV(mydrv_major, 0);
 
    /* Figure out our device number. */
    if (mydrv_major)
        result = register_chrdev_region(dev, 1, DEVICE_NAME);
    else {
        result = alloc_chrdev_region(&dev,01, DEVICE_NAME);
        mydrv_major = MAJOR(dev);
    }
    if (result < 0) {
        printk(KERN_WARNING "mydrv: unable to get major %d\n", mydrv_major);
        return result;
    }
    if (mydrv_major == 0)
        mydrv_major = result;
 
    mydrv_setup_cdev(MydrvDevs,0&mydrv_fops);
    printk("mydrv_init done\n");    
    return 0;
}
 
static void mydrv_exit(void)
{
    cdev_del(MydrvDevs);
    unregister_chrdev_region(MKDEV(mydrv_major, 0), 1);
    printk("mydrv_exit done\n");
}
 
module_init(mydrv_init);
module_exit(mydrv_exit);
 
MODULE_LICENSE("Dual BSD/GPL");
 
cs


User Source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* test_mydrv.c */
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
 
#define MAX_BUFFER 26
char buf_in[MAX_BUFFER], buf_out[MAX_BUFFER];
 
/*  구조체 포맷  */
typedef struct
{
   int age;  //나이 :35
   char name[30];// 이름 : HONG KILDONG
   char address[20]; // 주소 : SUWON CITY
   int  phone_number; // 전화번호 : 1234
   char depart[20]; // 부서 : ELAYER
} __attribute__ ((packed)) mydrv_data;
 
 
 
mydrv_data in;
mydrv_data out;
 
int main()
{
  int fd,i;
  
  fd = open("/dev/mydrv",O_RDWR);
  memset(&in, 0x00sizeof(mydrv_data));
  memset(&out, 0x00sizeof(mydrv_data));
 
  read(fd,&in,sizeof(mydrv_data));
 
  printf("age = %d\n",in.age);
  printf("name = %s\n", in.name);
  printf("address = %s\n",in.address);
  printf("phone = %d\n",in.phone_number);
  printf("depart = %s\n",in.depart); 
 
  out.age = 24;
  sprintf(out.name,"%s","jhong\x00");
  sprintf(out.address,"%s","busan\x00");
  out.phone_number = 777;
  sprintf(out.depart,"%s","system\x00");
 
  
 
  write(fd,&out,sizeof(mydrv_data));
  close(fd);
  return (0);
}
 
 
 
cs



결과


LIST