Thursday, April 23, 2015

User & Kernel Memory Area in Embedded Linux

@ Memory Copy Interfaces from Kernel to User
  : copy_to_user()
  : copy_from_user()
  : put_user()
  : get_user()

@ 차이점
  : 일반적으로 아래와 같이 사용
  -. 4 byte 이하 작은 데이터를 다룰 경우 : put_user, get_user
  -. 4 byte 이상 큰 데이터를 다룰 경우 : copy_to_user, copy_from_user

@ 참고사항
  : copy_to_user, copy_from_user 함수를 사용하지 않아도
  : parameter로 넘어온 buf 포인터를 통해 sprintf 라든지 = 대입이라든지 가능함
  : 하지만 user <-> kernel 간 메모리 복사를 안전하게 하려면
  : 검증된 방법(인터페이스)를 이용하여 구현하는 것을 권장


@ Example
/*
 * @file   test_mydrv.c
 * @brief  Application Program for copy_to_user, copy_from_user
 */

typedef struct
{
    int age;
    char name[30];
    char address[20];
    int phone_number;
    char depart[20];
} __attribute__ ((packed)) mydrv_data;


int main()
{
  mydrv_data data;

  int fd = open("/dev/mydrv",O_RDWR);

  data.age = 29;
  strcpy(data.name, "seungin.cha");
  strcpy(data.address, "hwagok-dong");
  data.phone_number = 49104714;
  strcpy(data.depart, "H&A");

  // Send data from user to kernel (and then, Print data by Kernel)
  write(fd, &data, sizeof(data));

  // Receive data from kernel to user
  read(fd, &data, sizeof(mydrv_data));

  // Print data by User
  printf("\n");
  printf("u_age    : %d\n", data.age);
  printf("u_name   : %s\n", data.name);
  printf("u_address: %s\n", data.address);
  printf("u_phoneno: %d\n", data.phone_number);
  printf("u_depart : %s\n", data.depart);
  printf("\n");

  close(fd);
  return 0;
}

/*
 * @file   mydrv.c
 * @brief  Module Program for copy_to_user, copy_from_user
 */

typedef struct
{
    int age;
    char name[30];
    char address[20];
    int phone_number;
    char depart[20];
} __attribute__ ((packed)) mydrv_data;

...

static ssize_t mydrv_write(struct file *filp,const char __user *buf, size_t count, loff_t *f_pos)
{
    mydrv_data* k_buf, u_buf;

    k_buf = kmalloc(sizeof(mydrv_data), GFP_KERNEL);
    if (copy_from_user(k_buf, buf, sizeof(mydrv_data)))
    {
        return -EFAULT;
    }

// copy_from_user 함수를 이용하지 않아도 복사가 가능하나 권장하지 않음
//  u_buf = (mydrv_data*) buf;
//  k_buf->age = u_buf->age;
//  sprintf(k_buf->name, u_buf->name);
//  sprintf(k_buf->address, u_buf->address);
//  k_buf->phone_number = u_buf->phone_number;
//  sprintf(k_buf->depart, u_buf->depart);

    printk("\n");
    printk("k_age    : %d\n", k_buf->age);
    printk("k_name   : %s\n", k_buf->name);
    printk("k_address: %s\n", k_buf->address);
    printk("k_phoneno: %d\n", k_buf->phone_number);
    printk("k_depart : %s\n", k_buf->depart);
    printk("\n");

    kfree(k_buf);
    return 0;
}

static ssize_t mydrv_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    mydrv_data k_struct;
    k_struct.age = 31;
    sprintf(&k_struct.name, "seungkil.cha");
    sprintf(&k_struct.address, "bueon");
    k_struct.phone_number = 26401717;
    sprintf(&k_struct.depart, "shinjung");

    if (copy_to_user(buf, &k_struct, sizeof(mydrv_data)))
    {
        return -EFAULT;
    }

    return 0;
}

No comments:

Post a Comment