Ядро Linux/Модулі

Матеріал з Вікіпідручника
Перейти до навігації Перейти до пошуку

Модуль ядра це код, який може завантажений у образ ядра при потребі, без необхідності перезборки ядра і перезавантаження комп'ютера. Модульна архітектура передбачає, що ядро не є монолітним і не включає кожен раз весь код необхідний для всіх можливих пристроїв і ситуацій роботи.

Як правило модулі ядра це драйвери пристроїв, які на прямую здійснюють доступ до комп'ютера і перефірійного обладнання.

Модулі ядра мають розширення файлу .ko дл ядра з версії 3.0.

Використання модулів[ред.]

Для того, щоб визначити всі завантажені модулі системи можна виконати команду lsmod, яка в свою чергу читає файл /proc/modules. Приклад результату, який повертає дана команда буде наступним:

Module                  Size  Used by
ctr                    13049  1 
ccm                    17773  1 
snd_hda_codec_hdmi     46368  1 
snd_hda_codec_cirrus    18855  1 
btusb                  32412  0 
hid_generic            12548  0 
arc4                   12608  2 
b43                   387371  0 
mac80211              630669  1 b43
hid_apple              13386  0 
bcm5974                17589  0 
joydev                 17381  0 
cfg80211              484040  2 b43,mac80211
ssb                    62379  1 b43
hid_holtek_mouse       12625  0 

Зауважте, що результат який надрукує команда lsmod як правило дуже довний і містить список з багатьох модулів. Цей приклад скорочено для зручності.

Для того, щоб додати модуль в ядро ви можете використовувати команду modprobe. Демон модуля ядра kmod, часто виконує modprobe для завантаження модулів. Команді modprobe передається строковий аргумент який може бути фактичним іменем модуля або псевдонім модуля. Modprode шукає файкл /proc/modprobe.conf аби знайти відповідність заданого псевдоніма із фактичним модулем. Для того, щоб визначити залежність модулів один від одного, modprobe шукає /lib/module/version/modules.dep і визначає які модулі необхідно завантажити перед тим як може бути завантажено заданий модуль. Файл modules.dep створюється за допомогою команди depmod -a, що визначає чи викликає відповідний модуль фукнції або змінні (символи), які визначені у інших модулях.

Якщо такі залежності є, то команда insmod завантажує їх перед тим як завантажити необхідний заданий модуль. Команда insmod потребує точного вказання шляху до імен файлів із зазначеними модулями, а modprobe не потребує. Ось приклад із завантаженням модуля "spidev.ko":

sudo modprobe spidev

Команди Modprobe, insmod і depmod знаходяться у module-init-tools або пакетах kmod.

Модулі, які вже завантажені перелічені у /proc/modules. Для того, щоб дізнатися інформацію про модуль у файлі modulename.ko використовуйте команду modinfo ім'я_модуля. Наприклад:

modinfo spidev

Зауважте, що ви не можете використовувати X, такі як xterm, оскільки ядро друкує свою інформацію прямо у консоль або у лог файли.

Написання і відлагодження модулів[ред.]

Простий модуль[ред.]

Найпростіший приклад коду модуля ядра:

#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
    printk(KERN_ALERT "Hello, world\n");
    return 0;
}
static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);

Модулі ядра повинні завжди містити ці дві функції, init_module і cleanup_module. Insmod викликає init_module коли він завантажує модулі до ядра, а rmsmod викликає функцію cleanup_module коли видаляє модуль. printk() це макрос логування, який використовуєтся ядром і має наданий йому пріорітет <1>. Пріорітети ядра, яких всього вісім, визначені у файлі kernel.h. Кожний пріорітет ядра має певне цільове призначення і відповідні визначення:

43 #define KERN_EMERG      "<0>"   /* system is unusable                   */
44 #define KERN_ALERT      "<1>"   /* action must be taken immediately     */
45 #define KERN_CRIT       "<2>"   /* critical conditions                  */
46 #define KERN_ERR        "<3>"   /* error conditions                     */
47 #define KERN_WARNING    "<4>"   /* warning conditions                   */
48 #define KERN_NOTICE     "<5>"   /* normal but significant condition     */
49 #define KERN_INFO       "<6>"   /* informational                        */
50 #define KERN_DEBUG      "<7>"   /* debug-level messages                 */

При використанні printk(), якщо при цьому будуть працювати syslogd і klogd, результат виводу printk() буде додано до /var/log/messages. Якщо printk() викликається із низьким пріоритетом, то його результат буде додано лише до /var/log/messages. Аби переконатися що вивід буде здійснюватися на консоль, використовуйте пріоритет KERN_ALERT.

Компіляція модуля[ред.]

Модуля ядра збираються дещо інакше ніж користувацький код. Ось приклад файлу збірки makefile:

obj-m += hello.o

all: modules

.DEFAULT:
	$(MAKE) -C $(KDIR) M=$$PWD $@

Ви можете зібрати свій простий модуль виконавши команду make.

Використовуючи макроси module_init() і module_exit() ви можете змінити імена функціям init_module() і cleanup_module(void).

Макрос __init звільняє пам'ять функції ініціалізації в модулі після вбудованого драйвера, наприклад, коли він був завантажений. Однак, це не відбувається при роботі modprobe. Цей макрос можна знайти в linux/init.h, і він корисний для управління пам'яттю. Макрос __initdata аналогічний __init, але використовується для змінних.

Макрос __exit не дозволяє завантажувати код cleanup_module під час ініціалізації, оскільки він не буде потрібний ядру, доки модуль використовується.

Макрос MODULE_LICENSE() дозволяє вам визначити ліцензування коду, і зазначити його для вашого коду.

MODULE_PARM() дозволяє передати параметри командного рядка, коли модуль буде ініціалізуватися за допомогою insmod.

Для того, щоб розділити модуль на декілька файлів, до файлу збірки треба додати наступне.

obj-m += hello.o
obj-m += startstop.o
startstop-objs := start.o stop.o

default: modules

.DEFAULT:
	$(MAKE) -C $(KDIR) M=$$PWD $@

Тестування модуля[ред.]

% make
make[1]: Entering directory `/usr/src/linux-2.6.10'
CC [M] /home/ldd3/src/misc-modules/hello.o
Building modules, stage 2.
MODPOST
CC /home/ldd3/src/misc-modules/hello.mod.o
LD [M] /home/ldd3/src/misc-modules/hello.ko
make[1]: Leaving directory `/usr/src/linux-2.6.10'
% su
root# insmod ./hello.ko
Hello, world
root# rmmod hello
Goodbye cruel world
root#

Посилання[ред.]