, Программирование ядра Linux часть 2 - символьные драйверы устройств и синхронизация ядра

Программирование ядра Linux часть 2 - символьные драйверы устройств и синхронизация ядра

Кайвань Н Биллимория

 

Первая публикация на английском языке: Март 2021

Ссылка на продукт: 1190321

Все права защищены. Никакая часть этой книги не может быть воспроизведена, сохранена в поисковой системе или передана в любой форме или любыми средствами без предварительного письменного разрешения издателя, за исключением случаев кратких цитат, встроенных в критические статьи и обзоры.

При подготовке этой книги были предприняты все усилия чтобы гарантировать точность представленной информации. Тем не менее, информация, содержащаяся в этой книге, продаётся без гарантии в явном или неявном виде. Ни авторы, ни Packt Publishing, ни их дилеры и дистрибьюторы не будут нести ответственность за любые убытки, вызванные или предположительно вызванные прямо или косвенно этой книгой.

Packt Publishing пыталась предоставить информацию о товарных знаках обо всех компаниях и продуктов, упомянутых в данной книге для надлежащего использования капиталов. Тем не менее, Packt Publishing не может гарантировать точность этой информации.

Опубликовано Packt Publishing Ltd.

Livery Place

35 Livery Street

Birmingham B3 2PB, UK

ISBN 978-1-80107-951-8

www.packtpub.com

2021-03-21

 Состав исполнителей

Автор
Кайвань Н Биллимория
Управляющий групповой обработкой
Вильсон Ди Зуза
Редактор ввода в эксплуатацию
Виджин Борича
Редактор разработки содержимого
Роуми Диас
Главный редактор
Рауль Ди Зуза
Технический редактор
Шрати Шетти
Литературный редактор
Safis Editing
Координатор проекта
Ниил Димелло
Корректор
Safis Editing
Составитель указателя
Прайтик Широдкар
Технолог
Шанкар Калбхор

Прежде всего моим дорогим родителям, Диане и Надиру "Надсу", показавшим мне как прожить счастливую и продуктивную жизнь.Моей дорожайшей супруге, Дильшад (собственноручно вступавшей финансовым консультантом), а также нашим изумительным детям, Шерой и Даниш -спасибо за вашу любовь и участие.

Кайвань Н Биллимория

 Об авторе

Кайвань Н Биллимория в далёком 1983 самостоятельно обучился программированию на BASIC на ПК IBM своего отца. Он программировал на С и Ассемблере в DOS пока он не раскрыл всё удовольствие от Unix, а в районе 1997, Linux!

Кайвань работал со множеством сторон программного стека Linux, включая сценарии Bash, системное программирование на C, внутреннее устройство ядра, драйверы устройств и работу со встраиваемым Linux. Он активно работал в нескольких коммерческих/ FOSS проектах. Его вклад состоит в драйверах основного потока ОС Linux и во множестве проектов меньшего размера, размещающихся в GitHub. Его страсть к Linux хорошо сочетается со страстью к обучению этим вопросам инженеров, чем он занимается уже более двух десятилетий. Он также является автором HandsOn System Programming with Linux Не вредят ему также и восстанавливающий бег.

Написание этой книги заняло много времени; я бы хотел выразить благодарность команде Packt за терпение и умение! Карлтон Борхес, Роми Диас, Виджин Борича, Рохит Раджкумар, Вивек Анантараман, Нитин Варгезе, Хеманги Лотликар и все остальные. На самом деле было приятно работать с вами.

Я должен поблагодарить очень способных технических критиков - Дональда "Донни" Теволта и Анила Кумара. Они выловили множество моих ошибок и упущений и сильно помогли сделать эту книгу лучше.

 Рецензенты

Дональд Теволт, но вы можете обращаться к нему как к "Донни", был вовлечён в Linux в далёком 2006, и работал с ним с тех пор. Он держатель сертификата безопасности 3 уровня Института профессионалов Linux, а также сертификата Обработчика происшествий GIAC. Донни профессиональный преподаватель Linux и благодаря магии Интернета он преподаёт занятия Linux по всему миру не выходя из дома. Он также занимается исследованием безопасности Linux в одной компании по безопасности IoT.

Анил Кумар является разработчиком в Intel Пакета поддержки платформы (BSP) и встроенного программного обеспечения (firmware) Linux. Он обладает опытом разработки программного обеспечения в 12 лет по множеству вертикалей, включая IoT, мобильные наборы микросхем, ноутбуки/ устройства Chrome, аудиовидео кодирования и преобразователей кода. Он обладает степенью магистра электроники в Индийском научном институте и степенью бакалавра по электронике и связи в Инженерном колледже BMS, Индия. Он энтузиаст электроники и блоггер, а также любит создавать забавные проекты "сделай сам" (DIY).

 www.PacktPub.com

 Предисловие

