Search
Write a publication
Pull to refresh

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

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

Что нам нужно:
  • Пакеты разработчика вроде 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
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.