Єдина Країна! Единая Страна!

Розробка для ядра Linux — 1. printk(“Привіт, світе!\n”)

Червень 14th, 2010

Я нещодавно серйозно (як мені здається) взявся за вивчення такої крутої штукенції, як “Linux kernel development”. Я вихований девізом “I’ve learned. I’ll share”, тому спробую ділитись новою для мене інформацією з вами.

На жаль, у мене немає ані часу, ані бажання розжовувати кожну тему, до того ж, теоретичного матеріалу, як мені здається, предостатньо. У мене найбільші проблеми виникають при пошуку достатньо простих для розуміння прикладів. На них я і спробую зосередити свою увагу…


І одразу ж почнемо з традиційної програми “Hello, world!”, якою у даному випадку є модуль ядра, котрий одразу ж після завантаження виводить на консоль те саме “Hello, world!”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <linux/init.h>
#include <linux/module.h>
 
MODULE_AUTHOR("Oleksandr Kravchuk");
MODULE_LICENSE("WTFPL");
MODULE_DESCRIPTION("Very simple Linux kernel module.");
 
static int __init hello_init(void)
{
        printk(KERN_ALERT "Hello, world\n");
 
        return 0;
}
 
static void __exit hello_exit(void)
{
        printk(KERN_ALERT "Goodbye, stupid world\n");
}
 
module_init(hello_init);
module_exit(hello_exit);

Даний модуль містить дві функції, одна (hello_init) виконується після завантаження модуля, інша — перед його вивантаженням (hello_exit). Макроси module_init та module_exit позначають функції, даючи їм відповідне призначення у нашому модулі. Інші спеціальні макроси (MODULE_AUTHOR, MODULE_LICENSE та MODULE_DESCRIPTION) використовуються для того, щоб розповісти ядру про наш модуль, а саме — про його автора, ліцензії та призначення; обов’язковим є лише один із низ — MODULE_LICENSE, без оголошення якого ядро відмовиться завантажити модуль (ви ж чудово знаєте, на скільки болючою для нас є тема ліцензій).

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

Функція printk() оголошена у самому ядрі Linux; вона є майже повним аналогом функції стандартної бібліотеки мови С, printf(). Модулю потрібна власна функція, оскільки воно запускається власноруч, без допомови стандартної бібліотеки С. Модуль може викликати функцію printk() через те, що після завантаження ядром модуля, останній лінкуєтьс з ядром, і отримує змогу доступатись до загальнодоступних символів ядра (функції та змінні). Стрічка KERN_ALERT вказує на пріорітет повідомлення.

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

1
2
3
4
5
6
7
8
obj-m := hello.o
 
KERNELDIR := /lib/modules/`uname -r`/build
 
all:
        $(MAKE) -C $(KERNELDIR) SUBDIRS=$(CURDIR) modules
clean:
        rm -rf $(obj-m) $(obj-m:.o=.mod.c) $(obj-m:.o=.mod.o)

Підвантаження і вивантаження модулів

Усе це щастя робиться за допомогою наступних знадобів:

  • insmod — підвантажує модуль до ядра Linux
  • modprobe — підвантажує, а потім одразу ж вивантажує модуль, корисно для перевірки працездатності модуля
  • rmmod — вивантажує модуль з ядра Linux
  • lsmod — виводить перелік усіх нині підвантажених ядром модулів

Перевіряємо наш модуль

# sudo insmod ./hello.ko
# sudo dmesg | tail
# sudo rmmod hello

Додаткові матеріали

  • LDD3 — Chapter 2. Building and Running Modules
  • Linux kernel coding style

    Коментарі

    коментарі

    Powered by Facebook Comments

  • 2 коментарі to “Розробка для ядра Linux — 1. printk(“Привіт, світе!\n”)”

    1. Artem Says:

      Саша, ты был когда Андрущман говорил про модификаторы __init и __exit? 😉

    2. Oleksandr Kravchuk Says:

      Артеме, дякую за рев’ю коду. Винен, виправив!

    Leave a Reply