Эта книга написана с целью помочь на практике вам изучить основы разработки символьного драйвера устройств Linux, а также получить необходимую теоретическую базу для снабжения вас всесторонним представлением этой обширной и интересной тематической области. Чтобы отдать должное основным темам, сфера данной книги намеренно ограничена (в целом) изучением того как писать символьные драйверы класса misc для вашей ОС Linux. Таким образом, вы будете способны глубоко впитать все основы и необходимые автору драйвера навыки чтобы далее относительно легко справляться с различными проектами драйверов Linux.

Основное внимание уделяется практической разработке драйвера посредством мощной инфраструктуры LKM (Loadable Kernel Module, загружаемого модуля ядра); основная часть разработки драйверов выполняется именно таким образом. Основной фокус удерживается на практической разработке кода драйвера, везде, где то требуется, достаточно глубоко разбираемся с внутренним устройством и при этом удерживаем на уме безопасность.

Рекомендация, которую мы не можем не дать достаточно строго: для того чтобы в действительности изучить и разобраться с имеющимися подробностями, на самом деле будет лучше сначала прочесть и разобраться со спутником этой книги, Программирование ядра Linux. Она рассматривает различные ключевые области - сборку ядра из исходника, написание модулей ядра посредством инфраструктуры LKM, внутреннее устройство ядра, включая архитектуру ядра, имеющуюся систему памяти, API выделения/ освобождения памяти, планирование ЦПУ и прочее. Такое сочетание этих двух книг снабдит вас уверенным и глубоким фронтом.

Эта книга не тратит времени даром - в самой первой главе вы узнаёте подробности инфраструктуры драйвера Linux и то как написать пока простой, на законченный символьный драйвер устройства класса misc. Далее вы узнаёте как сделать нечто очень необходимое: выполнить действенное взаимодействие вашего драйвера с процессами пространства пользователя с применением различных технологий (некоторые из которых также помогают целям отладки/ диагностики!). Далее рассматривается понимание аппаратного ввода/ вывода памяти (периферийной микросхемы). За этим следует подробное описание обработки аппаратных прерываний. Оно включает знакомство и применение определённых современных технологий драйверов - использование потоковых IRQ, применение управляющих ресурсами API для драйверов, выделение ресурсов ввода/ вывода и тому подобное. Это охватывает то что представляют собой верхняя/ нижняя половины, работу с tasklet-ами и softirq, а также замер задержек прерывания. Далее рассматриваются механизмы ядра, с которыми вы обычно работаете - применение таймеров ядра, настройка задержек, создание потоков ядра и управление ими, а также рабочие очереди.

Остающиеся две главы этой книги окунаются в относительно сложную пока и критичную для понимания тему относительно современного прототипа драйвера или разработки ядра пониманию синхронизации ядра и работы с ней.

Данная книга применяет самое последнее на момент её написание ядро Linux 5.4 LTS (Long Term Support, с длительным временем поддержки). Именно это ядро будет поддерживаться (но при этом с исправлениями ошибок и проблем безопасности) с ноября 2019 прямо вплоть до декабря 2025! Именно это является тем ключевым моментом, который гарантирует что содержимое данной книги будет оставаться актуальным и действующим на грядущие годы!

Мы очень надеемся, что то, что вы изучите в этой книге удовлетворит вас. Приятного чтения!

Bold

 Для кого эта книга

В первую очередь эта книга предназначена для программистов Linux, начинающих искать свой путь в разработке драйвера устройства. Из этой книги извлекут пользу разработчики драйвера Linux, стремящиеся преодолеть частые и распространённые проблемы в разработке ядра/ драйвера, а также разбирающиеся с выполнением общих задач драйвера и изучающих их, выполняющие ввод/ вывод с периферийных устройств, обрабатывающие аппаратные прерывания, имеющие дело с одновременностью и многое ещё с чем. Требуются базовые знания внутреннего устройства ядра Linux (и распространённых API), с разработкой модуля ядра, а также с программированием на C.

 Что охватывает эта книга

Глава 1. Написание простого символьного драйвера misc, прежде всего проходит по самым основам - что предполагается выполнять драйвером, пространство имён определённого устройства, имеющаяся sysfs и базовые догматы самого LDM. Затем мы окунаемся в собственно подробности написания простейшего символьного драйвера устройства; помимо прочего, вы изучите имеющуюся инфраструктуру - в действительности, собственно внутреннюю реализацию основной философии/ архитектуры того, что "если это не процесс, тогда это файл"! Вы ознакомитесь с тем как реализовывать различными способами некий символьный драйвер устройства класса misc; закрепить эти понятия помогут некоторые примеры кода. Также рассматриваются вызовы безопасности и как их решать (в данном контексте); на практике демонстрируется некий "плохой" драйвер, создающий проблему эскалации полномочий!

