Думаю каждый начинающий разработчик ядра Линукс мечтает написать свой модуль ядра. В этой статье я постараюсь объяснить как это сделать максимально просто, оставив все хитрые приемы на потом.
Что нам нужно:
Пишем в текстовом редакторе код модуля, назовем файл hi.c Содержимое его будет такое:
Что бы автоматизировать процесс компилирования модуля нам понадобится Makefile. Создаем его в текстовом редакторе в том же каталоге где и файл hi.c Содержимое его такое:
Важно: В 9-ой и 12-ой строчке нужно поставить Tab вместо пробелов, иначе make выдаст ошибку об этом.
Пришло время скомпилировать наш модуль. Находясь в директории модуля, даем команду в терминале:
$ make build
Если все прошло успешно, вывод будет примерно такой:
В каталоге должен появится файл hi.ko Проверим все ли с ним в порядке:
$ modinfo hi.ko
Теперь все готово что бы загрузить наш первый модуль, для этого нужны привилегии root-а. Загружаем модуль командой в терминале:
# insmod hi.ko
Проверяем появился ли он в списке модулей:
$ lsmod | grep hi
$ tail /var/log/messages
Последними должны быть такие строчки:
Для выгрузки модуля используем команду:
# rmmod hi
Источник: The Kernel Newbie Corner: Your First Loadable Kernel Module
Что нам нужно:
- Пакеты разработчика вроде gcc, binutils и т. д. Ставятся командой:
# apt-get install build-essential - Дерево исходных кодов ядра. Устанавливается командой в терминале:
# apt-get install linux-headers-`uname -r`
Пакет скорее всего уже установлен. - Утилиты insmod, rmmod Устанавливаются командой в терминале:
# apt-get install module-init-tools
Пакет скорее всего уже установлен. - Привилегии root
Пишем в текстовом редакторе код модуля, назовем файл hi.c Содержимое его будет такое:
/* Module source file 'hi.c'. */
#include <linux/module.h> // используется для всех модулей
#include <linux/init.h> // макросы выгрузки/загрузки модуля
#include <linux/kernel.h> // для использования функции printk
#include <asm/current.h> // для получения информации о процессах
#include <linux/sched.h> // для "struct task_struct"
static int hi(void) // функция которая выполняется перед загрузкой модуля
{
printk(KERN_INFO "hi module being loaded.\n");
printk(KERN_INFO "User space process is '%s'\n", current->comm);
printk(KERN_INFO "User space PID is %i\n", current->pid);
return 0; // всегда 0 чтобы гарантировать загрузку модуля
}
static void bye(void) // функция которая выполняется перед выгрузкой модуля
{
printk(KERN_INFO "hi module being unloaded.\n");
}
module_init(hi); // привязываем функцию hi к моменту загрузки модуля
module_exit(bye); // привязываем функцию bye к моменту выгрузки модуля
MODULE_AUTHOR("Robert P. J. Day");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("You have to start somewhere.");
Что бы автоматизировать процесс компилирования модуля нам понадобится Makefile. Создаем его в текстовом редакторе в том же каталоге где и файл hi.c Содержимое его такое:
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
.PHONY: build clean
build:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
else
$(info Building with KERNELRELEASE = ${KERNELRELEASE})
obj-m := hi.o
endif
Важно: В 9-ой и 12-ой строчке нужно поставить Tab вместо пробелов, иначе make выдаст ошибку об этом.
Пришло время скомпилировать наш модуль. Находясь в директории модуля, даем команду в терминале:
$ make build
Если все прошло успешно, вывод будет примерно такой:
make -C /lib/modules/2.6.28-11-generic/build M=/home/user1 modules make[1]: Вход в каталог `/usr/src/linux-headers-2.6.28-11-generic' Building with KERNELRELEASE = 2.6.28-11-generic CC [M] /home/user1/hi.o Building modules, stage 2. Building with KERNELRELEASE = 2.6.28-11-generic MODPOST 1 modules CC /home/user1/hi.mod.o LD [M] /home/user1/hi.ko make[1]: Выход из каталога `/usr/src/linux-headers-2.6.28-11-generic'
В каталоге должен появится файл hi.ko Проверим все ли с ним в порядке:
$ modinfo hi.ko
filename: hi.ko description: You have to start somewhere. license: Dual BSD/GPL author: Robert P. J. Day srcversion: A322C53DF6FAC6058130CF7 depends: vermagic: 2.6.28-11-generic SMP mod_unload modversions 586
Теперь все готово что бы загрузить наш первый модуль, для этого нужны привилегии root-а. Загружаем модуль командой в терминале:
# insmod hi.ko
Проверяем появился ли он в списке модулей:
$ lsmod | grep hi
hi 9600 0 ← вот он наш модуль usbhid 42336 0
Что касается функции printk которую мы использовали при написании модуля. Первое правило разработчика ядра: из ядра вы не можете нормально работать с пользовательским пространством, поэтому не стоит ожидать вывода функции printk прямо в терминал. Эта функция пишет данные напрямую в стандартный файл сообщений syslog-а, который обычно находится по адресу /var/log/messages. Можно посмотреть, что туда записал модуль например так:
$ tail /var/log/messages
Последними должны быть такие строчки:
Jul 13 09:58:16 host1 kernel: [ 2137.925382] hi module being loaded. Jul 13 09:58:16 host1 kernel: [ 2137.925386] User space process is 'insmod' Jul 13 09:58:16 host1 kernel: [ 2137.925389] User space PID is 5167
Для выгрузки модуля используем команду:
# rmmod hi
Источник: The Kernel Newbie Corner: Your First Loadable Kernel Module