Разработка модуля для ядра Linux 2.6.38

Автор: Пользователь скрыл имя, 03 Октября 2011 в 19:49, курсовая работа

Краткое описание

Модуль - это некий код, который может быть загружен или выгружен ядром по мере необходимости[1]. Модули расширяют функциональные возможности ядра без необходимости перезагрузки системы. Например, одна из разновидностей модулей ядра, драйверы устройств, позволяют ядру взаимодействовать с аппаратурой компьютера. При отсутствии поддержки модулей пришлось бы писать монолитные ядра и добавлять новые возможности прямо в ядро. При этом, после добавления в ядро новых возможностей, пришлось бы перезагружать систему.

Оглавление

Задание 4

Особенности реализации модуля ядра 5

Методы 5

Вывод информации 5

Пространство пользователя и пространство ядра 5

Сборка 6

Загрузка и выгрузка ядра 6

Файлы символьных устройств 7

Структура file_operations 7

Регистрация устройства 8

Отключение устройства 8

Создание файла устройства 8

Работа пользовательского приложения с модулем ядра 9

Разработка модуля ядра 10

Разработка простейшего модуля ядра 10

Создание прототипов функций 10

Реализация функций 11

Организация обмена данных с пространством пользователя 11

Реализация политики безопасности 12

Организация работы с модулем ядра 14

Заключение 15

Библиографический список 16

Приложение 17

Структура file_operations для ядра Linux 2.6.38 17

Код модуля ядра 18

Файлы: 1 файл

Модуль ядра.docx

— 72.24 Кб (Скачать)
  • try_module_get(THIS_MODULE): увеличивает счетчик обращений на 1.
  • try_module_put(THIS_MODULE): уменьшает счетчик обращений на 1.

Создание  файла устройства

      Для обеспечения возможности обратиться из пользовательского приложения к  нашему модулю создадим файл устройства с помощью mknod утилиты. Скрипт[5] для создания в нашем случае будет выглядеть так:

mknod char_dev c 100 0

      Где char_dev – имя файла, а 100 – номер который возвращает функция register_chrdev() при подключении модуля.

