This is an old revision of the document!


Задание по написанию модуля ядра

Формулировка задания

Реализовать модуль ядра, который регистрирует символьное устройство с именем “math”. Устройство должно предоставлять возможность взаимодействия с ним с помощью системного вызова ioctl(int fd, unsigned int cmd, unsigned long arg). Первый аргумент — файловый дескриптор, второй — номер команды, третий — адрес области памяти в пространстве пользователя (для иных устройств это произвольный аргумент). Область памяти должна содержать массив элементов типа int. Обработчик каждой команды должен считывать из адресного пространства пользователя аргумент(-ы), вычислять результат и записывать его в область памяти, следующую за последним аргументом. К примеру, MATH_IOCTL_SUM считывает аргументы по адресам arg и arg+sizeof(int), а записывает результат по адресу arg+2*sizeof(int).

Это устройство должно отвечать на несколько команд системного вызова ioctl(2):

  • MATH_IOCTL_SQR — возводит в квадрат единственный аргумент
  • MATH_IOCTL_NEG — меняет знак единственного аргумента
  • MATH_IOCTL_ADD — складывает два аргумента
  • MATH_IOCTL_SUB — вычитает второй аргумент из первого
  • MATH_IOCTL_MUL — умножает два аргумента
  • MATH_IOCTL_DIV — делит первый аргумент на второй

Требования к модулю

  • Модуль должен быть выгружаемым.
  • Модуль должен использовать определения команд MATH_IOCTL_XXX из файла math.h.
  • Модуль должен предоставлять возможность одновременной работы с символьным устройством 4 пользователям. Пятому пользователю (и последующим) на попытку открыть файл должен возвращаться код ошибки EBUSY.
  • Одновременное использование символьного устройства не должно приводить к гонкам (race condition).
  • Обработчик ioctl должен проверять входные данные и предотвращать целочисленные переполнения, деление на ноль и другие ошибки. Если аргументы пользователя некорректны, ему необходимо вернуть код ошибки EINVAL.
  • Для взаимодействия с памятью пользователя необходимо использовать функции из набора get_user, put_user, copy_to_user, copy_from_user.

Материалы к заданию

  • Исходный код утилиты math_ctl, с помощью которой можно проверить работоспособность символьного устройства.
  • Makefile для сборки модуля и утилиты math_ctl. Для сборки выполните команду “make” без аргументов, для загрузки модуля выполните “make insert_module”.
  • Заготовка исходного файла модуля с указанием стандартных заголовочных файлов.
  • Заголовочный файл с определением констант MATH_IOCTL_XXX.

Ссылка на архив: ftp://dione.intelib.org/pub/segoon/math.tar.gz

Советы

  • Для упрощения отладки используйте pr_info(), печатающую отладочную информацию в системный лог (либо другие функции из семейства printk). Лог можно прочитать с помощью консольной команды dmesg.
  • Для работы с символьным устройством используйте функции register_chrdev() и unregister_chrdev(). Из файловых операций структуры file_operations необходимо реализовать лишь методы open (вызывается при попытке открытия файла), release (вызывается при закрытии файлового дескриптора), unlocked_ioctl (вызывается при соответствующем системном вызове ioctl(2)). Остальные поля структуры file_operations для задания не важны.
  • Для ограничения числа пользователей рекомендуется использовать атомарные переменные.
  • Для сборки модуля требуются заголовочные файлы ядра. В дистрибутивах линукс семейства Debian (Debian, Ubuntu, Mint, …) для их установки требуется пакет linux-headers-generic. В дистрибутивах семейства Fedora требуется пакет kernel-devel.
  • Помните, что код ядра должен возвращать код ошибки в виде отрицательного значения для отличия от успешного (неотрицательного) результата. Пользовательский код преобразует это отрицательное значение в первоначальный код ошибки. Например, если ядро хочет вернуть код ошибки EBUSY, то соответствующая команда должна быть “return -EBUSY”, а не “return EBUSY”.
  • Если не понятно, как реализовать ту или иную команду, посмотрите в код утилиты math_ctl. Возможно, по коду пользователя этой команды вы поймёте, как нужно действовать.
  • Учтите, что адрес переменной типа int в адресном пространстве процесса имеет тип “int __user *”, а не “int *”. Макрос ”__user” используется для нахождения небезопасного разыменования пользовательского указателя.

Сдача решений

Решённое задание отправляйте на почту segooon AT gmail.com.

При возникновении проблем компиляции, отладки или других проблем пишите на тот же адрес.

Второе задание по написанию модуля ядра

Задание является факультативным.

Формулировка задания

Реализовать модуль ядра, который регистрирует символьное устройство с именем “prime”. Устройство должно предоставлять возможность взаимодействия с помощью системного вызова read.

При чтении с помощью системного вызова read устройство выдаёт последовательность простых чисел типа uint64_t. Устройство сохраняет информацию о том, сколько чисел было считано и при последовательных вызовах read выдаёт продолжение прерванной последовательности. Вызов read с размером буфера, не кратным 8 (sizeof(uint64_t)), обрабатывается как ошибочный.

Возможно использование устройства более чем одним пользователем. При этом каждый пользователь считывает свою последовательность простых чисел независимо от других пользователей.

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

 
linux-kernel-internals/task.1366916726.txt.bz2 · Last modified: 2013/04/25 19:05 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license:GNU Free Documentation License 1.2
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki