Первый модуль ядра на C и инструменты для его разглядывания • Live coding

“Hello, world!” для модулей ядра (читай — будущих драйверов). Напишем. Запустим. Отладим. Разглядим под микроскопом. Linux only, зато очень разный Linux. И конечно, C — точней, то, что от него осталось на пути к системному программированию. Таймлайн: 00:00 – Введение: тема — модули ядра, учимся на практике 00:51 – Особенности ядра: это "почти C", но на деле — другой мир 01:42 – Логическая схема: реальное устройство «железо–ядро–приложение» 02:53 – Почему нужны драйверы: связь приложения с железом 04:04 – Модули ядра: зачем, как, где в системе 05:05 – Напоминание: как устроено физическое железо 06:06 – Зачем модуль: операционка общается с драйверами через API 07:11 – Противопоставление: теория vs. практика — побеждает практика 08:07 – Первый модуль: Hello World ядра — пустой модуль 09:03 – Разбор структуры модуля: нет `main()`, вместо него `init/exit` 10:02 – `module_init` и `module_exit`: макросы, не функции 11:02 – Вопросы по структуре: зачем возвращаемое значение, зачем лицензия 12:29 – Возвращаемое значение в `init`, но не в `exit`: почему 13:14 – Пустой модуль — но уже масса нюансов 14:00 – Попытка компиляции — не работает: не видит заголовков 15:03 – Почему не работает: нужны заголовки ядра и правильный способ сборки 16:04 – Решение: `Makefile`, который делегирует сборку ядру 17:05 – Объяснение: как работает `make -C /lib/modules/.../build` 18:50 – `obj-m` в Makefile: как передаётся имя модуля 19:16 – Где искать правильный `Makefile`: `uname -r` помогает 20:10 – Путь к заголовкам и сборочной среде ядра 21:04 – Зачем использовать системный `Makefile`: не изобретаем велосипед 22:01 – Просмотр содержимого `Makefile` ядра: внушительный масштаб 23:00 – Заголовки ядра: где искать и почему важны версии 24:05 – Модули привязаны к конкретной версии ядра — нельзя взять чужой 25:00 – Проверка результата компиляции: появился `.ko`-файл 26:13 – Что такое `.ko`: объектный файл, специфичный для ядра 27:05 – Устраняем варнинги: компилятор должен совпадать с ядром 28:05 – Как найти используемый компилятор: `boot/config-*` 29:03 – Извлечение параметров ядра: 12.500 настроек в `boot/config` 30:20 – Проверка результата: меньше варнингов, модуль собран 31:06 – Демонстрация: если нет заголовков — ничего не получится 32:14 – Установка заголовков: одна команда решает проблему 33:01 – Проверка `modinfo` и `nm`: `.ko` содержит всё нужное ядру 35:03 – Загрузка модуля: `insmod`, проверка через `lsmod` 36:14 – Удаление модуля: `rmmod`, снова `lsmod` — модуль выгружен 37:01 – Результат: пока что модуль делает ничего — но работает 38:13 – Повтор сборки на другой системе: компилируется, подключается 39:15 – Печатаем в лог ядра: `printk()` вместо `printf()` 40:48 – `printk()` — лог ядра, а не вывод в stdout 41:27 – Где читать логи: `dmesg`, `/var/log/kern.log` 42:02 – Первый работающий `printk()` — Hello и Goodbye 43:22 – Подключение и отключение: проверка, всё сработало 44:01 – `printk()` и уровни логирования: `KERN_INFO`, `KERN_ERR` и т.д. 45:42 – Документация `printk()`: форматирование, спецификаторы 47:08 – Форматы указателей в ядре: `%p`, `%x`, `%k`, `%llx` 48:02 – Синтаксис уровней логов: макросы `KERN_*` + сообщение 49:05 – Отказ от загрузки модуля через `return -1`: безопасный способ дебага 50:21 – Пример с уровнями логов: визуально отличаются в `dmesg` 51:41 – Наглядное демо: все уровни раскрашены в `dmesg` 52:05 – Особенности ядра: терминалы, которые нельзя показать на стриме 53:01 – Последний пример: вывод адресов через `printk()` 54:15 – Вложенные функции: `gcc`-специфика, но часто используется 55:22 – Вывод указателей в разных форматах: пример `printk()` со всеми `%p*` 56:11 – Вывод таблички адресов: всё видно, всё работает 56:46 – Финал: `Hello World`, но для ядра — это уже большое дело 57:12 – Завершение: в следующий раз продолжим с новой функциональностью Конспект:

Смотрите также