Глава 2. Магистрали взаимодействия пользователь - ядро, рассматривают как осуществлять взаимодействие между имеющимися пространствами ядра и пользователя, что критически важно для вас, как некого автора модуля/ драйвера. Здесь вы изучите различные интерфейсы или магистрали взаимодействия. Именно это является одной из важнейших сторон написания кода ядра/ драйвера. Используется ряд методов: взаимодействие через традиционную procfs, наилучший вариант для драйверов через sysfs и некоторые прочие, посредством debugfs, сокетов netlink и системные вызовы ioctl(2).

Глава 3. Работа с памятью ввода/ вывода аппаратуры, рассматривает ключевые стороны написания драйвера - основную проблему (а также её решение) доступа к памяти оборудования (mapped memory I/O, ввод/ вывод установленной в соответствие памяти) из периферийного устройства или периферийной микросхемы. Для доступа к памяти аппаратного ввода/ вывода и манипуляции с ней мы рассматриваем общую технологию MMIO (memory-mapped I/O, поставленного в соответствие ввода/ вывода), а также (обычную для x86) технологию PIO (port I/O, ввода/ вывода портов). Также показываются некие образцы из имеющихся драйверов ядра.

Глава 4. Обработка аппаратных прерываний, показывает в общих деталях как обрабатывать аппаратные прерывания и работать с ними. Мы вкратце начинаем с того как с аппаратными прерываниями работает само ядро, затем мы переходим к тому как вы надеетесь "выделять" некую линию прерывания (рассматривая современные API управления ресурсами), а также как правильно реализовывать конкретную подпрограмму обработки прерывания. Далее рассматривается современный подход применения потоковых обработчиков (и того, почему именно их), NMI (Non-Maskable Interrupt, не маскируемых прерываний) и кое- что ещё. Рассматриваются основные причины собственно как "верхней половины", так и "нижней половины" механизмов прерывания (hardirq, tasklet и softirqs) и собственно их использование в коде, а также ключевые сведения, связанные с за и против обработки прерываний. Завершает эту ключевую главу замер задержек прерывания при помощи современного набора инструментов [e]BPF, а также посредством Ftrace.

Глава 5. Работа с таймерами, потоками и рабочими очередями ядра, охватывает то, как применять некоторые полезные (и часто используемые драйверами) механизмы ядра - задержки, таймеры, потоки ядра и рабочие очереди. Они представляются как удобные для множества ситуаций реального мира. Всё это рассматривается здесь: как осуществлять блокирующие задержки и задержки без блокировок (как того требует конкретная ситуация), настройка и применение таймеров ядра, создание потоков ядра и работа с ними, а также применение рабочих очередей ядра. Иллюстрации этих основных понятий, для их изучения в коде, служат некоторые образцы модулей, в том числе три версии примера драйвера sed simple encrypt decrypt, простой дешифрации зашифрованного.

Глава 6. Синхронизация ядра- Часть I, прежде всего покрывает основные ключевые понятия, относящиеся к критическим разделам, атомарности, того, чего достигает понятие блокировки и, что особенно важно, то, зачем всё это. Затем мы рассматриваем относящиеся к одновременности вопросы при работе внутри самого ядра Linux; это естественным образом перемещает нас в важное руководство по блокировкам, то, что означают взаимные блокировки, а также к ключевым пдходам предотвращения взаимных блокировок. Затем глубже рассматриваются две наиболее популярные технологии блокировок ядра - взаимное исключение блокировок и спин- блокировки, причём совместно с некоторыми примерами кода (драйвера).

Глава 7. Синхронизация ядра- Часть II, продолжает наше путешествие по синхронизации ядра. Здесь вы изучите ключевые оптимизации блокировок - применение облегчённой атомизации а также (наиболее последнее достижение) операторы refcount (счётчиков ссылок) для безопасной работы с целыми, применение побитовых операций RMW для безопасного выполнения побитовых операций, а также использование спин блокировок чтения- записи поверх обычных. Также обсуждается наследование рисков, таких как "ложное совместное использование" (false sharing). Далее рассматривается обзор свободных от блокирований технологий программирования (с концентрацией на переменных для ЦПУ и их применением, причём совместно с образцами). После этого рассматривается некая критически важная тема, технологии отладки блокировок, в том числе мощной проверки правильности блокировок ядра lockdep. Эта глава завершается кратким обзором барьеров памяти (совместно с использование барьеров памяти некого имеющегося сетевого драйвера ядра).

Мы снова подчёркиваем, что данная книга предназначения для программирующих ядро, которые не знакомы с написанием драйверов устройств; некоторые темы о драйверах выходят за рамки данной книги и не рассматриваются. К ним относятся прочие типы драйверов устройств (помимо символьных), работа с имеющимся деревом устройств и тому подобное. Для освоения этих вопросов Packt предлагает вам прочие ценные руководства. Эта книга послужит отличным началом.

 Как получить от этой книги больше пользы

