, Программирование ядра Linux

Программирование ядра Linux

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

 

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

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

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

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

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

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

Livery Place

35 Livery Street

Birmingham B3 2PB, UK

ISBN 978-1-78995-343-5

www.packtpub.com

2021-03-22

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

Автор
Кайвань Н Биллимория
Управляющий групповой обработкой
Вильсон Ди Зуза
Редактор ввода в эксплуатацию
Виджин Борича
Редактор разработки содержимого
Роуми Диас
Главный редактор
Рауль Ди Зуза
Технический редактор
Нитик Черувакодан
Литературный редактор
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, активным образом, а также получить необходимую теоретическую базу для снабжения вас всесторонним представлением этой обширной и интересной тематической области. Она намеренно сосредотачивается на разработке ядра с помощью мощной инфраструктуры LKM (Loadable Kernel Module, загружаемого модуля ядра); подавляющая часть разработки проектов и продуктов, включая разработку драйверов выполняется именно таким образом.

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

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

Следующий, ключевой, раздел поспособствует вашему пониманию важных и существенных внутреннего устройства ядра - архитектуру самого ядра Linux, структуру его задач, а также стеки пользователя и режима ядра. Управление памятью - ключевая и увлекательная тема - мы посвящаем ей целые три главы (в достаточной степени отражающие внутреннее устройство и, что немаловажно, то, как именно выделять любую свободную память ядра). Завершают это раздел рабочие подробности и более глубокие детали планирования ЦПУ в Linux.

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

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

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

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

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

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

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

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

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

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

Глава 2. Сборка ядра Linux 5.4 из исходного кода - Часть I, выступает первой частью пояснения того как собирать ядро современного Linux с нуля при помощи исходного кода. В этой части вам будут предоставлены базовые сведения - имеющаяся номенклатура версий, различные деревья исходного кода,схема исходного кода самого ядра - в избранном дереве исходного кода ядра. Затем вам будет подробно показано как в точности выгружать некое стабильное унифицированное дерево исходного кода ядра Linux в вашу ВМ. Затем мы слегка рассмотрим относящееся к самой структуре исходного кода ядра, получая, по сути, "представление на 10 000 футов" основы кода ядра. Далее следует реальная работа по извлечению и настройке самого ядра Linux. Также показывается создание и использование некой индивидуальной записи меню для настройки ядра.

Глава 3. Сборка ядра Linux 5.4 из исходного кода - Часть II, это вторая часть осуществления сборки ядра из исходного кода. В этой части вы продолжите свою предыдущую главу, теперь и в самом деле собирая свой ядро, устанавливая модули ядра, разбираясь с тем что в действительности представляет собой initramfs (initrd) и как её вырабатывать, а также настройка необходимого начального загрузчика (для x86). К тому же, в качестве ценного добавления, данная глава затем поясняет как выполнять кросс- компиляцию необходимого ядра для типичной встраиваемой цели ARM (с применением в качестве целевого устройства популярного Raspberry Pi). Также упоминается ряд советов и трюков со сборками ядра и даже работы по безопасности (упрочнению) ядра.

Глава 4. Написание вашего первого модуля ядра - LKM, Часть I, это первая из двух частей, которая охватывает фундаментальные стороны разработки ядра Linux - собственно платформу LKM, а также как с ней разобраться и применять в качестве вас как "пользователя модуля" - программиста модуля ядра или драйвера устройства. Она покрывает самые основы архитектуры ядра Linux и затем, очень подробно, каждый шаг, вовлечённый в написание простейшего модуля ядра "Hello, world", его компиляции, вставки, проверки и удаления из пространства рассматриваемого ядра. Мы также подробно рассмотрим ведение журнала ядра при помощи вездесущего API printk.

