Разработка модуля для ядра Linux 2.6.38
Курсовая работа, 03 Октября 2011, автор: пользователь скрыл имя
Краткое описание
Модуль - это некий код, который может быть загружен или выгружен ядром по мере необходимости[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 Кб (Скачать)Как можно заметить с данными, адрес которых передается в функцию, можно работать только с помощью методов get_user и put_user.
Реализация политики безопасности
Чтобы избежать ошибок при подключении нескольких пользовательских процессов к модулю ядра, а так же предотвратить выгрузку модуля во время использования необходимо реализовать политику безопасности.
Для
предотвращения использования модуля
двумя и более
- static int device_open(struct
inode *inode, struct file *file ) - {
- if (Device_Open)
- return -EBUSY;
- Device_Open++;
- return SUCCESS;
- }
- static int device_release(stru
ct inode *inode, struct file *file ) - {
- Device_Open--;
- return SUCCESS;
- }
Для предотвращения выгрузки модуля во время использования существуют стандартные механизмы. Все что необходимо сделать это вызвать методы try_get_module во время начала использования модуля и put_module в конце использования. Если произойдет ошибка при вызове этих методов, модуль может быть никогда не выгружен.
- static int device_open(struct
inode *inode, struct file *file ) - {
- if (Device_Open)
- return -EBUSY;
- Device_Open++;
- try_module_get(THIS_MODULE);
- return SUCCESS;
- }
- static int device_release(stru
ct inode *inode, struct file *file ) - {
- Device_Open--;
- module_put(THIS_MODULE);
- return SUCCESS;
- }
Организация работы с модулем ядра
Не смотря на то что модуль полностью готов и скомпилирован мы не можем его использовать пока не будет создан файл устройства. Для его создания вызовем в консоли стандартную утилиту mknod. Подробно данный процесс описан в главе «Создание файла устройства».
Заключение
В ходе данной работы был разработан модуль для ядра Linux 2.6.38 и пользовательское приложение для демонстрации возможностей работы модуля ядра. Были изучены основы создания модулей и особенности работы с файлами устройств.
Основные сложности при выполнении данной работы возникали с тем, что информация по работе с модулями ядра быстро устаревает, и приемы, которые работали в одной версии, ядра уже не работают в другой. Новые версии ядра Linux выходят очень часто, и большая часть информации устаревает еще до ее перевода на русский язык.
Библиографический список
- Михаэль Кофлер Linux. Полное руководство. – СПб.: Питер, 2011. – 800с.
- Роберт Лав Разработка ядра Linux. – М.: Вильямс, 2008. – 448с.
- Ори Померанц Ядро Linux. Программирование модулей. – М.: КУДИЦ-Образ, 2002. – 112с.
- В. Б. Иванов Прикладное программирование на С/С++. С нуля до мультимедийных и сетевых приложений. – М.: Солон-пресс, 2008. – 240с.
- Arnold Robbins Bash Pocket Reference. O'Reilly Media, 2010. – 132с.
Приложение
Структура file_operations для ядра Linux 2.6.38
- struct file_operations {
- struct module *owner;
- loff_t (*llseek) (struct file
*, loff_t, int); - ssize_t (*read) (struct file *
, char __user *, size_t, loff_t *); - ssize_t (*write) (struct file
*, const char __user *, size_t, loff_t *); - ssize_t (*aio_read) (struct ki
ocb *, const struct iovec *, unsigned long , loff_t); - ssize_t (*aio_write) (struct k
iocb *, const struct iovec *,unsigned long , loff_t); - int (*readdir) (struct file *,
void *, filldir_t); - unsigned int (*poll) (struct f
ile *, struct poll_table_struct *); - long (*unlocked_ioctl) (struct
file *, unsigned int, unsigned long ); - long (*compat_ioctl) (struct f
ile *, unsigned int, unsignedlong ); - int (*mmap) (struct file *, st
ruct vm_area_struct *); - int (*open) (struct inode *, s
truct file *); - int (*flush) (struct file *, f
l_owner_t id ); - int (*release) (struct inode *
, struct file *); - int (*fsync) (struct file *, i
nt datasync); - int (*aio_fsync) (struct kiocb
*, int datasync); - int (*fasync) (int, struct fil
e *, int); - int (*lock) (struct file *, in
t , struct file_lock *); - ssize_t (*sendpage) (struct fi
le *, struct page *, int, size_t , loff_t *, int); - unsigned long (*get_unmapped_
area )(struct file *, unsignedlong , unsigned long, unsignedlong , unsigned long); - int (*check_flags)(int);
- int (*flock) (struct file *, i
nt , struct file_lock *); - ssize_t (*splice_write)(struct
pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int ); - ssize_t (*splice_read)(struct
file *, loff_t *, struct pipe_inode_info *, size_t, unsignedint ); - int (*setlease)(struct file *,
long, struct file_lock **); - long (*fallocate)(struct file
* file, int mode, loff_t offset,loff_t len); - };
Код модуля ядра
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <asm/uaccess.h>
- #include "chardev.h"
- #define SUCCESS 0
- #define DEVICE_NAME "char_dev"
- #define BUF_LEN 80
- static int Device_Open = 0;
- static int current_buffer;
- static int init_current_buffer
( void); - static char buf0[BUF_LEN], buf
1 [BUF_LEN], buf2[BUF_LEN], buf_temp [BUF_LEN]; - static char *Message_Ptr;
- static int device_open(struct
inode *inode, struct file *file ) - {
- printk("device_open(%p)\n", fi
le ); - if (Device_Open)
- return -EBUSY;
- Device_Open++;
- Message_Ptr = buf0;
- try_module_get(THIS_MODULE);
- return SUCCESS;
- }
- static int device_release(stru
ct inode *inode, struct file *file ) - {
- printk("<1>device_release(%p,%
p) \n", inode, file); - Device_Open--;
- module_put(THIS_MODULE);
- return SUCCESS;
- }
- static ssize_t device_read(struct file *file,
char __user * buffer, size_t length, loff_t * offset) - {
- int bytes_read = 0;
- printk("<1>device_read(%p,%p,%
d) \n", file, buffer, length); - if (*Message_Ptr == 0)
- return 0;
- while (length && *Message_Ptr)
{ - put_user(*(Message_Ptr++), buf
fer ++); - length--;
- bytes_read++;
- }
- return bytes_read;
- }
- static ssize_t device_write(struct file *file
, -
const char __user * buffer,
size_t length , loff_t * offset) - {
- int i;
- printk("<1>device_write(%p,%s,
%d)" , file, buffer, length); - switch (current_buffer) {
- case 0:
- for (i = 0; i < length && i
< BUF_LEN; i++) - get_user(buf0[i], buffer + i);
- break;
- case 1:
- for (i = 0; i < length && i
< BUF_LEN; i++) - get_user(buf1[i], buffer + i);
- break;
- case 2:
- for (i = 0; i < length && i
< BUF_LEN; i++) - get_user(buf2[i], buffer + i);
- break;
- }
- init_current_buffer();
- return i;
- }
- int device_ioctl(struct inode
* inode, - struct file *file,
- unsigned int ioctl_num,
- unsigned long ioctl_param)
- {
- current_buffer = ioctl_num;
- init_current_buffer();
- printk("<1>set buf num %d\n", ioctl_num);
- return SUCCESS;
- }
- static loff_t device_llseek(struct file *fil
e , int loff_t) - {
- init_current_buffer();
- Message_Ptr += loff_t;
- printk("<1>set position %d\n", loff_t);
- return SUCCESS;
- }
- struct file_operations Fops = {
- .read = device_read,
- .write = device_write,
- .unlocked_ioctl = device_ioctl
, - .open = device_open,
- .release = device_release,
- .llseek = device_llseek
- };
- int init_module()
- {
- int ret_val;
- ret_val = register_chrdev(MAJO
R_NUM , DEVICE_NAME, &Fops); - if (ret_val < 0) {
- printk("%s failed with %d\n",
- "Sorry, registering the character device ", ret_val);
- return ret_val;
- }
- printk("mknod
%s c %d 0\n", DEVICE_FILE_NAME, MAJOR_
NUM ); - return 0;
- }
- static int init_current_buffer
(){ - int i;
- switch (current_buffer) {
- case 0:
- Message_Ptr = buf0;
- break;
- case 1:
- Message_Ptr = buf1;
- break;
- case 2:
- Message_Ptr = buf2;
- break;
- }
- return 0;
- }
- void cleanup_module()
- {
- int ret;
- unregister_chrdev(MAJOR_NUM, D
EVICE_NAME ); - }