Для максимального получения пользы от данной книги мы ожидаем от вас знаний и опыта в следующем:

  • Самостоятельно изучите некую систему Linux с применением командной строки (её оболочки).

  • Язык программирования C.

  • Ознакомьтесь с тем как писать простейшие модули ядра посредством инфраструктуры LKM (Loadable Kernel Module, загружаемого модуля ядра).

  • Разберитесь (по крайней мере с основами) ключевых понятий внутреннего устройства Linux: с архитектурой ядра, управлением памятью (плюс с API динамического выделения/ освобождения памяти), а также планированием ЦПУ.

  • Это не обязательно, однако опыт с понятиями и технологиями программирования ядра Linux отлично помогут.

В идеале, мы настоятельно рекомендуем вначале прочесть компаньона данной книги, Программирование ядра Linux.

Здесь мы приводим основные подробности требл=ований данной книги к аппаратным и программным средствам, а также к их установке:

Таблица 0-1. Предварительные требования
Номер главы Необходимое программное обеспечение Свободное/ проприетарное Ссылки для выгрузки программного обеспечения Спецификация оборудования Необходимая ОС

Все главы

Последний дистрибутив Linux; мы пользуемся Ubuntu 18.04 LTS (а также Fedora 31 / Ubuntu 20.04 LTS); любые из них пригодны. Рекомендуется чтобы вы устанавливали свою ОС Linux как некую VM (virtual machine), применяя в качестве гипервизора Oracle VirtualBox 6.x (или более позднюю версию.

Бесплатное (с открытым исходным кодом)

Ubuntu (для настольных систем): https://ubuntu.com/download/desktop, Oracle VirtualBox: https://www.virtualbox.org/wiki/Downloads

Обязательно: современный, относительно мощный ПК или ноутбук с 4ГБ оперативной памяти (минимально; чем больше, тем лучше), 25ГБ свободного дискового пространства и хорошее подключение к Интернету.

Желательно мы также пользуемся в качестве испытательного стенда Raspberry Pi 3B+.

ВМ в хосте Windows, либо обособленная Linux в качестве ОС.

Подробности этапов установки (касательно программного обеспечения):

  1. Установите Linux в качестве некой ВМ в системе хоста Windows, следуя одному из этих руководств:

  2. В своей ВМ Linux установите все необходимые программные пакеты:

    1. Зарегистрируйтесь в Linux своей гостевой ВМ и вначале внутри окна терминала (из оболочки) выполните следующие команды:

      
      > sudo apt update
      > sudo apt install gcc make perl
      		
    2. Теперь установите Добавления гостя Oracle VirtualBox. Ссылка: How to Install VirtualBox Guest Additions in Ubuntu (Этот шаг применим только если вы запустили Ubuntu в качестве некой ВМ с применением в качестве прикладного приложения гипервизора Oracle VirtualBox).

    3. Для установки необходимых пакетов выполните следующие шаги:

      1. Внутри ВМ Ubuntu вначале запустите команду

        
        > sudo apt update
        		
      2. Теперь в отдельной строке запустите команду

        
        > sudo apt install git fakeroot build-essential tar ncurses-dev tar xz-utils libssl-dev bc stress python3-distutils libelf-dev linux-headers-$(uname -r) bison flex libncurses5-dev util-linux net-tools linux-tools-$(uname -r) exuberant-ctags cscope sysfsutils curl perf-tools-unstable gnuplot rt-tests indent tree pstree smem hwloc bpfcc-tools sparse flawfinder cppcheck tuna hexdump trace-cmd virt-what
        		
  3. Полезные ресурсы:

  • Подробные инструкции, а также дополнительные полезные проекты, установка инструментальных средств переноса на ARM и многое иное описывается в Главе 1, Настройка рабочего пространства ядра из книги- компаньона данного руководства Программирование ядра Linux.

  • Мы проверили весь код из данной книги (он также имеет свой собственный репозиторий GitHub) в следующих платыормах:

    • Гостевая ОС x86_64 Ubuntu 18.04 LTS (запущенная в Oracle VirtualBox 6.1)

    • Гостевая ОС x86_64 Ubuntu 20.04.1 LTS (запущенная в Oracle VirtualBox 6.1)

    • Естественная ОС x86_64 Ubuntu 20.04.1 LTS

    • ARM Raspberry Pi 3B+ (запущенная как в качестве ядра своего дистрибутива, так и в качестве нашего индивидуального ядра 5/4); лёгкое тестирование.

    Если вы пользуетесь цифровой версией данной книги, мы предлагаем вам набирать необходимый код собственноручно или, ещё лучше, получая доступ к коду через репозиторий GitHub (ссылка доступна в следующем разделе). Следование этому правилу поможет вам избежать какие бы то ни было потенциальные проблемы, связанные с копированием и вставкой кода..

    Для данной книги мы регистрируемся с учётной записью llkd. Я настоятельно рекомендую вам следовать соответствующему эмпирическому правилу: не доверяйте никаким словам вовсе, вместо этого проверяйте всё самостоятельно.. Тем самым, данная книга снабжает вас множеством практических экспериментов и образцов кода драйвера ядра, которые вы можете и обязаны попробовать самостоятельно; это послужит вам великолепной подмогой в совершении действительного развития и глубокого изучения, а также понимания различных сторон разработки драйвера/ ядра Linux.

     Выгрузка файлов образца кода

    Вы можете выгрузить примеры кода для данной книги с GitHub по ссылке: https://github.com/PacktPublishing/Linux-Kernel-Programming-Part-2. В случае наличия обновлений этого кода они будут обновлять этот имеющийся репозиторий GitHub.

    Мы также обладаем прочими пакетами кода из своего богатого каталога книг и видео, доступного в: https://github.com/PacktPublishing/ Сверяйтесь с ними!

     Загрузка цветных изображений этой книги

    Мы дополнительно снабжаем вас файлом PDF, который содержит цветные изображения экранных снимков/ схем, использованных в данной книге. Вы можете загрузить этот файл по адресу: http://www.packtpub.com/sites/default/files/downloads/9781801079518_ColorImages.pdf.

     Соглашения

    В данной книге вы найдёте ряд текстовых стилей, которые делают разницу между различными видами информации. Здесь мы приводим некоторые примеры этих стилей и объяснение их назначения.

    CodeInText обозначает в тексте, имена таблиц базы данных, имена папок, имена файлов, расширения файлов, имена путей, модели URL-адресов, ввод пользователя, и регулировки Twitter. Вот некие примеры: "Соответствующий API ioremap() возвращает некий KVA с типом void *, в качестве его адреса местоположения.".

    Блок кода записываются следующим образом:

    
    static int __init miscdrv_init(void)
    {
        int ret;
        struct device *dev;
     	   

    Когда мы желаем привлечь ваше внимание к определённой части блока кода, соответствующие строки или элементы устанавливаются жирным текстом:

    
    #define pr_fmt(fmt) "%s:%s(): " fmt, KBUILD_MODNAME, __func__
    [...]
    #include <linux/miscdevice.h>
    #include <linux/fs.h>
    [...]
     	   

    Всякий ввод и вывод в командной строке записывается следующим образом:

    
    pi@raspberrypi:~ $ sudo cat /proc/iomem
     	   

    Жирный шрифт указывает некий новый термин, важное слово или слова, которые вы наблюдаете на экране. Например, слова в меню или блоках диалога в тексте, подобном приводимому здесь. Например: "Выберите System info из панели Administration.

    [Замечание]Замечание

    Предостережения или важные замечания появляются в блоках подобных этому.

    [Совет]Совет

    Советы и ловкие приёмы возникают таким образом.

     Разделы

    В этой книге вы будете находить отдельные часто повторяющиеся заголовки (Приготовление, Как это сделать..., Как это работает..., Также ознакомьтесь... и Дополнительно). Чтобы получить чёткие инструкции как выполнить определённый рецепт, применяйте эти разделы следующим образом:

     Обратная связь с читателями

    Обращения наших читателей всегда приветствуются. Дайте нам знать что вы думаете об этой книге - что вам нравится или не нравится. Обратная связь с читателями важна нам, так как помогает нам разрабатывать издания, от которых вы на самом деле получите максимальную пользу.

    Для отправки обычного отклика просто пошлите электронное письмо на адрес feedback@packtpub.com с упоминанием заголовка книги в теме вашего сообщения.

    Если у вас существует тема, в которой у вас имеется опыт и вы заинтересованы либо в написании, либо во вкладе в книгу, обратитесь к руководству по адресу www.packtpub.com/authors.

     Поддержка пользователей

    Теперь, когда вы являетесь гордым владельцем книги Packt, у нас есть целый ряд моментов для помощи вам в получении максимальной выгоды от вашей покупки.

     Опечатки

    Хотя мы и предприняли все меры чтобы обеспечить точность нашего содержимого, ошибки всё- таки возможны. Если вы обнаружили ошибку в нашей книге - возможно, ошибку в тексте или в коде - мы будем признательны если вы сообщите об этом нам. Сделав это, вы можете предостеречь остальных читателей от разочарования и помочь нам улучшить последующие версии данной книги. Если вы обнаружили ошибку, пожалуйста, сообщите о ней посетив www.packtpub.com/submit-errata, выбрав вашу книгу, кликнув на ссылку Errata Submission Form, и заполнив подробности найденной вами ошибки. Когда ваша ошибка будет проверена, вы получите уведомление и ошибка будет выложена на наш веб- сайт или добавлена в какой- нибудь перечень существующих ошибок с заголовком раздела Errata.

    Для просмотра ранее выявленных ошибок посетите www.packtpub.com/books/content/support и введите название нужной книги в поле поиска. Необходимая информация появится в разделе Errata.

     Незаконное тиражирование

    Пиратство, защищённых авторским правом материалов в Интернете является постоянной проблемой во всех средствах массовой информации. В Packt мы подходим к защите наших авторских прав и лицензий очень серьёзно. Если вы столкнётесь с какой-либо незаконной копией наших работ в любой форме в Интернете, пожалуйста, предоставьте нам сразу адрес местонахождения или имя веб-сайта, чтобы мы могли принять меры. {Прим. пер.: Согласно закону об авторском праве РФ, авторские права на перевод принадлежат авторам этого перевода. Данным переводом, по нашему мнению, мы служим популяризации основных стратегических направлений развития тем Packt. В случае наличия конструктивных предложений, готовы к тесному сотрудничеству.}

    Пожалуйста, обратитесь по адресу copyright@packtpub.com со ссылкой на материалы содержащие признаки нарушения авторских прав.

    Мы выражаем вам признательность в защите наших авторов и нашей возможности доносить до вас имеющего ценность содержимого.

     Вопросы

    Если у вас есть проблемы по любым сторонам данной книги, вы можете контактировать с нами по адресу questions@packtpub.com и мы предпримем все меры в отношении ваших проблем.

     Содержание

    Предисловие
    Что охватывает эта книга
    Что вам нужно для этой книги
    Для кого эта книга
    Соглашения
    Обратная связь с читателями
    Поддержка пользователей
    Выгрузка файлов образца кода
    Опечатки
    Незаконное тиражирование
    Вопросы
    Раздел 1. Основы символьного драйвера
    Глава 1. Написание простого символьного драйвера misc
    Технические требования
    Приступая к написанию простейшего символьного драйвера устройства misc
    Разбираемся с основами устройства
    Быстрые замечания относительно Модели устройства Linux
    Написание кода драйвера misc - часть 1
    Разбираемся в собственно соединении между самим процессом, его драйвером и имеющимся ядром
    Обработка не поддерживаемых методов
    Написание кода драйвера misc - часть 2
    Написание кода драйвера misc - часть 3
    Тестирование нашего образца драйвера misc
    Копирование данных из ядра в пространство пользователя и наоборот
    Использование API ядра для выполнения переноса данных
    Драйвер misc с неким секретом
    Написание `безопасного` кода драйвера устройства musc
    Наш безопасный драйвер - код init
    Наш безопасный драйвер - метод read
    Наш безопасный драйвер - метод write
    Наш безопасный драйвер - очистка
    Наш безопасный драйвер - проверочное прикладное приложение пространства пользователя
    Проблемы и связанные с безопасностью вопросы
    Взлом безопасного драйвера
    Плохой драйвер - ошибочный read()
    Плохой драйвер - ошибочный write() - эскалация прав!
    Изменения проверочного прикладного приложения пространства пользователя
    Изменения драйвера устройства
    Давайте теперь получим права root
    Выводы
    Вопросы
    Дальнейшее чтение
    Глава 2. Магистрали взаимодействия пользователь - ядро
    Технические требования
    Подходы к обменам/ взаимодействию драйвера ядра с с прикладным приложением C пространства пользователя
    Взаимодействие через файловую систему процессов (procfs)
    Основы файловой системы procfs
    Каталоги в procfs
    Основная цель, отведённая procfs
    procfs вне рамок авторов драйвера
    Применение procfs для взаимодействия с определённым пространством пользователя
    Базовые API procfs
    Четыре файла procfs, которые мы создадим
    Испытание динамического элемента procfs управления debug_level
    Динамическое управление debug_level через procfs
    Несколько API procfs misc
    Взаимодействие через файловую систему sys (sysfs)
    Создание (псевдо) файла sysfs в коде
    Создание образца устройства платформы
    Устройства платформы
    Пробуем всё это вместе - настройка атрибутов устройства и создание соответствующего файла sysfs
    Собственно код для реализации нашего файла sysfs и его обратных вызовов
    Правило "одно значение на файл sysfs"
    Взаимодействие через файловую систему debug (debugfs)
    Проверка наличия debugfs
    Поиск документации API debugfs
    Пример взаимодействия с debugfs
    Создание и применение первого файла debugfs
    Создание и применение второго файла debugfs
    Вспомогательный API debugfs для работы с глобальыми численными значениями
    Удаление псевдо файла (файлов) debugfs
    Наблюдаем ошибку ядра - Упс!
    debugfs - реальные пользователи
    Взаимодействие через сокеты netlink
    Преимущества применения сокетов
    Разбираемся с тем что представляет собой сокет netlink
    Пишем приложение сокета netlink пространства пользователя
    Пишем код сокета netlink пространства ядра как модуль ядра
    Пробуем свой проект взаимодействия netlink
    Взаимодействие через системные вызовы ioctl
    Применение ioctl в пространствах пользователя и ядра
    Пространство пользователя - использование системного вызова ioctl
    Пространство ядра - использование системного вызова ioctl
    ioctl в качестве интерфейса отладки
    Сопоставление методов взаимодействия - таблица
    Выводы
    Вопросы
    Дальнейшее чтение
    Глава 3. Работа с памятью ввода/ вывода аппаратуры
    Технические требования
    Доступ к памяти ввода/ вывода аппаратуры из ядра
    Осознание основной проблемы с прямым доступом
    Основное решение - установка соответствия через память ввода/ вывода или порт ввода/ вывода
    Запрос полномочий ядра
    Разбираемся с вводом/ выводом соответствия памяти и применяем его
    Используем API ioremap*()
    Более новое поколение - API управляемое devm_*
    Получение ресурсов устройства
    Всё вместе при API devm_ioremap_resource()
    Поиск нового соответствия через /proc/iomem
    MMIO - выполнение реального ввода/ вывода
    Выполнение от 1 до 8 считываний и записей в областях памяти MMIO
    Выполнение повторяющегося ввода/ вывода в областях памяти MMIO
    Настройка и копирование в областях памяти MMIO
    Разбираемся с вводом/ выводом соответствия портов и его использование
    PMIO - выполнение реального ввода/ вывода
    Пример PMIO - i8042
    Поиск портов через /proc/ioports
    Ввод/ вывод через порты - несколько остающихся моментов, которые стоит отметить
    Выводы
    Вопросы
    Дальнейшее чтение
    Глава 4. Обработка аппаратных прерываний
    Технические требования
    Аппаратные прерывания и как ядро обрабатывает их
    Выделение аппаратного IRQ
    Выделение вашего обработчика прерывания при помощи request_irq()
    Высвобождение линии IRQ
    Настройка флагов прерывания
    Разбираемся с прерываниями, переключаемыми уровнем и фронтом - краткое замечание
    Представление кода 1 - сетевой драйвер IXGB
    Реализация подпрограммы обработки прерывания
    Руководство по контексту прерывания - что делать, а что нет
    Не допускать блокировок - выявление возможных путей блокирования
    Маскирование прерываний - значение по умолчанию и их контроль
    Оставляйте всё быстрым
    Собственно написание подпрограммы обработки прерываний
    Представление кода 2 - обработчик прерываний драйвера i8042
    Представление кода 3 - обработчик прерываний сетевого драйвера IXGB
    Выделение IRQ - современный подход - возможности управляемого прерывания
    Работа с моделью потоковых прерываний
    Применение модели потоковых прерываний - её API
    Применение модели управляемых потоковых прерываний - рекомендуемый способ
    Представление кода 4 - потоковый обработчик прерывания микроконтроллера STM32 F7
    Внутренняя реализация соответствующего потокового прерывания
    Зачем пользоваться потоковыми прерываниями?
    Потоковые прерывания - на самом деле выполняют их в реальном масштабе времени
    Ограничения при использовании потокового обработчика
    Работа с более ранними потоковыми обработчиками hardirq
    Включение и запрет IRQ
    Не маскируемые прерывания
    Просмотр всех выделенных линий прерываний (IRQ)
    Разбираемся и с верхними и нижними половинами и применяем их
    Определение и применение tasklet
    Инициализация tasklet
    Исполнение tasklet
    Основы механизма ядра softirq
    Доступные softirqs и для чего они предназначены
    Разбираемся с тем как ядро исполняет softirqs
    Исполнение tasklet
    Использование потоков ядра ksoftirqd
    softirqs и одновременность
    Обработчики hardirqs, tasklets и потока - чем и когда пользоваться
    Полное понимание установленного контекста
    Просмотр контекста - примеры
    Как Linux устанавливает приоритеты действий
    Несколько ответов на остающиеся вопросы
    Балансировка нагрузки прерываний и сродство IRQ
    Поддерживает ли ядро обособленные стеки IRQ?
    Замеры метрик и задержек
    Замер прерываний при помощи [e]BPF
    Обслуживание замера времени индивидуальных hardirqs
    Обслуживание замера времени индивидуальных softirqs
    Применение Ftrace для получения обработчика системных задержек
    Обнаружение запрещённых прерываний с наихудшими временными задержками при помощи Ftrace
    Прочие инструменты
    Выводы
    Вопросы
    Дальнейшее чтение
    Глава 5. Работа с таймерами, потоками и рабочими очередями ядра
    Технические требования
    Задержка на заданное время в самом ядре
    Разбираемся как пользоваться атомарным API *delay()
    Разбираемся как пользоваться атомарным API *sleep()
    Получение временных отметок внутри кода ядра
    Давайте испробуем - как долго происходят задержки и засыпания в действительности?
    Драйверы "sed" - демонстрация таймеров, потоков и рабочих очередей ядра
    Настройка и использование таймеров ядра
    Применение таймеров ядра
    Наш образец модуля таймера ядра - представление кода 1
    Наш образец модуля таймера ядра - представление кода 2
    Наш образец модуля таймера ядра - его исполнение
    sed1 - реализация таймаутов при помощи нашего демонстрационного драйвера sed1
    Умышленный пропуск своей шины
    Создание потоков ядра и работа с ними
    Простая демонстрация - создание потока ядра
    Запуск демонстрационного потока ядра kthread_simple
    Драйвер sed2 - проектирование и разработка
    sed2 - проектирование
    sed2 - реализация кода
    sed2 - испробуем его
    Запросы к потоку ядра и настройка планирования политики/ приоритета
    Применение рабочих очередей ядра
    Самый минимум внутреннего устройства рабочих очередей
    Применение глобальных в ядре рабочих очередей
    Наш образец рабочей очереди модуля ядра - представление кода
    Наш образец рабочей очереди модуля ядра - его исполнение
    Минипроект sed3 - краткий взгляд
    Выводы
    Вопросы
    Дополнительное чтение
    Раздел 2. Окунаемся глубже
    Глава 6. Синхронизация ядра- Часть I
    Критические разделы, исключительное исполнение и атомарность
    Что такое критический раздел?
    Классический случай - глобальное i++
    Концепции - блокировки
    Резюме ключевых моментов
    Связанные с одновременностью вопросы внутри самого ядра Linux
    Системы SMP со множеством ядер и состязательность данных
    Вытесняемые ядра, блокирующий ввод/ вывод и состязательность данных
    Аппаратные прерывания и состязательность данных
    Руководства по блокировками и взаимному блокирования
    Взаимное исключение или спин блокировки? Что и когда применять
    Определение того, какую блокировку применять - в теории
    Определение того, какую блокировку применять - на практике
    Применение блокировок взаимного исключения
    Инициализация взаимного исключения
    Правильное применение взаимного исключения
    API взаимного исключения и его снятия, а также их применение
    Взаимное исключение через сон с (без) прерывания?
    Взаимное исключение - пример драйвера
    Собственно взаимное исключение - несколько остающихся моментов
    Варианты API взаимного исключения
    Вариант trylock взаимного исключения
    Вариант взаимного исключения с прерыванием и варианты с уничтожением
    Вариант взаимного исключения ввода/ вывода
    Семафор и взаимное исключение
    Инверсия приоритета и взаимное исключение
    Внутреннее проектирование
    Применение спин блокировки
    Спин блокировка - образец применения
    Спин блокировка - образец драйвера
    Проверка - засыпание в атомарном контексте
    Проверка в отладчике ядра 5.4
    Проверка в дистрибутиве без отладчика ядра 5.4
    Блокировки и прерывания
    Применение спин блокировок - краткое резюме
    Выводы
    Вопросы
    Дополнительное чтение
    Глава 7. Синхронизация ядра- Часть II
    Применение взаимодействий atomic_t и refcount_t
    Сопоставление интерфейсов: более нового refcount_t и более старого atomic_t
    Пример интерфейсов refcount_t и atomic_t
    Образцы использования refcount_t внутри основного кода самого ядра
    64- битные атомарные операторы с целыми
    Использование атомарных операторов RMW
    Атомарные операции RMW - действия с регистрами устройств
    Применение побитовых операций RMW
    Применение побитовых операций - некий пример
    Действенный поиск побитовой маски
    Применение спин блокировок читатель - писатель
    Интерфейсы спин блокировок читатель - писатель
    Слово предостережения
    Семафор читатель - писатель
    Воздействие кэширования и ложное совместное использование
    Свободное от блокирований программирование с переменными для ЦПУ
    Переменные для ЦПУ
    Работа с выделением для ЦПУ
    Выделение, инициализация и освобождение переменных для ЦПУ
    Выполнение операций ввода/ вывода с переменными для ЦПУ
    Выделение для ЦПУ - образец модуля ядра
    Выделение для ЦПУ - применение внутри ядра
    Отладка блокировок внутри самого ядра
    Настройка ядра отладки для отладки блокировок
    Средство проверки блокировок lockdep - раннее обнаружение проблем с блокировками
    Примеры - перехват ошибок взаимной блокировки при помощи lockdep
    Пример 1 - перехват собственной ошибки взаимной блокировки при помощи lockdep
    Его исправление
    Пример 2 - перехват взаимной блокировки AB-BA при помощи lockdep
    lockdep - пояснения и проблемы
    Пояснения lockdep
    Проблемы lockdep
    Статистические данные lockdep
    Представление статистических данных lockdep
    Барьеры памяти - введение
    Пример использования барьера памяти в драйвере устройства
    Выводы
    Вопросы
    Дальнейшее чтение
    Указатель