Глава 5. Написание вашего первого модуля ядра - LKM, Часть II, выступает второй рассматривающей инфраструктуру LVM частью. Здесь мы приступаем к чему- то критически важному - изучению того как "лучше" применять Makefile, что поможет вам вырабатывать более надёжный код (имея некую проверку кода, исправление, статический анализ целей и тому подобное). Затем мы подробно покажем все этапы для успешной кросс- трансляции некого модуля ядра для какой- то альтернативной архитектуры, как эмулировать в своём ядре "подобный библиотеке" код (как через подход "редактирования сязей" - linking, так и через составление модулей в стек), задавая и передачу параметров в ваш модуль ядра и применяя их. Дополнительные темы включают в себя авоматическую загрузку модулей при запуске, важные руководства по безопасности, а также некоторые сведения по документации собираемого ядра и того, как получать к ней доступ. Более занимательным делают обучение некоторые примеры модулей ядра.

Глава 6. Существенные моменты внутреннего устройства ядра - Процессы и Потоки, погружается в некоторые сущностные вопросы тем внутреннего устройства ядра. Мы начинаем с того что подразумевается под выполнением в процессе и контекстах прерывания, а также минимально, но давая всё необходимое по структуре VAS (virtual address space, пространства виртуальных адресов) процесса пользователя. Это знаменует определённый этап для вас: далее вы более подробно ознакомитесь с архитектурой ядра Linux, сосредотачиваясь на собственно организации структур задачи процесса/ потока и соответствующих им стеках - режимов пользователя и ядра. Затем мы приоткроем вам больше структуру задачи самого ядра (структуру данных "root"), как на самом деле пожинать сведения из неё, и даже выполнять итерации по различным спискам (задач). Оживят эту тему несколько модулей ядра.

Глава 7. Внутреннее устройство управления памятью - Существенные моменты, ключевая в некоторм смысле глава, окунается в существенные вопросы внутреннего устройства подсистемы управления памятью Linux, причём до той степени детализации, которая необходима типичному автору модуля или разработчику драйвера. Таким образом, это рассмотрение обязательно носит более теоретический характер, тем не менее, полученные здесь знания имеют для вас, разработчика ядра, решающее значение как в отношении понимания и применения соответствующих API- интерфейсов памяти ядра, так и для выполнения имеющей значение отладки на уровне ядра. Мы рассмотрим расщепление на ВМ (и как оно происходит в различных реальных архитектурах), получим глубокое понимание VAS пользователя (на это откроет нам глаза наша утилита procmap), а также сегмент самого ядра (или VAS ядра). Далее мы вкратце рассмотрим технику безопасности рандомизации схемы памяти ([K]ASLR) и закончим данную главу обсуждением организации физической памяти в Linux.

Глава 8. Выделение памяти ядра авторам модуля Часть I, пачкает наши руки API выделения памяти ядра (и, очевидно, её высвобождения). Сначала вы ознакомитесь с двумя "уровнями" распределения в Linux - распределителе листов (slab), который размещается поверх "механизма" распределения памяти самого ядра и распределителя страниц (или BSA). Мы вкратце узнаем об основах алгоритма распределения страниц и его структуре данных "freelist", эти сведения важны для принятия решения о том, какой уровень применять. Далее мы сразу же перейдём к практической работе по применению этих ключевых API. Рассматриваются основные идеи, лежащие в основе распределителя листов (или кэша) и API первичного распределителя ядра - kzalloc/ kfree. Важно отметить, что также описываются ограничения значения размера, недостатки и предосторожности при применении этих распространённых API. Кроме того, что в особенности полезно для авторов драйверов, мы рассмотрим современные API распределения памяти, управляемые ресурсами (процедуры devm_*()).

Глава 9. Выделение памяти ядра авторам модуля Часть II, следует далее, неким логическим образом, продолжая предыдущую главу. Здесь вы обучитесь тому как создавать индивидуальные кэши листов (что полезно для частых распределений и возвратов, например, в неком индивидуальном драйвере), причём совместно с с некоторой поддержкой относительно отладки распределения памяти на уровне листов.Затем вы разберётесь с API vmalloc() (и дружественных им), а также с их использованием. Очень важно, что рассмотрев большое число API для распределения и изъятия памяти ядра, вы теперь ознакомитесь с тем, как подобрать подходящий API, принимая во внимание конкретную ситуацию в которой вы пребываете. Данная глава завершается важным рассмотрением платформы "уничтожителя" OOM (Out Of Memory, нехватки памяти). Разобравшись с ним, вы вы также придёте к более глубокому пониманию того как в реальности работает выделение памяти в пространстве пользователя через технику подкачки по запросу.

