Как стать автором
Поиск
Написать публикацию
Обновить

Пишем модуль ядра Линукс

Думаю каждый начинающий разработчик ядра Линукс мечтает написать свой модуль ядра. В этой статье я постараюсь объяснить как это сделать максимально просто, оставив все хитрые приемы на потом.

Что нам нужно:
  • Пакеты разработчика вроде 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
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.