
Представляем книгу Олега Цилюрика “Расширения ядра Linux: драйверы и модули”. В книге подробно рассмотрено программирование драйверов ядра Linux, исследованы возможности расширяемости ядра при помощи модулей. Основная версия ядра – 5.15. Код примеров отработан и проверен на десятках различных инсталляций Linux, установленных из различных дистрибутивов и разных семейств дистрибутивов: Fedora, CentOS, Debian, Ubuntu, Mint. Уделено внимание архитектурам x_64, x_86, ARM, а также одноплатному компьютеру Raspberry Pi и драйверам устройств, подключаемых по USB. Затронут стандарт POSIX, разобраны API ядра, работа с Raspberry Pi, системные вызовы и подключение разнообразных периферийных устройств.
Ядро Linux — шедевр низкоуровневого кода на языке C. Разработка ядра не прекращается уже почти 30 лет, и занимается этим глобальное сообщество энтузиастов и профессионалов. Системные вызовы ядра Linux, тонкости управления памятью или параллельная обработка запросов – все эти темы важны сами по себе и в совокупности, но есть и ещё одна важная тема, до сих пор освещённая на русском языке фрагментарно и неравномерно: программирование драйверов и модулей ядра.
Именно этой теме посвящён фундаментальный труд, впервые публикуемый в качестве отдельной книги. Он зародился в начале 2000-х как материал для корпоративного курса и постоянно обновлялся вплоть до ноября 2022 года – и в данной версии выходит на бумаге. Новейшая версия ядра, учтённая в книге, – 5.15.
В книге подробно разобраны API ядра, системные вызовы, обработка сигналов, взаимодействия с периферийными устройствами и, в частности, с протоколом USB. Уделено внимание процессорным архитектурам x_64, x_86, ARM, а также одноплатному компьютеру Raspberry Pi и драйверам внешних устройств. Рассмотрена конфигурация и загрузка модулей и всевозможные варианты кастомизации ядра, рассмотрен стандарт POSIX.
Книга ориентирована на опытных программистов и системных администраторов, работающих с Linux. Призвана послужить достойным аналогом и дополнением классической работы «Драйверы устройств Linux. 3-е издание» Джонатана Корбетта и соавторов (Corbet J., Rubini A., Kroah-Hartman G. Linux Device Drivers, 3rd Edition).
Хорошая книга не дарит тебе откровение, хорошая книга укрепляет тебя в твоих самостоятельных догадках.
Андрей Рубанов, «Хлорофилия»
От автора……………………………………………………………………………………………….. 11
Предыстория………………………………………………………………………………………………………………………………. 11
Кому адресована книга?…………………………………………………………………………………………………………… 13
Структура книги………………………………………………………………………………………………………………………… 15
Соглашения, принятые в тексте………………………………………………………………………………………………… 18
Код примеров и замеченные опечатки…………………………………………………………………………………….. 19
Замечания о версиях ядра…………………………………………………………………………………………………………. 22
Обновляемость ядра………………………………………………………………………………………………………………….. 23
Использованные источники информации………………………………………………………………………………… 25
Обновления текущей редакции текста…………………………………………………………………………………….. 25
Глава 1. Модули с высоты птичьего полёта…………………………………………… 27
Linux и GNU………………………………………………………………………………………………………………………………… 27
FAQ 28
Модуль в иерархии программных систем……………………………………………………………………………….. 29
Наш первый модуль ядра………………………………………………………………………………………………………….. 31
Сборка модуля……………………………………………………………………………………………………………………. 31
Загрузка и исполнение………………………………………………………………………………………………………. 33
Точки входа и завершения………………………………………………………………………………………………… 34
Внутренний формат модуля……………………………………………………………………………………………………… 36
Диагностика модуля………………………………………………………………………………………………………………….. 38
Уровни диагностики в /proc………………………………………………………………………………………………. 42
Представление адресов в Linux………………………………………………………………………………………… 43
Форматы вывода………………………………………………………………………………………………………………… 45
Основные ошибки модуля…………………………………………………………………………………………………………. 48
Обсуждение………………………………………………………………………………………………………………………………… 50
Глава 2. Архитектура и вокруг………………………………………………………………. 53
Ядро: монолитное и микроядро……………………………………………………………………………………………….. 53
Траектория системного вызова………………………………………………………………………………………………… 55
Библиотечный и системный вызов из процесса………………………………………………………………. 56
Под капотом системного вызова………………………………………………………………………………………. 63
Отслеживание системного вызова в процессе…………………………………………………………………. 66
Различия программ пространств ядра и пользователя………………………………………………………….. 67
Интерфейсы модуля…………………………………………………………………………………………………………………… 70
Взаимодействие модуля с уровнем пользователя…………………………………………………………… 70
Взаимодействие модуля с ядром………………………………………………………………………………………. 75
Коды ошибок………………………………………………………………………………………………………………………. 77
Загрузка модулей………………………………………………………………………………………………………………………. 77
Автоматическая загрузка модулей…………………………………………………………………………………… 78
Запрет загрузки (черный список модулей)………………………………………………………………………. 79
Параметры загрузки модуля…………………………………………………………………………………………………….. 80
Конфигурационные параметры ядра………………………………………………………………………………………. 85
Параметры в ядре………………………………………………………………………………………………………………. 85
Параметры в модуле………………………………………………………………………………………………………….. 88
Подсчет ссылок использования………………………………………………………………………………………………… 91
Обсуждение………………………………………………………………………………………………………………………………… 93
Глава 3. Инструментальное окружение………………………………………………….. 95
Основные команды…………………………………………………………………………………………………………………….. 95
Системные файлы………………………………………………………………………………………………………………………. 96
Графика, терминал и текстовая консоль…………………………………………………………………………………. 99
Управление текстовыми консолями……………………………………………………………………………………….. 100
Коротко о компиляторе GCC………………………………………………………………………………………………….. 102
Ассемблер в Linux……………………………………………………………………………………………………………………. 105
Нотация AT&T…………………………………………………………………………………………………………………. 107
Инлайновый ассемблер GCC………………………………………………………………………………………….. 108
Создание среды сборки модулей ядра…………………………………………………………………………………… 110
Работа над кодом…………………………………………………………………………………………………………………….. 114
В деталях о сборке…………………………………………………………………………………………………………………… 117
Переменные периода компиляции………………………………………………………………………………….. 117
Дополнительные параметры периода компиляции………………………………………………………. 118
Версионность ядра в коде модуля………………………………………………………………………………….. 118
Как собрать одновременно несколько модулей?………………………………………………………….. 120
Как собрать модуль и используемые программы к нему?……………………………………………. 120
Пользовательские библиотеки………………………………………………………………………………………… 121
Как собрать модуль из нескольких объектных файлов?………………………………………………. 123
Рекурсивная сборка…………………………………………………………………………………………………………. 125
Подписывание модулей…………………………………………………………………………………………………………… 127
Инсталляция модуля……………………………………………………………………………………………………………….. 130
Нужна ли новая сборка ядра?………………………………………………………………………………………………… 131
Динамическая сборка модулей (DKMS)………………………………………………………………………………… 133
Обсуждение………………………………………………………………………………………………………………………………. 138
Глава 4. Внешние интерфейсы модуля…………………………………………………. 139
Драйверы: интерфейс устройства………………………………………………………………………………………….. 139
Символьные устройства………………………………………………………………………………………………….. 143
Варианты реализации……………………………………………………………………………………………. 145
Ручное создание имени………………………………………………………………………………….. 146
Использование udev……………………………………………………………………………………….. 151
Динамические имена………………………………………………………………………………………. 155
Разнородные (смешанные) устройства………………………………………………………… 159
Управляющие операции устройства…………………………………………………………………….. 162
Множественное открытие устройства………………………………………………………………….. 169
Счетчик ссылок использования модуля……………………………………………………………….. 177
Режимы выполнения операций ввода/вывода……………………………………………………… 180
Неблокирующий ввод/вывод и мультиплексирование……………………………………….. 181
Блочные устройства………………………………………………………………………………………………………… 190
Особенности драйвера блочного устройства………………………………………………………. 193
Обзор примеров реализации………………………………………………………………………………….. 194
Регистрация устройства…………………………………………………………………………………………. 195
Подготовка к регистрации……………………………………………………………………………… 195
Диски с разметкой MBR и GPT……………………………………………………………………… 197
Заполнение структуры…………………………………………………………………………………… 199
Завершение регистрации……………………………………………………………………………….. 201
Таблица операций устройства………………………………………………………………………………. 201
Обмен данными……………………………………………………………………………………………………….. 205
Классика: очередь и обслуживание ядром………………………………………………….. 210
Очередь и обработка запроса в драйвере……………………………………………………. 212
Отказ от очереди…………………………………………………………………………………………….. 214
Пример перманентных данных……………………………………………………………………… 215
Некоторые важные API………………………………………………………………………………….. 215
Результаты тестирования………………………………………………………………………………………. 216
Файловая система FUSE…………………………………………………………………………………………. 221
Интерфейс /proc……………………………………………………………………………………………………………………….. 228
Терминальные значения в /proc и /sys……………………………………………………………………………. 230
Использование /proc………………………………………………………………………………………………………… 231
Специфический механизм procfs……………………………………………………………………………. 232
Варианты реализации чтения……………………………………………………………………….. 240
Запись данных………………………………………………………………………………………………… 244
Общий механизм файловых операций………………………………………………………………….. 245
Интерфейс /sys………………………………………………………………………………………………………………………….. 251
Создание и использование имен в /sys……………………………………………………………………………. 253
Ошибки обменных операций…………………………………………………………………………………………… 261
Сетевые интерфейсы и протоколы…………………………………………………………………………………………. 263
Сетевые инструменты……………………………………………………………………………………………………… 265
Сетевые интерфейсы………………………………………………………………………………………………. 265
Инструменты наблюдения……………………………………………………………………………………… 269
Инструменты интегрального тестирования…………………………………………………………. 276
Структуры данных сетевого стека…………………………………………………………………………………. 278
Драйверы: сетевой интерфейс………………………………………………………………………………………… 279
Создание сетевых интерфейсов…………………………………………………………………………….. 279
Новая схема, и детальнее о ее создании………………………………………………………………. 281
Операции сетевого интерфейса……………………………………………………………………………… 286
Переименование сетевого интерфейса………………………………………………………………….. 291
Путь пакета сквозь стек протоколов………………………………………………………………………………. 293
Прием: традиционный подход………………………………………………………………………………. 293
Прием: высокоскоростной интерфейс…………………………………………………………………… 294
Передача пакетов……………………………………………………………………………………………………. 297
Статистика интерфейса…………………………………………………………………………………………………… 298
Виртуальный сетевой интерфейс……………………………………………………………………………………. 301
Протокол сетевого уровня………………………………………………………………………………………………. 307
Еще раз о виртуальном интерфейсе……………………………………………………………………………….. 314
Протокол транспортного уровня……………………………………………………………………………………. 321
Использование драйверов Windows……………………………………………………………………………….. 323
Обсуждение………………………………………………………………………………………………………………………. 324
Глава 5. Внутренние API ядра………………………………………………………………. 326
Механизмы управления памятью…………………………………………………………………………………………… 326
Карта памяти……………………………………………………………………………………………………………………. 326
Динамическое выделение памяти…………………………………………………………………………………… 330
Распределители памяти…………………………………………………………………………………………………… 334
Слябовый распределитель………………………………………………………………………………………………. 336
Страничное выделение……………………………………………………………………………………………………. 344
Выделение больших буферов…………………………………………………………………………………………. 344
Динамические структуры и управление памятью………………………………………………………… 345
Циклический двусвязный список…………………………………………………………………………… 345
Модуль, использующий динамические структуры……………………………………………… 349
Сложноструктурированные данные…………………………………………………………………….. 351
Еще об инициализации объектов ядра………………………………………………………………….. 351
Служба времени………………………………………………………………………………………………………………………. 352
Информация о времени в ядре…………………………………………………………………………………………. 352
Источник прерываний системного таймера…………………………………………………………. 355
Дополнительные источники информации о времени…………………………………………… 356
Три класса задач во временной области……………………………………………………………………….. 357
Измерения временных интервалов…………………………………………………………………………………. 358
Временные задержки……………………………………………………………………………………………………….. 365
Таймеры ядра…………………………………………………………………………………………………………………… 371
Таймеры высокого разрешения………………………………………………………………………………………. 372
Абсолютное время……………………………………………………………………………………………………………. 375
Часы реального времени (RTC)………………………………………………………………………………………. 376
Время и диспетчеризация в ядре…………………………………………………………………………………….. 381
Параллелизм и синхронизация………………………………………………………………………………………………. 382
Потоки ядра………………………………………………………………………………………………………………………. 385
Создание потока ядра…………………………………………………………………………………………….. 385
Свойства потока……………………………………………………………………………………………………… 387
Новый интерфейс потоков……………………………………………………………………………………… 389
Синхронизация завершения…………………………………………………………………………………… 394
Синхронизация в коде……………………………………………………………………………………………………… 401
Критические секции кода и защищаемые области данных………………………………… 401
Механизмы синхронизации…………………………………………………………………………………… 402
Условные переменные и ожидание завершения…………………………………………………… 402
Атомарные переменные и операции……………………………………………………………………… 405
Битовые атомарные операции………………………………………………………………………. 405
Арифметические атомарные операции………………………………………………………… 406
Локальные переменные процессора……………………………………………………………………… 407
Предыдущая модель………………………………………………………………………………………. 407
Новая модель………………………………………………………………………………………………….. 408
Блокировки………………………………………………………………………………………………………………. 409
Семафоры и мьютексы…………………………………………………………………………………… 410
Спин-блокировки……………………………………………………………………………………………. 415
Блокировки чтения/записи…………………………………………………………………………….. 417
Сериальные (последовательные) блокировки……………………………………………… 420
Мьютексы реального времени………………………………………………………………………. 422
Инверсия и наследование приоритетов………………………………………………………… 422
Множественное блокирование………………………………………………………………………………. 423
Уровень блокирования…………………………………………………………………………………………… 424
Предписание порядка выполнения……………………………………………………………………….. 430
Аннотация ветвлений……………………………………………………………………………………… 430
Барьеры…………………………………………………………………………………………………………… 431
Обработка прерываний…………………………………………………………………………………………………………… 432
Общая модель обработки прерывания…………………………………………………………………………… 433
Наблюдение прерываний в /proc……………………………………………………………………………………. 436
Регистрация обработчика прерывания………………………………………………………………………….. 439
Обработчик прерываний: верхняя половина………………………………………………………………… 442
Управление линиями прерывания…………………………………………………………………………. 444
Пример обработчика прерываний………………………………………………………………………… 444
Отложенная обработка: нижняя половина……………………………………………………………………. 446
Отложенные прерывания: softirq…………………………………………………………………………… 446
Тасклеты………………………………………………………………………………………………………………….. 450
Демон ksoftirqd………………………………………………………………………………………………………… 452
Очереди отложенных действий: workqueue…………………………………………………………. 452
Сравнение и примеры…………………………………………………………………………………………….. 455
Обсуждение………………………………………………………………………………………………………………………. 460
Глава 6. Периферийные устройства в модулях ядра…………………………….. 466
Поддержка шинных устройств в модуле……………………………………………………………………………….. 466
Анализ оборудования……………………………………………………………………………………………………………… 468
Подсистема udev………………………………………………………………………………………………………………. 473
Идентификация модуля……………………………………………………………………………………………………. 477
Ошибки идентификации модуля……………………………………………………………………………………… 479
Устройства на шине PCI…………………………………………………………………………………………………………. 480
Подключение к линии прерывания…………………………………………………………………………………. 491
Отображение памяти……………………………………………………………………………………………………….. 492
DMA…………………………………………………………………………………………………………………………………… 493
Устройства USB……………………………………………………………………………………………………………………….. 499
Некоторые технические детали……………………………………………………………………………………… 499
Поддержка в Linux…………………………………………………………………………………………………………… 501
Пара слов о USB-модемах………………………………………………………………………………………………. 503
Устройства USB в коде модуля………………………………………………………………………………………. 506
Многофункциональные USB-устройства………………………………………………………………………. 514
Устройства в пространстве пользователя…………………………………………………………………………….. 520
Аппаратные порты…………………………………………………………………………………………………………… 521
Особенности доступа………………………………………………………………………………………………………. 526
Проект libusb…………………………………………………………………………………………………………………….. 527
GPIO…………………………………………………………………………………………………………………………………… 536
Глава 7. Расширенные возможности программирования……………………… 543
Операции с файлами данных………………………………………………………………………………………………….. 544
Запуск новых процессов из ядра……………………………………………………………………………………………. 552
Сигналы UNIX………………………………………………………………………………………………………………………….. 554
Вокруг экспорта символов ядра…………………………………………………………………………………………….. 561
Неэкспортируемые символы ядра………………………………………………………………………………….. 564
Использование неэкспортируемых символов……………………………………………………………….. 572
Подмена системных вызовов…………………………………………………………………………………………… 576
Добавление новых системных вызовов………………………………………………………………………….. 584
Скрытый обработчик системного вызова……………………………………………………………………… 591
Динамическая загрузка модулей……………………………………………………………………………………………. 600
…из процесса пользователя…………………………………………………………………………………………….. 601
…из модуля ядра……………………………………………………………………………………………………………….. 609
Подключаемые плагины………………………………………………………………………………………………….. 613
Обсуждение………………………………………………………………………………………………………………………………. 623
Глава 8. Отладка в ядре……………………………………………………………………….. 628
Отладочная печать………………………………………………………………………………………………………………….. 629
Интерактивные отладчики……………………………………………………………………………………………………… 629
Отладка в виртуальной машине…………………………………………………………………………………………….. 632
Отдельные отладочные приемы и трюки………………………………………………………………………………. 635
Модуль, исполняемый как разовая задача……………………………………………………………………. 635
Тестирующий модуль………………………………………………………………………………………………………. 637
Интерфейсы пространства пользователя к модулю……………………………………………………… 640
Комплементарный отладочный модуль………………………………………………………………………… 642
Пишите в файлы протоколов…………………………………………………………………………………………… 645
Некоторые мелкие советы в завершение……………………………………………………………………….. 645
Чаще перезагружайте систему!……………………………………………………………………………… 645
Используйте естественные POSIX-тестеры………………………………………………………….. 646
Тестируйте чтение сериями……………………………………………………………………………………. 646
Заключение………………………………………………………………………………………….. 647
Приложение 1. Краткая справка по утилите make………………………………… 649
Приложение 2. Тесты распределителя памяти………………………………………. 652
Приложение 3. Четыре способа записи в защищенную страницу…………. 666
Описание проблемы………………………………………………………………………………………………………………… 666
Отключение страничной защиты: ассемблер……………………………………………………………………….. 667
Отключение страничной защиты: API ядра………………………………………………………………………….. 668
Снятие защиты со страницы памяти……………………………………………………………………………………… 670
Наложение отображения участка памяти…………………………………………………………………………….. 671
Тест выполнения………………………………………………………………………………………………………………………. 672
Обсуждение………………………………………………………………………………………………………………………………. 674
Позднее дополнение………………………………………………………………………………………………………………… 675
Источники информации……………………………………………………………………….. 677
Предметный указатель…………………………………………………………………………. 681
Об авторе……………………………………………………………………………………………… 685

Цилюрик Олег Иванович — программист-разработчик с более чем 40-летним опытом, преподаватель, автор нескольких книг по Linux и Unix, высоко оцененных профессионалами и широкой читательской аудиторией.
-
Расширения ядра Linux: драйверы и модули
1500 ₽
1275 ₽