Глава 10. Планировщик ЦПУ - Часть I, это первая часть из двух глав рассматривает некую полезную смесь относящихся к планированию ЦПУ в ОС Linux теории и практики. Первоначально уделяется внимание самым минимальным необходимым теоретическим знаниям о потоке, таких как KSR и доступные политики планирования ядра. Затем рассматриваются достаточные для того, чтобы вы разобрались как работает в современной ОС Linux планирование ЦПУ, подробности внутреннего устройства ядра. Попутно вы изучите как "визуализировать" планирование процессорных устройств при помощи таких мощных инструментов как perf; также рассматриваются атрибуты планирования (политика и приоритет в реальном масштабе времени).

Глава 11. Планировщик ЦПУ - Часть II, эта вторая часть планирования ЦПУ продолжает более глубокое рассмотрение данной темы. Здесь мы охватываем последующие инструменты визуализации для планирования ЦПУ (применяющие мощное программное обеспечение, такое как утилиты LTTng и trace-cmd). Далее мы погружаемся в маскирование сродства своего ЦПУ и то как запрашивать/ устанавливать его, управляя политикой и приоритетом планирования на по- поточной основе - насколько мощная функциональная возможность! Здесь представлен обзор значимости и важности контрольных групп (cgroups) наряду с занимательным примером распределения полосы пропускания ЦПУ через cgroups v2. Можете ли вы запускать Linux в качестве ОС реального времени? Да, это действительно так! Далее приводятся подробности того как это осуществлять. Завершаем данную главу мы обсуждением задержек (в отношении планирования) и того как замерять их.

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

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

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

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

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

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

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

Основные подробности относительно аппаратных и программных требований, а также их установки,целиком рассматриваются в подробностях в Главе 1, Настройка рабочего пространства ядра. Очень важно чтобы вы подробно прочли её и следовали всем приводимым в ней инструкциям.

Кроме того, мы проверили весь код из данной книги (он также имеет свой собственный репозиторий 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); лёгкое тестирование.

  • Гостевая ОС x86_64 x86_64 CentOS 8 (запущенная в Oracle VirtualBox 6.1); лёгкое тестирование.

Мы предполагаем, что когда вы запускаете Linux в качестве некого гостя (ВМ), основной системой хоста выступает либо Windows 10 или его последующие вариации (естественно, даже Windows 7 будет работать), либо последние дистрибутивы Linux (например, Ubuntu или Fedora), либо даже macOS.

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

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

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

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

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

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