Работа  пользовательского  приложения с модулем  ядра

      Для работы с модулем ядра необходимо подключиться к файлу устройства с помощью функции open. Далее работа с модулем ядра ничем не отличается от работы с обычным файлом, естественно, учитывая специфику модуля и реализованные функции.

      Пример  программы для работы с модулем:

  1. #include <fcntl.h>      /* open */
  2. #include <unistd.h>     /* exit */
  3. #include <sys/ioctl.h>  /* ioctl */
  4.  
  5. main()
  6. {
  7.  
  8. int file_descret_val0;
  9.  
  10. char msg[] "Hello there!\n";
  11.  
  12. char msg2[] "One two three\n";
  13.  
  14. char bmsg[80];
  15.  
  16.  
  17. file_desc open(DEVICE_FILE_NAMEO_RDWR);
  18.   
  19. if (file_desc 0) {
  20.  
  21.   printf("Error opening %s\n"DEVICE_FILE_NAME);
  22.  
  23.   exit(-1);
  24.   
  25. }
  26.  
  27. ioctl(file_desc01);
  28.  
  29. write(file_descmsgsizeof(msg));
  30.  
  31. ioctl(file_desc02);
  32.  
  33. write(file_descmsg2sizeof(msg2));
  34.  
  35. ioctl(file_desc01);
  36.  
  37. lseek(file_desc30);
  38.  
  39. ret_val read(file_descbmsgsizeof(bmsg));
  40.  
  41. bmsg[ret_val"\0";
  42.   
  43. printf("-->");
  44.   
  45. printf(bmsg);
  46.   
  47. printf("\n");
  48.  
  49.  
  50. ioctl(file_desc0i++);
  51.  
  52. close(file_desc);
  53. }

     Функция ioctl – определяет в какой буфер происходит запись. В 17 строке выбираем буфер под номером 1. В следующей строке происходит запись в выбранный буфер. Далее происходит запись в буфер под номером 2. Команда lseek передвигает указатель чтения на +3 байта. Функция read в итоге вернет «lo there!».

 

Разработка  модуля ядра

      Разработка  модуля ядра проходит в несколько  этапов:

  1. создание простейшего модуля ядра;
  2. создание прототипов необходимых функций;
  3. реализация функций;
  4. организация обмена данными с пространством пользователя;
  5. реализация политики безопасности модуля ядра;
  6. организация работы с модулем ядра

Разработка  простейшего модуля ядра

      Для простейшего модуля ядра достаточно реализовать функцию инициализации и функцию деинициализации которые будут вызваны при загрузке модуля и соответственно его выгрузке.

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3.  
  4. int init_module(void)
  5. {
  6.  
  7.       printk("<1>Module loaded");
  8.  
  9.       return 0;
  10. }
  11.  
  12. void cleanup_module()
  13. {
  14.  
  15.       printk("<1>module removed");
  16. }

     Данный  код является полностью работоспособным  и выводит сообщения при подключении  модуля и его отключении.

Создание  прототипов функций

      Для модуля понадобятся функции: open, close, write, read, ioctl и lseek. Создадим прототипы этих функций. Аргументы и возвращаемые значения можно найти в struct file_operations.

  1. static int device_open(struct inode *inodestruct file *file)
  2. static int device_release(struct inode *inodestruct file *file)
  3. static ssize_t device_read(struct file *file, char __user buffersize_t lengthloff_t offset)
  4. static ssize_t device_write(struct file *fileconst char __user buffersize_t lengthloff_t offset)
  5. int device_ioctl(struct inode *inodestruct file *fileunsigned int ioctl_numunsigned long ioctl_param)
  6. static loff_t device_llseek(struct file *fileint loff_t)

     Прототипы реализованы, но как можно заметить, их имена не совпадают и именами  нужных нам функций, и даже если бы совпадали, их было бы невозможно вызвать. Для того чтобы иметь возможность  вызывать описанные функции необходимо определить экземпляр структуры  file_operations, где должны быть указаны ссылки на эти методы:

  1. struct file_operations Fops {
  2.  
  3. .read device_read,
  4.  
  5. .write device_write,
  6.  
  7. .unlocked_ioctl device_ioctl,
  8.  
  9. .open device_open,
  10.  
  11. .release device_release,
  12.  
  13. .llseek device_llseek
  14. };

     Следующий шаг это регистрация устройства,  должна происходить при инициализации модуля:

  1. register_chrdev(MAJOR_NUMDEVICE_NAME, &Fops);

     Теперь  можно быть уверенным, что функции будут вызваны. Но при выгрузке модуля, но все равно останется зарегистрированным, что может привести к ошибке. Чтобы этого избежать, нужно вызвать метод unregister_chrdev(MAJOR_NUM, DEVICE_NAME)  в методе cleanup_module.

Реализация  функций

      На  данном этапе реализуется логика модуля ядра, пример организации которой подробно рассматривается в главе «Работа пользовательского приложения с модулем ядра». Но некоторые функции не будут работать  правильно, пока не будет организована передача данных между пространством пользователя и ядра.

Организация обмена данных с пространством  пользователя

      Примером  функций для которых необходим обмен данными между пространством пользователя и пространством ядра могут служить функции write и read:

 

  1. static ssize_t device_write(struct file *file,
  2.  
  3.           const char __user buffersize_t lengthloff_t offset)
  4. {
  5.   
  6. int i;
  7.  
  8. printk("<1>device_write(%p,%s,%d)"filebufferlength);
  9.   
  10. switch (current_buffer) {
  11.   
  12. case 0:
  13.  
  14.   for (0length && BUF_LENi++)
  15.  
  16.     get_user(buf0[i]buffer i);
  17.  
  18.   break;
  19.  
  20.   
  21. case 1:
  22.  
  23.   for (0length && BUF_LENi++)
  24.  
  25.     get_user(buf1[i]buffer i);
  26.  
  27.   break;
  28.  
  29.   
  30. case 2:
  31.  
  32.   for (0length && BUF_LENi++)
  33.  
  34.     get_user(buf2[i]buffer i);
  35.  
  36.   break;
  37.   
  38. }
  39.  
  40. init_current_buffer();
  41.   
  42. return i;
  43. }
  44.  
  45. static ssize_t device_read(struct file *file, char __user buffersize_t lengthloff_t offset)
  46. {
  47.   
  48. int bytes_read 0;
  49.  
  50. printk("<1>device_read(%p,%p,%d)\n"filebufferlength);
  51.   
  52. if (*Message_Ptr == 0)
  53.  
  54.   return 0;
  55.   
  56. while (length && *Message_Ptr) {
  57.  
  58.   put_user(*(Message_Ptr++)buffer++);
  59.  
  60.   length--;
  61.  
  62.   bytes_read++;
  63.   
  64. }
  65.   
  66. return bytes_read;
  67. }

Информация о работе Разработка модуля для ядра Linux 2.6.38