logo

Програмування модуля ядра Linux: програма Hello World

Модулі ядра — це фрагменти коду, які можна завантажувати та вивантажувати в ядро ​​на вимогу. Вони розширюють функціональність ядра без необхідності перезавантаження системи. Користувацькі коди можна додати до ядра Linux двома способами.
  • Основний спосіб — додати код до дерева вихідних кодів ядра та перекомпілювати ядро.
  • Більш ефективним способом є додавання коду до ядра під час його роботи. Цей процес називається завантаженням модуля, де модуль посилається на код, який ми хочемо додати до ядра.
Оскільки ми завантажуємо ці коди під час виконання, і вони не є частиною офіційного ядра Linux, вони називаються завантажуваним модулем ядра (LKM), який відрізняється від базового ядра. Базове ядро ​​знаходиться в каталозі /boot і завжди завантажується під час завантаження нашої машини, тоді як LKM завантажуються після того, як базове ядро ​​вже завантажено. Тим не менш, ці LKM є значною частиною нашого ядра, і вони взаємодіють із базовим ядром для виконання своїх функцій. LKM можуть виконувати різноманітні завдання, але в основному вони діляться на три основні категорії
  • драйвер пристрою
  • драйвер файлової системи і
  • Системні виклики.
Отже, які переваги пропонують LKM? Однією з головних переваг у них є те, що нам не потрібно постійно перебудовувати ядро ​​кожного разу, коли ми додаємо новий пристрій або оновлюємо старий пристрій. Це економить час, а також допомагає утримувати наше базове ядро ​​без помилок. Корисним емпіричним правилом є те, що ми не повинні змінювати наше базове ядро, якщо у нас є робоче базове ядро. Також це допомагає діагностувати системні проблеми. Наприклад, припустимо, що ми додали модуль до базового ядра (тобто ми змінили наше базове ядро, перекомпілювавши його), і в модулі є помилка. Це спричинить помилку під час завантаження системи, і ми ніколи не дізнаємося, яка частина ядра викликає проблеми. Тоді як якщо ми завантажуємо модуль під час виконання, і це спричиняє проблеми, ми одразу дізнаємося про проблему та можемо вивантажити модуль, доки не виправимо її. LKM є дуже гнучкими в тому сенсі, що їх можна завантажувати та розвантажувати за допомогою однієї командної лінії. Це допомагає економити пам’ять, оскільки ми завантажуємо LKM лише тоді, коли вони нам потрібні. Крім того, вони не повільніші за базове ядро, оскільки виклик будь-якого з них є просто завантаженням коду з іншої частини пам’яті. **Попередження: LKM не є космічними програмами користувача. Вони є частиною ядра. Вони мають вільний запуск системи і можуть легко вивести її з ладу. So now that we have established the use loadable kernel modules we are going to write a hello world kernel module. That will print a message when we load the module and an exit message when we unload the module. Code: CPP
/**  * @file hello.c  * @author Akshat Sinha  * @date 10 Sept 2016  * @version 0.1  * @brief An introductory 'Hello World!' loadable kernel  * module (LKM) that can display a message in the /var/log/kern.log  * file when the module is loaded and removed. The module can accept  * an argument when it is loaded -- the name which appears in the  * kernel log files. */ #include  /* Needed by all modules */ #include  /* Needed for KERN_INFO */ #include  /* Needed for the macros */ ///< The license type -- this affects runtime behavior MODULE_LICENSE('GPL'); ///< The author -- visible when you use modinfo MODULE_AUTHOR('Akshat Sinha'); ///< The description -- see modinfo MODULE_DESCRIPTION('A simple Hello world LKM!'); ///< The version of the module MODULE_VERSION('0.1'); static int __init hello_start(void) {  printk(KERN_INFO 'Loading hello module...n');  printk(KERN_INFO 'Hello worldn');  return 0; } static void __exit hello_end(void) {  printk(KERN_INFO 'Goodbye Mr.n'); } module_init(hello_start); module_exit(hello_end); 
Пояснення до коду вище: Модулі ядра повинні мати принаймні дві функції: функцію «початку» (ініціалізації) під назвою init_module(), яка викликається, коли модуль вбудовано в ядро, і функцію «завершення» (очищення) під назвою cleanup_module(), яка викликається безпосередньо перед тим, як його перейти в режим rmmoding. Насправді все змінилося, починаючи з ядра 2.3.13. Тепер ви можете використовувати будь-яку назву для початкової та кінцевої функцій модуля. Фактично, новий метод є кращим. Однак багато людей все ще використовують init_module() і cleanup_module() для своїх початкових і кінцевих функцій. У цьому коді ми використали hello_start() як функцію ініціалізації та hello_end() як функцію очищення. Ще одна річ, яку ви могли помітити, це те, що замість функції printf() ми використали printk(). Це пояснюється тим, що модуль нічого не друкуватиме на консолі, але реєструватиме повідомлення в /var/log/kern.log. Тому він використовується для налагодження модулів ядра. Крім того, існує вісім можливих рядків рівня журналу, визначених у заголовку, які потрібні під час використання printk(). Ми перерахували їх у порядку зменшення серйозності:
  • KERN_EMERG: Використовується для екстрених повідомлень, зазвичай тих, які передують аварії.
  • KERN_ALERT: Ситуація, що вимагає негайної дії.
  • KERN_CRIT: Критичні умови, які часто пов’язані з серйозними збоями апаратного чи програмного забезпечення.
  • KERN_ERR: Використовується для повідомлення про умови помилки; драйвери пристроїв часто використовують KERN_ERR для повідомлення про апаратні проблеми.
  • KERN_WARNING: попередження про проблемні ситуації, які самі по собі не створюють серйозних проблем із системою.
  • KERN_NOTICE: нормальні ситуації, які все ж варті уваги. На цьому рівні повідомляється про низку умов, пов’язаних із безпекою.
  • KERN_INFO: Інформаційні повідомлення. Багато драйверів друкують інформацію про обладнання, яке вони знаходять під час запуску на цьому рівні.
  • KERN_DEBUG: Використовується для повідомлень налагодження.
  • Ми використали KERN_INFO для друку повідомлення. Підготовка системи до виконання коду: The system must be prepared to build kernel code and to do this you must have the Linux headers installed on your device. On a typical Linux desktop machine you can use your package manager to locate the correct package to install. For example under 64-bit Debian you can use:
    akshat@gfg:~$ sudo apt-get install build-essential linux-headers-$(uname -r) 
    Makefile для компіляції вихідного коду:
    obj-m = hello.o all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 
    **Примітка: не забудьте про простори вкладок у Makefile Компіляція та завантаження модуля: Run the make command to compile the source code. Then use insmod to load the module.
    akshat@gfg:~$ make make -C /lib/modules/4.2.0-42-generic/build/ M=/home/akshat/Documents/hello-module modules make[1]: Entering directory `/usr/src/linux-headers-4.2.0-42-generic' CC [M] /home/akshat/Documents/hello-module/hello.o Building modules stage 2. MODPOST 1 modules CC /home/akshat/Documents/hello-module/hello.mod.o LD [M] /home/akshat/Documents/hello-module/hello.ko make[1]: Leaving directory `/usr/src/linux-headers-4.2.0-42-generic' 
    Now we will use insmod to load the hello.ko object.
    akshat@gfg:~$ sudo insmod hello.ko 
    Тестування модуля: You can get information about the module using the modinfo command which will identify the description author and any module parameters that are defined:
    akshat@gfg:~$ modinfo hello.ko filename: /home/akshat/Documents/hello-module/hello.ko version: 0.1 description: A simple Hello world LKM author: Akshat Sinha license: GPL srcversion: 2F2B1B95DA1F08AC18B09BC depends: vermagic: 4.2.0-42-generic SMP mod_unload modversions 
    To see the message we need to read the kern.log in /var/log directory.
    akshat@gfg:~$ tail /var/log/kern.log ... ... Sep 10 17:43:39 akshat-gfg kernel: [26380.327886] Hello world To unload the module we run rmmod: akshat@gfg:~$ sudo rmmod hello Now run the tail command to get the exit message. akshat@gfg:~$ tail /var/log/kern.log ... Sep 10 17:43:39 akshat-gfg kernel: [26380.327886] Hello world Sep 10 17:45:42 akshat-gfg kernel: [26503.773982] Goodbye Mr.