Мы дополнительно снабжаем вас файлом PDF, который содержит цветные изображения экранных снимков/ схем, использованных в данной книге. Вы можете загрузить этот файл по адресу: http://www.packtpub.com/sites/default/files/downloads/9781789953435_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. Настройка рабочего пространства ядра
Технические требования
Запуск Linux в качестве гостевой ВМ
Установка 84- битного гостевого Linux
Включение в вашей системе расширенной поддержки виртуализации
Выделение достаточного пространства на имеющемся диске
Установка гостевых дополнений Oracle VirtualBox
Эксперименты с Raspberry Pi
Настройка необходимого программного обеспечения - дистрибутив и пакеты
Установка программных пакетов
Установка гостевых дополнений Oracle VirtualBox
Установка необходимых программных пакетов
Установка инструментальной линейки кросс- трансляции и QEMU
Установка кросс- компилятора
Важные замечания относительно установки
Дополнительные полезные проекты
Применение страниц руководства Linux
Вариант tldr
Определение местоположения и применение документации ядра Linux
Выработка документации вашего ядра из исходного кода
Инструментарий статического анализа для ядра Linux
Следующее поколение Инструментария трассировки Linux
Утилита procmap
Простой проект FOSS системы Linux встроенного ARM
Современные трассировка и анализ производительности при помощи [e]BPF
Проект LDV - Linux Driver Verification
Выводы
Вопросы
Дальнейшее чтение
Глава 2. Сборка ядра Linux 5.4 из исходного кода - Часть I
Технические требования
Предварительные замечания относительно сборки ядра
Номенклатура выпусков ядра
Рабочий поток разработки ядра - основы
Типы деревьев исходного кода ядра
Этапы сборки ядра из исходного кода
Этап 1 - получение дерева исходного кода ядра Linux
Выгрузка конкретного дерева ядра
Клонирование дерева Git
Этап 2 - выделение необходимого дерева исходного кода
Краткий тур по дереву исходного кода ядра
Этап 3 - настройка ядра Linux
Разбираемся с системой сборки kbuild
Достигаем установленной по умолчанию конфигурации
Получение хорошей отправной точки для настройки ядра
Настройка ядра для типичных встроенных систем Linux
Настройка ядра при помощи конфигурации дистрибутива как отправная точка
Регулировка настройки через подход localmodconfig
Начинаем при помощи подхода localmodconfig
Регулируем настройки своего ядра через создание UI menuconfig
Пример использования создания UI menuconfig
Дополнительно о kbuild
Поиск отличий в настройках
Индивидуализация меню ядра - добавление вашего собственного элемента меню
Файлы Kconfig*
Создание нового элемента меню в файле Kconfig
Некоторые подробности по языку самого Kconfig
Выводы
Вопросы
Дальнейшее чтение
Глава 3. Сборка ядра Linux 5.4 из исходного кода - Часть II
Технические требования
Этап 4 - сборка образа и модулей ядра
Этап 5 - установка модулей ядра
Определение местоположения модулей ядра внутри полученного исходного кода ядра
Получение модулей ядра установленными
Этап 6 - генерация образа initramfs и настройка начальной загрузки
Генерация образа initramfs в Fedora 30 и выше
Генерация образа initramfs - под капотом
Разбираемся с инфраструктурой initramfs
Зачем требуется инфраструктура initramfs?
Разбираемся с основами процесса запуска в x86
Дополнительно об инфраструктуре initramfs
Этап 7 - индивидуализация начального загрузчика GRUB
Персонализация GRUB - основы
Выбор ядра по умолчанию для запуска
Запуск нашей ВМ через начальный загрузчик GNU GRUB
Эксперименты с приглашением на ввод GRUB
Проверка настроек нашего нового ядра
Сборка ядра для Raspberry Pi
Шаг 1 - клонирование дерева исходного кода ядра
Шаг 2 - установка инструментальной линейки кросс- трансляции
Первый метод - установка пакета через apt
Второй метод - установка посредством исходного репозитория
Шаг 3 - настройка и сборка необходимого ядра
Различные советы по сборке ядра
Минимальные требования версии
Сборка ядра для другой площадки
Наблюдаем за исполнением сборки своего ядра
Усечённый синтаксис оболочки для процедуры сборки
Решение проблем с переключателями компилятора
Решение проблем с пропущенными заголовками разработки OpenSSL
Выводы
Вопросы
Дальнейшее чтение
Глава 4. Написание вашего первого модуля ядра - LKM, Часть I
Технические требования
Осваиваем архитектуру ядра - часть 1
Пространство пользователя и пространство ядра
API библиотек и системных вызовов
Составляющие пространства ядра
Пользуемся LKM
Инфраструктура LKM
Модули ядра внутри дерева исходного кода ядра
Написание нашего самого первого модуля ядра
Введение в наш код C LKM Hello, world
Разбиваем его на части
Заголовки ядра
Макросы модуля
Точки входа и выхода
Возвращаемые значения
Соглашение возврата 0/-E
Макросы ERR_PTR и PTR_ERR
Ключевые слова __init и __exit
Распространённые операции в модулях ядра
Сборка модуля ядра
Исполнение модуля ядра
Быстрый первый взгляд на printk() ядра
Перечисление всех живых модулей ядра
Выгрузка определённого модуля из памяти ядра
Наш удобный сценарий lkm
Разбираемся с ведением журнала ядра и printk
Применение закольцованного буфера в памяти ядра
Ведение журнала ядра и journalctl systemd
Применение уровней регистрации printk
Удобные макросы pr_<foo>
Запись на консоль
Запись вывода в консоль Raspberry Pi
Включение сообщений ядра pr_debug()
Ограничение по скорости экземпляров printk
Генерация сообщений ядра из пространства пользователя
Стандартизация вывода printk через макро pr_fmt
Переносимость и формат спецификаторов printk
Разбираемся с основами модуля ядра Makefile
Выводы
Вопросы
Дальнейшее чтение
Глава 5. Написание вашего первого модуля ядра - LKM, Часть II
Технические требования
`Наилучший` шаблон Makefile для ваших модулей ядра
Настройка `отладки` ядра
Кросс- компиляция модуля ядра
Установка системы под кросс- компиляцию
Попытка 1 - установка `особых` переменных среды
Попытка 2 - указание в качестве цели для Makefile правильного дерева исходного кода ядра
Попытка 3 - кросс- компиляция нашего модуля ядра
Попытка 4 - кросс- компиляция нашего модуля ядра
Получение минимальных сведений о системе
Будьте слегка более внимательны к безопасности
Лицензирование модулей ядра
Эмуляция `подобных библиотечным` функциональных возможностей для модулей ядра
Осуществление эмуляции библиотеки через множество исходных файлов
Разбираемся с областью действия функции и переменной в модуле ядра
Разбираемся с составлением стека модуля
Выполняем попытку составления стека модуля
Передача параметров в модуль ядра
Объявление и использование параметров модуля
Получение/ установка параметров модуля после вставки
Типы данных параметров и удостоверение
Удостоверение параметров модуля ядра
Перекрытие названия параметра модуля
Относящиеся к аппаратуре параметры ядра
Плавающая точка не допускается в ядре
Автоматически загружаемые модули при запуске системы
Модуль auto-loading - дополнительные сведения
Модули ядра и безопасность - обзор
Возможности регулировок файловой системы proc воздействуют на системный журнал
Криптографические подписи в модулях ядра
Общее отключение модулей ядра
Руководящие правила по стилю кодирования для разработчиков ядра
Вклад в ядро основной линии
Приступаем к вкладу в ядро основной линии
Выводы
Вопросы
Дополнительное чтение
Раздел 2. Разбираемся с ядром и работаем с ним
Глава 6. Существенные моменты внутреннего устройства ядра - Процессы и Потоки
Технические требования
Разбираемся с контекстами процессов и прерываний
Разбираемся с основами VAS процесса
Организация процессов, потоков и их стеков - пространства пользователя и ядра
Организация пространства пользователя
Организация пространства ядра
Суммируем текущую ситуацию
Просмотр стеков пользователя и ядра
Традиционный подход к просмотру имеющихся стеков
Просмотр стека пространства ядра заданного потока или процесса
Просмотр стека пространства пользователя заданного потока или процесса
[e]BPF - современный подход к просмотру обоих стеков
Обзор на 10 000 футов VAS конкретного процесса
Разбираемся со структурой задачи ядра и получаем к ней доступ
Взгляд на структуру задачи
Доступ к структуре задачи при помощи current
Определение контекста
Работа со структурой задачи через current
Встроенные вспомогательные методы ядра и оптимизация
Пробуем модуль ядра для вывода на печать сведений контекста
Убеждаемся в монолитности ОС Linux
Кодируем для безопасности при помощи printk
Выполняя итерации по спискам задач ядра
Выполняя итерации по списку задач I - отображение всех процессов
Выполняя итерации по списку задач II - отображение всех потоков
Различия между процессом и потоком - TGID и PID
Выполняя итерации по списку задач III - собственно код
Выводы
Вопросы
Дополнительное чтение
Глава 7. Внутреннее устройство управления памятью - Существенные моменты
Технические требования
Разбираемся с расщеплением ВМ
Заглядываем под капот - программа C Hello, world
Выход за рамки API printf ()
Расщепление ВМ в 64- битных системах Linux
Виртуальная адресация и трансляция адреса
VAS процесса - полное представление
Исследуем VAS процесса
Подробно исследуем VAS пользователя
Непосредственный просмотр карты памяти процесса при помощи procfs
Реализация вывода /proc/PID/maps
Страница vsyscall
Интерфейсы для представления карты памяти процесса
Утилита визуализации VAS процесса procmap
Разбираемся с основами VMA
Исследуем сегмент самого ядра
Верхняя память в 32- битных системах
Написание модуля ядра для отображения сведений относительно сегмента ядра
Представление самого сегмента ядра в Raspberry Pi через dmesg
Макросы и переменные, описывающие структуру сегмента ядра
Пробуем - просматриваем подробности сегмента ядра
VAS самого ядра через procmap
Пробуем - сегмент пользователя
Страница ловушки null
Просматриваем документацию ядра относительно структуры памяти
Рандомизация структуры памяти - KASLR
ASLR режима пользователя
KASLR
Запрос/ установка состояния KASLR при помощи сценария
Физическая память
Физическая организация оперативной памяти
Узлы
Зоны
Прямое соответствие оперативной памяти и трансляция адресов
Выводы
Вопросы
Дальнейшее чтение
Глава 8. Выделение памяти ядра авторам модуля Часть I
Технические требования
Введение в распределители памяти ядра
Разбираемся с распределителем страниц ядра (или BSA) и применяем его
Основы работы с распределителем страниц
Организация freelist
Работы распределителя страниц
Работая по нескольким сценариям
Самый простой случай
Более сложный случай
Вариант падения
Внутреннее устройство распределителя страниц - некоторые дополнительные подробности
Изучаем как пользоваться API распределителя страниц
Никогда не засыпать в прерывании или атомарных контекстах
Флаги GFP -погружаемся глубже
Работа с флагами GFP
Высвобождение страниц при помощи распределителя страниц
Написание модуля ядра для демонстрации применения API распределителя страниц
Развёртываем свой модуль ядра lowlevel_mem_lkm
Распределитель страниц и внутренняя фрагментация
API распределителя страниц exact
Разбираемся с распределителем листов ядра и используем его
Предмет идеи кэширования
Изучаем как пользоваться API распределителя листов
Выделение листов памяти
Высвобождение листов памяти
Структуры данных - некоторые подсказки архитектуры
Реальное кэширование листов применяемое для kmalloc
Написание модуля ядра для применения основ API листов
Ограничения по размеру API kmalloc
Тестирование наличия пределов - выделение памяти единственным вызовом
Проверка через псевдо- файл /proc/buddyinfo
Распределитель листов - некоторые дополнительные подробности
Применение API управляемого ресурсом выделения памяти ядра
Дополнительный вспомогательный API листов
Группы контроля и память
Предостережения при использовании распределителя листов
Лежащие в основе подробности и решения
Тестирование выделения листов при помощи ksize() - вариант 1
Тестирование выделения листов при помощи ksize() - вариант 2
Интерпретация вывода для варианта 2
Нанесение его на график
Реализации уровня листов внутри самого ядра
Выводы
Вопросы
Дальнейшее чтение
Глава 9. Выделение памяти ядра авторам модуля Часть II
Технические требования
Создание индивидуального кэша листов
Создание и применение индивидуального кэша листов внутри модуля ядра
Создание и индивидуального кэша листов
Применение новой кэшированной листами памяти
Уничтожение индивидуального кэша
Индивидуальный лист - демонстрационный модуль ядра
Разбираемся с уплотнителями листа
Сумируем за и против распределения листов
Отладка на уровне листов
Отладка посредством притравки листа
Тестируем - включаем ошибку UAF
Параметры отладки SLUB при запуске и во время работы
Разбираемся с API vmalloc() ядра и применяем его
Изучаем применение API семейства vmalloc
Краткое замечание относительно выделения памяти и подкачку страниц по запросу
Друзья vmalloc()
Определяя защиты памяти
Тестируем - быстрое подтверждение правильности концепции
Почему память доступна только на чтение?
API kmalloc() и vmalloc() - быстрое сопоставление
Распределение памяти в самом ядре - какой API применять и когда
Набор API визуализции выделения памяти ядра
Выбор подходящего API для выделения памяти ядра
Пара слов о DMA и CMA
Оставляем в живых - уничтожитель OOM
Высвобождение памяти - задача уборки ядра и OOM
Умышленная активация уничтожителя OOM
Активация уничтожителя OOM посредством Magic SysRq
Активация уничтожителя OOM c помощью сумасшедшей программы- распределителя
Разбираемся со стоящей за уничтожителем OOM рациональностью
Вариант 1 - vm.overcommit устанавливается равным 2, overcommit отключается
Вариант 2 - vm.overcommit устанавливается равным 0, overcommit включён, установлено по умолчанию
Подкачка страниц по запросу и OOM
Разбираемся со значением показателя OOM
Выводы
Вопросы
Дальнейшее чтение
Глава 10. Планировщик ЦПУ - Часть I
Технические требования
Изучение внутреннего устройства планирования ЦПУ - часть 1 - существенные основы
Чем является KSE в Linus?
Политики планирования POSIX
Визуализация всего потока
Применение perf для визуализации всего потока
Визуализации всего потока альтернативными походами (CLI)
Изучение внутреннего устройства планирования ЦПУ - часть 2
Разбираемся с модульными классами планирования
Опрашиваем значение класса планирования
Несколько слов об CFS и величине значения vruntime
Потоки - каковы политика и приоритет планирования
Изучение внутреннего устройства планирования ЦПУ - часть 3
Кто исполняет код планировщика?
Когда выполняется планировщик?
Часть прерывания по времени
Часть контекста самого процесса
Вытесняемое ядро
Точки входа планировщика ЦПУ
Переключатель контекста
Выводы
Вопросы
Дальнейшее чтение
Глава 11. Планировщик ЦПУ - Часть II
Технические требования
Визуализация всего потока при помощи LTTng и trace-cmd
Визуализация при помощи LTTng и Trace Compass
Фиксация сеанса трассировки ядра при помощи LTTng
Фиксация при помощи GUI - Trace Compass
Визуализация при помощи trace-cmd
Фиксация простого сеанса при помощи записи trace-cmd
Фиксация и интерпретация при помощи записи trace-cmd (CLI)
Фиксация и интерпретация при помощи графического интерфейса
Разбираемся с маской сродства ЦПУ, запрашиваем и устанавливаем её
Запрос и установка маски сродства потока ЦПУ
Применение taskset(1) для выполнения маски сродства ЦПУ
Установка маски сродства ЦПУ в потоке ядра
Запрашиваем и устанавливаем политику и приоритет планирования потока
Внутри самого ядра - в потоке ядра
Контроль над полосой пропускания ЦПУ при помощи cgroup
Поиск cgroups v2 в системе Linux
Тестируем - контроллер ЦПУ cgroups v2
Преобразовываем основную линию Linux в ОС РВ
Собираем RTL для основной линии ядра 5.x (в x86_64)
Получение исправлений RTL
Применяем исправлений RTL
Настраиваем и собираем своё ядро RTL
Основная линия и RTL - суммируем технические различия
Задержки и их измерение
Измеряем задержки планирования при помощи cyclictest
Получаем и применяем набор исправлений RTL
Устанавливаем cyclictest (и прочие необходимые пакеты) в своём устройстве
Исполняем имеющиеся варианты тестирования
Просматриваем полученные результаты
Измеряем задержки планирования через современный инструментарий BPF
Выводы
Вопросы
Дальнейшее чтение
Раздел 3. Окунаемся глубже
Глава 12. Синхронизация ядра- Часть I
Критические разделы, исключительное исполнение и атомарность
Что такое критический раздел?
Классический случай - глобальное i++
Концепции - блокировки
Резюме ключевых моментов
Связанные с одновременностью вопросы внутри самого ядра Linux
Системы SMP со множеством ядер и состязательность данных
Вытесняемые ядра, блокирующий ввод/ вывод и состязательность данных
Аппаратные прерывания и состязательность данных
Руководства по блокировками и взаимному блокирования
Взаимное исключение или спин блокировки? Что и когда применять
Определение того, какую блокировку применять - в теории
Определение того, какую блокировку применять - на практике
Применение блокировок взаимного исключения
Инициализация взаимного исключения
Правильное применение взаимного исключения
API взаимного исключения и его снятия, а также их применение
Взаимное исключение через сон с (без) прерывания?
Взаимное исключение - пример драйвера
Собственно взаимное исключение - несколько остающихся моментов
Варианты API взаимного исключения
Вариант trylock взаимного исключения
Вариант взаимного исключения с прерыванием и варианты с уничтожением
Вариант взаимного исключения ввода/ вывода
Семафор и взаимное исключение
Инверсия приоритета и взаимное исключение
Внутреннее проектирование
Применение спин блокировки
Спин блокировка - образец применения
Спин блокировка - образец драйвера
Проверка - засыпание в атомарном контексте
Проверка в отладчике ядра 5.4
Проверка в дистрибутиве без отладчика ядра 5.4
Блокировки и прерывания
Применение спин блокировок - краткое резюме
Выводы
Вопросы
Дополнительное чтение
Глава 13. Синхронизация ядра- Часть II
Применение интерфейсов refcount_t и atomic_t
Сопоставление более нового atomic_t и более старого refcount_t интерфейсов
Элементарные интерфейсы atomic_t и refcount_t
Примеры использования refcount_t внутри основы кода самого ядра
Использование атомарных операторов RMW
Атомарные операции RMW - действия с регистрами устройств
Применение побитовых операций RMW
Применение побитовых операций - некий пример
Действенный поиск побитовой маски
Применение спин блокировок читатель - писатель
Интерфейсы спин блокировок читатель - писатель
Пара слов предостережения
Семафор читатель - писатель
Воздействие кэширования и ложное совместное использование
Свободное от блокирований программирование с переменными для ЦПУ
Переменные для ЦПУ
Работа с выделением для ЦПУ
Выделение, инициализация и освобождение переменных для ЦПУ
Выполнение операций ввода/ вывода (чтения и записи) с переменными для ЦПУ
Выделение для ЦПУ - образец модуля ядра
Выделение для ЦПУ - применение внутри ядра
Отладка блокировок внутри самого ядра
Настройка ядра отладки для отладки блокировок
Средство проверки блокировок lockdep - раннее обнаружение проблем с блокировками
Примеры - перехват ошибок взаимной блокировки при помощи lockdep
Пример 1 - перехват собственной ошибки взаимной блокировки при помощи lockdep
Его исправление
Пример 2 - перехват взаимной блокировки AB-BA при помощи lockdep
lockdep - пояснения и проблемы
Пояснения lockdep
Проблемы lockdep
Статистические данные lockdep
Представление статистических данных lockdep
Барьеры памяти - введение
Пример использования барьера памяти в драйвере устройства
Выводы
Вопросы
Дальнейшее чтение
Дополнение A. Zonefs
Что представляют собой Зонированные хранилища и Инициатива Зонированных хранилищ?
Что такое Устройства Зонированного хранения?
Зачем нужны Зонированные хранилища?
Вариант SMR
NVMe и Зонированные пространства имён в Твердотельных устройствах
Инфраструктура данных - и Адаптивные Зонированные хранилища
Ядро Linux и Зонированные блочные устройства
Инициатива Зонированных хранилищ - Облегчение более широкой поддержки и внедрения приложений
Дополнительно о Зонированных хранилищах
Файловая система Zonefs стартовала в Linux® 5.6
Постойте, ещё одна файловая система Linux?
Кому вообще нужны Зонированные блочные устройства?
Что ожидать от Zonefs?
Упрощение принятия Зонированных хранилищ
ZoneFS - Файловая система зон для Зонированных блочных устройств
Введение
Зонированные блочные устройства
Обзор Zonefs
Записанные на диске метаданные
Подкаталоги типа зон
Зонированные файлы
Обычные зонированные файлы
Последовательные зонированные файлы
Варианты форматирования
Обработка ошибок ввода/ вывода
Варианты монтирования
Инструменты Пространства пользователя Zonefs
Примеры
Указатель