Глава 2. Сборка ядра Linux 5.4 из исходного кода - Часть I

Содержание

Глава 2. Сборка ядра Linux 5.4 из исходного кода - Часть I
Технические требования
Предварительные замечания относительно сборки ядра
Номенклатура выпусков ядра
Рабочий поток разработки ядра - основы
Типы деревьев исходного кода ядра
Этапы сборки ядра из исходного кода
Этап 1 - получение дерева исходного кода ядра Linux
Выгрузка конкретного дерева ядра
Клонирование дерева Git
Этап 2 - выделение необходимого дерева исходного кода
Краткий тур по дереву исходного кода ядра
Этап 3 - настройка ядра Linux
Разбираемся с системой сборки kbuild
Достигаем установленной по умолчанию конфигурации
Получение хорошей отправной точки для настройки ядра
Настройка ядра для типичных встроенных систем Linux
Настройка ядра при помощи конфигурации дистрибутива как отправная точка
Регулировка настройки через подход localmodconfig
Начинаем при помощи подхода localmodconfig
Регулируем настройки своего ядра через создание UI menuconfig
Пример использования создания UI menuconfig
Дополнительно о kbuild
Поиск отличий в настройках
Индивидуализация меню ядра - добавление вашего собственного элемента меню
Файлы Kconfig*
Создание нового элемента меню в файле Kconfig
Некоторые подробности по языку самого Kconfig
Выводы
Вопросы
Дальнейшее чтение

Сборка ядра Linux из исходного кода это занимательный способ начать ваше путешествие по разработке ядра! Успокойтесь, это длинное и трудное путешествие, но это забавно, не так ли? Тема сборки ядра сама по себе достаточно велика чтобы заслуженно быть разделённой на две главы, а это первая из них.

Первейшая цель данной главы и следующей за ней состоит в подробном описании того как в точности вы можете собрать с нуля некое ядро Linux, из его исходного кода. В этой главе вы первоначально изучите как выгружать дерево исходного кода стабильного унифицированного ядра Linux в свою гостевую ВМ (Виртуальную машину) Linux (под унифицированным - vanilla - ядром мы подразумеваем простой и обычный исходный код ядра по умолчанию, выпущенный сообществом ядра Linux в его репозитории, https://kernel.org/). Затем мы изучим слегка подробнее структуру исходного кода самого ядра - предоставив, по существу, представление на 10 000 футов базового кода ядра. Далее последует реальный рецепт сборки ядра.

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

В этой главе мы рассмотрим следующие вопросы:

  • Предварительные требования для сборки ядра Linux

  • Этапы сборки ядра из исходного кода

  • Шаг 1 - получение дерева исходного кода ядра Linux

  • Шаг 2 - выделение дерева исходного кода ядра

  • Шаг 3 - настройка необходимого ядра Linux

  • Индивидуализация меню своего ядра - добавление нашего собственного элемента меню.

Технические требования

Я предполагаю, что вы прошлись по Главе 1, Настройка рабочего пространства ядра и обладаете надлежащим образом подготовленной гостевой ВМ, исполняющей Ubuntu 18.04 LTS (либо CentOS 8 или последующих стабильных выпусков этих дистрибутивов) и установили все необходимые пакеты. Если это не так, я настоятельно рекомендую прежде всего покончить с этим.

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

Предварительные замечания относительно сборки ядра

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

Некоторые из основных ключевых моментов, которые мы обсудим в этом разделе содержат следующее:

  • Выпуск ядра, или номенклатура номера версии

  • Типичный рабочий поток разработки ядра

  • Присутствие различных типов деревьев исходного кода ядра внутри общего репозитория

Расставив по местам эти сведениями, вы будете лучше вооружены для продвижения по процедуре сборки ядра. Ладно, давайте пройдёмся по каждому из процедурных вопросов.

Номенклатура выпусков ядра

Чтобы увидеть номер версии ядра просто выполните в своей оболочке uname -r. Как вы в точности интерпретируете вывод uname -r В своей гостевое ВМ дистрибутиве Ubuntu версии 18.04 LTS мы исполняем uname (1), передавая параметр переключателя -r для отображения лишь значения текущей версии или выпуска ядра:


$ uname -r
5.0.0-36-generic
		
[Замечание]Замечание

Естественно, на момент прочтения данных строк ядро Ubuntu 18.04 LTS несомненно было обновлено до более позднего выпуска; это совершенно нормально. Ядро 5.0.0.36-generic было тем, с которым я столкнулся в Ubuntu 18.04.3 LTS на момент написания данной главы..

Современная номенклатура нумерации выпуска ядра Linux такова:


major#.minor#[.patchlevel][-EXTRAVERSION]
 	   

Она также часто записывается и поясняется как w.x[.y][-z].

Квадратные скобки вокруг компонентов patchlevel и EXTRAVERSION указывают на их необязательность. Приводимая далее таблица суммирует значения всех компонентов в значении номера выпуска:

Таблица 2-1. Номенклатура выпуска ядра Linux
# компонента выпуска Значение Образцы номеров

Major # (или w)

Основной или старший номер; в настоящий момент мы пребываем в последовательности ядра 5.x, следовательно значение сташего номера это 5.

2, 3, 4 и 5

Minor # (или x)

Младший номер, иерархически под старшим номером.

0 и далее

[patchlevel] (или y)

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

0 и далее

[-EXTRAVERSION] (или -z)

Также именуемый localversion; обычно применяется ядрами дистрибутива для отслеживания их внутренних изменений.

Разнятся; Ubuntu применяет w.x.y-'n'-generic

Итак, теперь мы можем интерпретировать номер выпуска ядра своего дистрибутива Ubuntu 18.04 LTS, 5.0.0-36-generic:

  • Major # или (w): 5

  • Minor # или (x): 0

  • [patchlevel] или (y): 0

  • [-EXTRAVERSION] или (-z): -36-generic

Обратите внимание, что ядра дистрибутива могут следовать в точности этим соглашениям или отклоняться от них, на самом деле это их дело. Обычные или унифицированные ядра, выпускаемые в https://www.kernel.org/ действительно следуют им (по крайней мере пока Линус не решит изменить их).

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

(a) В качестве интересного упражнения настройки своего ядра, позднее мы изменим компонент localversion ( синоним-EXTRAVERSION) того ядра, что мы соберём.

(b) Исторически, в в ядрах вплоть до 2.6 (иначе говоря, теперь уже это устарело), младший номер скрывал особое значение; когда его номер был чётным, это указывало на стабильный выпуск ядра, в случае нечётного это был нестабильный, или бета выпуск. Это уже не так.

Рабочий поток разработки ядра - основы

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

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

Подробное описание можно обнаружить внутри самой документации ядра здесь .

Распространённым заблуждением, в особенности в его младенческие годы, было то, что ядро Linux разрабатывается очень специальным образом. Это вовсе не так! Процесс разработки ядра (в целом) превратился в хорошо промасленную систему с тщательно задокументированным процессом и ожиданием того, что участник разработки ядра должен знать его, чтобы правильно им пользоваться. Я отсылаю вас к предыдущей ссылке за полными сведениями.

Чтобы мы могли взглянуть на типичный цикл разработки, представим себе, что у нас имеется самое последний Git дерева ядра основной линии Linux, клонированный в нашу систему.

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

Относящиеся к использованию мощного инструмента SCM (Source Code Management, управления исходным кодом) git(1) выходит за рамки этой книги. Обратитесь, пожалуйста к разделу Дальнейшее чтение за полезными ссылками по изучению того как применять Git. Очевидно, что я настоятельно рекомендую получить по крайней мере базовое знакомство с использованием git(1).

Как уже упоминалось ранее, поскольку на момент написания этих строк ядро 5.4 это самая последняя версия LTS (Long-Term Stable, долгосрочной стабильности), поэтому мы можем применять её в последующих материалах. Итак, как это произошло? Очевидно, что она эволюционировала из ядер rc (release candidate, кандидатов выпуска) и предшествующие ему предыдущие выпуски ядра, которыми в данном случае были бы ядра v5.4-rc'n' и стабильное v5.3, которое было перед ним. Для получения читаемого персоналом журнала тэгов в упорядоченном по датам дереве Git ядра мы пользуемся командой git log, которая следует далее. Здесь нас всего лишь интересует та работа, которая привела к выпуску нашего ядра 5.4 LTS, поэтому мы намеренно усекли приводимый ниже вывод, чтобы показать лишь эту часть:

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

Команда git log (которую мы применяем в своём следующем блоке кода и фактически все прочие подчинённые команды git) будут работать только с неким деревом git. Мы применяем приводимое ниже исключительно для демонстрации собственно эволюции своего ядра. Слегка позже мы покажем вам как вы можете клонировать некое дерево Git.


$ git log --date-order --graph --tags --simplify-by-decoration --pretty=format:'%ai %h %d'
* 2019-11-24 16:32:01 -0800 219d54332a09  (tag: v5.4)
* 2019-11-17 14:47:30 -0800 af42d3466bdc  (tag: v5.4-rc8)
* 2019-11-10 16:17:15 -0800 31f4f5b495a6  (tag: v5.4-rc7)
* 2019-11-03 14:07:26 -0800 a99d8080aaf3  (tag: v5.4-rc6)
* 2019-10-27 13:19:19 -0400 d6d5df1db6e9  (tag: v5.4-rc5)
* 2019-10-20 15:56:22 -0400 7d194c2100ad  (tag: v5.4-rc4)
* 2019-10-13 16:37:36 -0700 4f5cafb5cb84  (tag: v5.4-rc3)
* 2019-10-06 14:27:30 -0700 da0c9ea146cb  (tag: v5.4-rc2)
* 2019-09-30 10:35:40 -0700 54ecb8f7028c  (tag: v5.4-rc1)
* 2019-09-15 14:19:32 -0700 4d856f72c10e  (tag: v5.3)
* 2019-09-08 13:33:15 -0700 f74c2bb98776  (tag: v5.3-rc8)
* 2019-09-02 09:57:40 -0700 089cf7f6ecb2  (tag: v5.3-rc7)
* 2019-08-25 12:01:23 -0700 a55aa89aab90  (tag: v5.3-rc6)
[...]
		

Ага! В нашем предыдущем блоке кода вы можете ясно видеть, что наше стабильное ядро 5.4 было выпущено 24 ноября 2019, а дерево 5.3 15 сентября 2019 (естественно, вы можете удостовериться в этом в прочих полезных ресурсах, например, в https://kernelnewbies.org/LinuxVersions).

Для рассматриваемой последовательности разработок, которая в конечном итоге привела к нашему ядру 5.4, эта последняя дата (15 сентября 2019) знаменует дату старта того, что носит название окна слияния для следующего стабильного ядра на период (около) двух недель. На этот период разработчикам разрешается представлять на рассмотрение новый код в имеющееся дерево ядра (на самом деле, реальная работа должна была бы проводиться намного раньше; все плоды этой работы теперь слиты в данный момент в основную ветку).

Двумя неделями позже (30 сентября 2019), это окно слияния было закрыто и стартовала работа над rc ядра, причём, естественно, 5.4-rc1 стала самой первой из версий rc. Такие деревья -rc (также именуемые предваряющими заплатками) в первую очередь работают над слиянием исправлений и исправлением (регрессионных) ошибок, в конечном итоге приводя к тому, что по мнению главных сопровождающих (Линуса Торвальдса и Эндрю Мортона) рассматривается как "стабильное" дерево ядра. Общее число предваряющих заплаток (выпусков span class="term">-rc) может быть разным. Тем не менее, обычно такое окно "исправления ошибок" требует где- то от 6 до 10 недель, по истечению которых выпускается новое стабильное ядро. В своём предыдущем блоке кода мы можем обнаружить, что в конечном итоге восемь кандидатов выпуска привели в результате к стабильному выпуску дерева 5.4 24 ноября 2019 (что заняло в общей сложности 0 дней).

То же самое можно визуально увидеть через страницу выпусков:

 

Рисунок 2-1


Приведшие к ядру 5.4 LTS выпуски (читайте снизу вверх)

Наш предыдущий снимок экрана это частичный снимок экрана, который показывает как различные кандидаты выпуска ядра v5.4-rc'n' в конечном итоге привели к выпуску дерева LTS 5.4 (5 ноября 2019 и при этом v5.4-rc'8' был последним выпуском rc). Эта работа на самом деле никогда не прекращается: в начале декабря 2019 вышел в свет кандидат выпуска v5.5-rc'1'.

В общем случае, выбрав в качестве примера последовательность ядра 5.x (то же самое остаётся справедливым для всех прочих самых последних серий основного ядра), рабочий поток разработки ядра выглядит следующим образом:

  1. Выполняется стабильный выпуск 5.x. Тем самым, начинается окно слияния для следующего (в основной ветке) ядра 5.x+1.

  2. Окно слияния остаётся открытым примерно 2 недели и в основной ветке сливаются новые исправления.

  3. Когда (как правило) 2 недели проходят, это окно слияний закрывается.

  4. Стартуют ядра rc (синоним предваряющих исправлений основной ветки). 5.x+1-rc1, 5.x+1-rc2, ... 5.x+1-rcn. Этот процесс требует около 6 - 8 недель.

  5. Появляется новый стабильный выпуск: выпускается новое стабильное 5.x+1 ядро.

  6. Этот выпуск пассивно обрабатывается "командой стабильности"

    • Существенные исправления ошибок или проблем безопасности в результате приводят к выпускам 5.x+1.y: 5.x+1.1, 5.x+1.2, ..., 5.x+1.n.

    • Сопровождение производится до следующей стабильной версии или наступает дата EOL (End Of Life).

...и весь процесс повторяется.

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

Типы деревьев исходного кода ядра

Существуют различные типы деревьев исходного кода ядра Linux. Самым ключевым выступает ядро LTS (Long Term Support, Долговременной поддержки). Ладно, что в точности представляет собой ядро выпуска LTS. Это просто некий "специальный" выпуск в том плане, что разработчики ядра будут продолжать вносить в него без существенных изменений важные исправления ошибок и проблем безопасности (хорошо, проблемы безопасности это обычно не что иное как ошибки), причём вплоть до даты EOL (окончания времени жизни).

Термин "время жизни" некого ядра LTS обычно минимально будет 2 годами и он может продолжаться несколько больше (порой оно расширяется). ядро LTS 5.4, которое будет применяться на протяжении данной книги выступает 20м ядром LTS и обладает продолжительностью жизни в 6 лет - с ноября 2019 по декабрь 2025. {Прим. пер.: На момент перевода также имеется ядро LTS 5.10, ограниченное EOL декабрь 2022.}

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

  • Деревья -next: Это действительно передовой край, деревья подсистем с новыми исправлениями, собираемыми здесь для проверки и рассмотрения. Это именно то, над чем будет работать участник восходящего ядра.

  • Предварительные исправления, также именуемые -rc или основной линией: Это ядра претендентов на выпуск (release candidate), которые вырабатываются перед неким выпуском.

  • Стабильные ядра: Как подразумевает их название, именно они представляют конечный бизнес. Эти ядра обычно прихватываются дистрибутивами и прочими проектами (по крайней мере для начала работы с ним). Они также носят название унифицированных ядер (vanilla kernels).

  • Ядра распространения и LTS: Ядра распространения (очевидно) являются теми ядрами, которые представлены в дистрибутивах. Обычно они начинаются с некого базового унифицированного/ стабильного ядра. Ядра LTS это намеренно обслуживаемые на протяжении длительного времени ядра, что делает их особенно полезными для промышленных/ производственных проектов и продуктов.

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

    В этой книге мы будем работать над самым последним ядром LTS на момент написания этой книги, коим выступает ядро LTS 5.4. Как я уже упоминал в Главе 1, Настройка рабочего пространства ядра. Изначально ядро LTS 5.4 было запущено со сроком EOL "по крайней мере до декабря 2021". В настоящий момент времени (июнь 2020), он был передвинут на декабрь 2025, оставляя содержимое этой книги актуальным и допустимым на годы вперёд!

  • Ядра Super LTS (SLTS): Ещё более длительное время поддерживаемые ядра LTS (согласно Платформ гражданской инфраструктуры, проекту Фонда Linux).

Это достаточно понятно интуитивно. Тем не менее, я отсылаю вас к странице Releases kernel.org для получения подробностей по типу выпуском ядер. И снова, за ещё большими подробностями, обращайтесь к Как действует процесс разработки.

Интересно отметить, что некоторые ядра LTS обладают очень долговременными, уместно получившими название ядер SLTS или Super LTS. Например, ядро Linux 4.4 (16й выпуск LTS) может рассматриваться как ядро SLTS. В качестве самого первого ядра, выбранного под SLTS, уже упомянутая Платформа гражданской инициативы будет предоставлять сопровождение по крайней мере до 2026, а возможно и до 2036 года.

Выполнение запросов к репозиторию www.kernel.org неким не интерактивным образом в виде сценария может быть осуществлён с применением curl(1) (ниже приводится вывод текущего состояния Linux по состоянию на 05 января 2021):


$ curl -L https://www.kernel.org/finger_banner
The latest stable version of the Linux kernel is: 5.10.4
The latest mainline version of the Linux kernel is: 5.11-rc2
The latest stable 5.10 version of the Linux kernel is: 5.10.4
The latest stable 5.9 version of the Linux kernel is: 5.9.16 (EOL)
The latest longterm 5.4 version of the Linux kernel is: 5.4.86
The latest longterm 4.19 version of the Linux kernel is: 4.19.164
The latest longterm 4.14 version of the Linux kernel is: 4.14.213
The latest longterm 4.9 version of the Linux kernel is: 4.9.249
The latest longterm 4.4 version of the Linux kernel is: 4.4.249
The latest linux-next version of the Linux kernel is: next-20210105
$
		

Наконец, ещё один безопасный способ выгрузки заданного ядра предоставляется самими поддерживающими это ядро, которые предлагают некий сценарий для безопасной выгрузки определённого дерева исходного кода ядра Linux, проверяя его подпись PGP. Этот сценарий доступен здесь.

Итак, теперь, когда мы вооружены знаниями о номенклатуре версий ядра и типами деревьев исходного кода ядра, настало время нашего путешествия по сборке нашего ядра.

Этапы сборки ядра из исходного кода

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

  1. Получить дерево исходного кода ядра Linux в виде одного из следующих вариантов:

    • Выгрузка исходного кода конкретного ядра виде некого сжатого файла

    • Клонирование некого дерева Git (ядра)

  2. Раскрыть дерево исходного кода полученного ядра в неком местоположении в вашем домашнем каталоге (если вы получили ядро клонированием дерева Git, пропускайте этот шаг).

  3. Настройка Выберите варианты поддержки своего ядра которые требуются для вашего нового ядра, make [x|g|menu]config, причём предпочтительным способом выступает make menuconfig .

  4. Сборка необходимых загружаемых моделей ядра и всех DTB (Device Tree Blobs, BLOB-ов дерева устройств) при помощи make [-j'n'] all. Это выполняет сборку соответствующего образа сжатия ядра (arch//boot/[b|z|u]image), образа ядра без сжатия vmlinux System.map, объектов модуля самого ядра и всех файлов настроек DTB.

  5. Установка только что собранных модулей при помощи sudo make modules_install. Этот этап устанавливает модули по умолчанию в /lib/modules/$(uname -r)/.

  6. Настройка начального загрузчика GRUB и образа initramfs (ранее носившая название initrd) (специфичного для x86): sudo make install:

    • Здесь создаётся и устанавливается образ initramfs (initrd) в /boot.

    • Это обновляет файл настрое начального загрузчика на запуск нового ядра (первой записи).

  7. Индивидуальная настройка меню начального загрузчика GRUB (не обязательно).

Эта глава, будучи первой из двух по данной теме, по сути дела рассмотрит шаги с 1 по 3, также рассматривая множество необходимых лежащих в основе материалов. Наша следующая глава осветит все остальные этапы, с 4 по 7. Итак, давайте приступим к этапу 1.

Этап 1 - получение дерева исходного кода ядра Linux

В этом разделе мы рассмотрим два проторённых пути, которыми мы имеем возможность получения дерева исходного кода Linux:

  • Через выгрузку и раскрытие конкретного дерева ядра исходного кода ядра из общедоступного репозитория ядра (https://www.kernel.org/)

  • Путём клонирования дерева исходного кода Линуса Торвальда (или иного) - например, дерева Git linux-next.

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

Для тех парней, которые намерены вносить свой вклад в "восходящий" код ядра основной линии, именно второй подход - клонирование дерева Git - это путь ваших действий. (Естественно, много чего ещё имеется здесь; мы обсудим некоторые подробности в своём разделе Типы деревьев исходного кода ядра).

В своём следующем разделе мы продемонстрируем оба подхода. Прежде всего мы опишем тот подход, в котором выгружается из соответствующего репозитория ядра конкретное дерево исходного кода ядра (не дерево Git). По ситуации на момент написания этих строк мы выбираем для этой цели самого последнего ядра LTS Linux 5.4. В своём втором пожходе мы выполним клонирование дерева Git.

Выгрузка конкретного дерева ядра

Прежде всего, где расположен исходный код необходимого нам ядра? Короткий ответ состоит в том, что это общедоступный сервер репозитория виден по адресу https://www.kernel.org/. Домашняя страница этой площадки отображает самые стабильные версии ядра Linux, а также самые последние выпуски longterm и linux-next (следующий далее снимок экрана отображает эту площадку по состоянию на 29 ноября 2019. Он отображает даты в хорошо известном формате yyyy-mm-dd):

 

Рисунок 2-2


Площадка kernel.org (по состоянию на 29 ноября 2019)

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

Быстрое напоминание: мы также предоставляем файл PDF, который имеет цветные образы применяемых в этой книге экранных снимков/ схем. Вы можете выгрузить его здесь.

Имеется множество способов выгрузки некого (сжатого) файла исходного кода ядра. Давайте рассмотрим два из них:

  • Интерактивный способ, и скорее всего самый простой, состоит в том чтобы вы посетили указанный ранее вебсайт и просто кликнули по соответствующей ссылке tarball. Ваш браузер выгрузит в вашу систему необходимый файл образа (в формате .tar.xz).

  • В качестве альтернативы вы можете выгрузить его через командную строку (оболочку или соответствующий CLI) при помощи утилиты wget(1) (то же самое вы можете сделать воспользовавшись мощной утилитой curl(1)). Например, для выгрузки стабильного сжатого файла исходного кода ядра 5.4.0, мы можем выполнить следующее:

    
    > wget --https-only -O ~/Downloads/linux-5.4.0.tar.xz https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.0.tar.xz
    		
[Совет]Совет

Если предыдущая утилита wget(1) не сработала, скорее всего это из- за того, что изменилась ссылка на необходимый (сжатый) tarball ядра. Например, если это не работает для 5.4.0.tar.xz, попробуйте ту же самую утилиту wget, но измените значение версии на 5.4.1.tar.xz.

Это безопасно выгрузит сжатое дерево исходного кода ядра в папку вашего компьютера ~/Downloads. Естественно, вы можете не захотеть ту версию ядра, которая отображена в домашней странице данного репозитория. Например, что если для своего конкретного проекта я нуждаюсь в самом последнем стабильном (LTS) ядре 4.19, 19м выпуске LTS? Всё просто через браузер кликните по ссылке https://www.kernel.org/pub/ (или в зеркале https://mirrors.edge.kernel.org/pub/), непосредственно справа от ссылки "HTTP", отображённой в самых первых нескольких строках, и перейдите в соответствующий каталог linux/kernel/v4.x/ вашего сервера (вы можете быть перенаправлены в некую площадку зеркала). Либо просто укажите для wget(1) необходимый URL (в данном случае, на момент написания этих строк, это был https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.19.164.tar.xz).

Клонирование дерева Git

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

В этой книге, однако, мы не собираемся погружаться в кровавые подробности настройки дерева linux-next. Такой процесс уже хорошо документирован и мы бы предпочли не повторять просто инструкции (за подробностями отсылаем вас к ссылкам из раздела Дальнейшее чтение). Подробная страница о том как в точности вам надлежит клонировать дерево linux-next, находится тут: Working with linux-next и, как уже упоминалось ранее, дерево linux-next выступает областью, содержащей исправления, предназначенных для окна слияния следующего ядра. Если вы находитесь на переднем крае разработки нового ядра, возможно, вы пожелаете работать с этим деревом, а не с деревом основной линии Линуса Торвальдса.

Для наших целей клонирования репозитория Git Linux основной линии (mainline, дерева Git Линуса Торвальдса) более чем достаточно. Сделайте это так (набирайте это в одной строке):


> git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
		
[Совет]Совет

Обратите внимание, что клонирование дерева ядра Linux целиком является требовательной к времени, сети и потреблении диска операцией! Будьте уверены что у вас имеется свободным достаточное дисковое пространство (неплохо бы иметь по крайней мере несколько гигабайт).

Выполнение git clone --depth n <...>, где n это целое значение, очень полезно для ограничения глубины истории (фиксаций) и тем самым удерживает выгрузку/ использование диска на более низком уровне. Как упоминает страница man для параметра --depth git-clone(1): "Создаёт неглубокий клон с историей, усекаемой до предписанного числа фиксаций".

Следуя приведённому выше совету, почему бы не последовать так (опять же, наберите это в одной строке)?


> git clone --depth=3 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
		

Если вы намерены работать с этим деревом Git основной линии, пожалуйста, пропустите раздел Этап 2 - выделение необходимого дерева исходного кода (поскольку операция git clone в любом случае раскроет необходимое дерево исходного кода) и продолжайте со следующим разделом Этап 3 - настройка ядра Linux.

Этап 2 - выделение необходимого дерева исходного кода

Как уже упоминалось ранее, этот раздел предназначен тем, кто выгрузил определённое ядро Linux из его репозитория, https://www.kernel.org/, и имеет целью собрать его. В этой книге мы пользуемся выпуском ядра LTS 5.4. С другой стороны, если вы осуществили git clone дерева основной линии Git Linux, как было показано в нашем предыдущем разделе, вы без всякой опаски можете опустить этот раздел и перейти к следующему по настройке ядра.

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

Мы предполагаем, что как то подробно было показано ранее в этой главе, вы теперь обладаете выгруженным базовым кодом ядра Linux версии 5.4 в виде сжатого файла (в каталоге ~/Downloads):


$ cd ~/Downloads ; ls -lh linux-5.4.tar.xz
-rw-rw-r-- 1 llkd llkd 105M Nov 26 08:04 linux-5.4.tar.xz
		

Самым простым способом для раскрытия этого файла служит применение для этого вездесущей утилиты tar(1):


$ tar xf ~/Downloads/linux-5.4.tar.xz
		

Это раскроет наше дерево исходного кода ядра в каталог с названием linux-5.4 внутри текущего каталога ~/Downloads. Но что если вы желаете выделить его в другой папке, скажем в ~/kernels Тогда сделайте следующее:


$ mkdir -p ~/kernels
$ tar xf ~/Downloads/linux-5.4.tar.xz --directory=${HOME}/kernels/
		

Это раскроет исходный код ядра в вашей папке ~/kernels/linux-5.4/. Согласно соглашениям, и это хороший практический приём, давайте настроим некую переменную окружения для указания на это местоположение нашего корня дерева исходного кода ядра:


$ export LLKD_KSRC=${HOME}/kernels/linux-5.4
		
[Замечание]Замечание

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

Хотя для выделения сжатого файла вы и можете пользоваться приложением управления файлами с графическим интерфейсом (таким как Nautilus(1)), я настойчиво побуждаю вас быть знакомыми с применением интерфейса командной строки Linux для выполнения подобных действий.

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

Не забывайте про tldr(1) когда вам требуется быстро просмотреть наиболее часто применяемые варианты распространённых команд! Например, для tar(1), просто воспользуйтесь для просмотра tldr tar.

Вы заметили? Мы выделили дерево исходного кода своего ядра в любом каталоге из своего домашнего каталога (или даже вообще где угодно), в то время как в прошлые дни это дерево всегда раскрывалось в местоположении доступном для записи root (чаще всего, в /usr/src/). В наши дни просто скажите (этому) нет.

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

Краткий тур по дереву исходного кода ядра

В вашей системе теперь доступен исходный код необходимого ядра! Круто, давайте бегло посмотрим на него:

 

Рисунок 2-3


Корень дерева исходного кода ядра Linux 5.4

Отлично! Насколько оно большое? Быстрый du -m . в корне дерева исходного кода нашего ядра выявит, что конкретно это дерево исходного кода ядра (напомним, в версии 5.4) по размеру чуть меньше чем 1 000МБ - почти гигабайт!

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

К вашему сведению, размер ядра Linux рос и становится всё больше и больше в терминах строк исходного кода (SLOC, Source Lines Of Code). Текущий оценивается примерно в более чем 20 миллионов строк. Естественно, будем справедливы, не весь этот код будет скомпилирован при сборке ядра.

Как теперь мы узнаем какова в точности версия этого кода ядра Linux, просто просматривая его исходный текст Это легко, один из быстрых способов состоит в простой проверке самых первых строк Makefile данного проекта. Между прочим, наше ядро повсеместно применяет Makefile; им обладает большинство каталогов. На данный Makefile, который расположен в самом корне дерева исходного кода ядра, мы будем обозначать как Makefile верхнего уровня:


$ head Makefile
# SPDX-License-Identifier: GPL-2.0
VERSION = 5
PATCHLEVEL = 4
SUBLEVEL = 0
EXTRAVERSION =
NAME = Kleptomaniac Octopus

# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
# More info can be located in ./README
$
		

Ясно, это исходный код нашего ядра 5.4.0.

Давайте сделаем для себя представление на 10 000 футов дерева исходного кода ядра. В нашей следующей таблице суммируются обширное разбиение на категории и цели (наиболее) важных файлов и каталогов в корне дерева исходного кода ядра:

Таблица 2-2. Схема дерева исходного кода ядра Linux
Название файла или каталога Назначение

Файла верхнего уровня

README

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

COPYING

Лицензионные термины в соответствии с которыми выпущен исходный код данного ядра. Подавляющее большинство выпускается под хорошо знакомой лицензией GNU GPL v2 (записываемой как GPL-2.0)[1]

MAINTAINERS

ЧаВо: как- то неважно выглядит XYZ, с кем мне контактировать когда что- то происходит? Это именно то в точности, что предоставляет данный файл - это список всех подсистем ядра, в самом деле, вплоть до уровня отдельных компонентов (таких как определённый драйвер), его состояния, кто в данный момент сопровождает его, список адресов электронной почты, вебсайт и тому подобное. Имеется даже вспомогательный сценарий для поиска определённой персоны или команды для обсуждения: scripts/get_maintainer.pl[2]

Makefile

Это Makefile верхнего уровня; системный построитель ядра kbuild и модуди ядра применяют этот Makefile (по крайней мере изначально) для своей сборки.

Каталоги основной подсистемы

kernel/

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

mm/

Здесь обитает пакет кода управления памятью (mm, memory management). Мы слегка затронем его в Главе 6, Существенные моменты внутреннего устройства ядра - Процессы и Потоки, а также некоторые материаля связанные с ним охватываются в Главе 7, Внутреннее устройство управления памятью - Существенные моменты, а также в Главе 8, Выделение памяти ядра авторам модуля Часть I.

fs/

Располагаемый здесь код реализует две ключевые функциональные возможности файловой системы: уровень абстракции - VFS (Virtual Filesystem Switch, переключатель виртуальной файловой системы) и драйверы индивидуальных файловых систем (ext[2|4], btrfs, nfs, ntfs, overlayfs, squashfs, jffs2, fat, f2fs и тому подобных.

block/

Путь кода, лежащего в основе блочного ввода/ вывода (VFS/ FS). Он содержит собственно код реализации кэширования страниц, общий уровень блочного ввода/ вывода, планировщики ввода/ вывода и тому подобное.

net/

Полная (буквально следуя Request For Comments - RFC) реализация стека сетевого протокола. Содержит высококачественную реализацию TCP, UDP, IP и многих прочих сетевых протоколов.

ipc/

Код подсистемы IPC (Inter-Process Communication, межпроцессного взаимодействия); охватывает такие механизмы IPC (и для SysV, и для POSIX), как очереди сообщений, совместную память, семафоры и тому подобное.

sound/

Код аудио системы, также носящий название ALSA (Advanced Linux Sound Architecture).

virt/

Собственно код виртуализации (гипервизора); здесь реализована популярная и мощная KVM (Kernel Virtual Machine, ВМ на основе ядра).

Инфраструктура/ разное

arch/

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

crypto/

Данный каталог содержит реализацию шифров уровня ядра (алгоритма шифрования/ дешифрации, также известные как преобразования) и API ядра для обслуживания потребителей, которым требуются криптографические службы.

include/

Этот каталог содержит независимые от архитектуры заголовки ядра (также имеется ряд зависящих от архитектуры заголовков в arch/<cpu>/include/...).

init/

Это независимый от архитектуры код инициализации ядра; здесь находится, возможно, самое близкое к тому, что мы получаем в функции main самого ядра (помните, ядро не является приложением): init/main.c:start_kernel() с функцией start_kernel() внутри неё, рассматриваемой в качестве самой начальной точки входа C в процессе инициализации ядра.

lib/

Ближайший аналог некой библиотеки для самого ядра. Важно осознавать, что само ядро не поддерживает разделяемые библиотеки, как то делают прикладные приложения пространства пользователя. Располагаемый здесь код автоматически связывается с основным файлом образа ядра и следовательно доступен этому ядру во время его исполнения (внутри /lib располагаются разнообразные компоненты: [раз]архивирование, контрольные суммы, побитные маски, математические операции, подпрограммы обработки строк, алгоритмы обхода деревьев и тому подобное).

scripts/

Здесь помещаются разнообразные сценарии, некоторые из которых применяются при сборке ядра, а многие для прочих целей (таких как статический/ динамический анализ и тому подобное; в основном Bash и Perl).

security/

Помещает LSM (Linux Security Module, модуль безопасности Linux), некую платформу Mandatory Access Control (MAC, мандатного контроля за доступом), которая имеет целью выставление более строгого контроля доступа для прикладных приложений пространства пользователя в пространство ядра, нежели это делает по умолчанию ядро (устанавливаемая по умолчанию модель носит название Discretionary Access Control (DAC, разграничительного контроля доступа). В настоящее время Linux поддерживает различные LSM; наиболее известными являются SELinux, AppArmor, Smack, Tomoyo, Integrity и Yama (обратите внимание, что LSM по умолчанию отключён)).

tools/

Здесь располагаются различные инструменты, в основном, приложения (или сценарии) пространства пользователя, которые "тесно связаны" с самим ядром (исключительным образцом служит perf, современный инструмент профилирования).

Ниже приводятся важные пояснения по этой таблице:

  • [1]Лицензирование ядра: Не вдаваясь в юридические подробности, вот практическая суть вещей: поскольку само ядро выпускается под лицензией GNU GPL-2.0 (GNU GPL это GNU General Public License), общедоступная лицензия GNU), всякий напрямую применяющий базовый код ядра проект (даже его крошечную часть!), автоматически подпадает под данную лицензию (свойство "производной работы" GPL-2.0). Такие проекты или продукты обязаны выпускать свои ядра в той же самой терминологии лицензирования. С практической точки зрения ситуация на местах гораздо более туманна; многие исполняющие ядро Linux продукты обладают внутри себя частным кодом пространства пользователя и/ или ядра. Обычно они осуществляют это через повторное производство ядра (зачастую драйвера устройства), работающего в формате Loadable Kernel Module (LKM, загружаемого модуля ядра). Имеется возможность выпуска определённого модуля ядра (LKM) под моделью двойной лицензии (например, в качестве двойного BSD/GPL; сам LKM является предметом рассмотрения Главы 4, Написание вашего первого модуля ядра - LKM, Часть I, и Главы 5, Написание вашего первого модуля ядра - LKM, Часть II и там мы рассмотрим некоторые сведения относительно лицензирования модулей ядра). Некоторые парни предпочитают частное лицензирование, управляя выпусками их кода ядра внутри модуля ядра, который не лицензируется в терминологии GPL-2.0; технически это возможно, но (по крайней мере) считается антисоциальным (и может пересекать черту законности). Те, кто заинтересовался этим вопросом, могут найти дополнительные ссылки по лицензированию в документе Дальнейшее чтение для данной главы.

  • [2]MAINTAINERS: Вот некий пример запуска сценария Perl get_maintainer.pl (обратите внимание: он предназначен для запуска исключительно в дереве Git):

    
    $ scripts/get_maintainer.pl -f drivers/android/
    Greg Kroah-Hartman  (supporter:ANDROID DRIVERS)
    "Arve Hjønnevåg"  (supporter:ANDROID DRIVERS)
    Todd Kjos  (supporter:ANDROID DRIVERS)
    Martijn Coenen  (supporter:ANDROID DRIVERS)
    Joel Fernandes  (supporter:ANDROID DRIVERS)
    Christian Brauner  (supporter:ANDROID DRIVERS)
    devel@driverdev.osuosl.org (open list:ANDROID DRIVERS)
    linux-kernel@vger.kernel.org (open list)
    $
    		
  • [3]Портирование arch (ЦПУ) Linux:

    
    $ cd ${LLKD_KSRC} ; ls arch/
    alpha/ arm64/ h8300/   Kconfig     mips/  openrisc/ riscv/ sparc/ x86/
    arc/   c6x/   hexagon/ m68k/       nds32/ parisc/   s390/  um/    xtensa/
    arm/   csky/  ia64/    microblaze/ nios2/ powerpc/  sh/    unicore32/
    		
[Совет]Совет

Как разработчику ядра или драйвера, пролистывание дерева исходного кода ядра это то, к чему вам придётся привыкнуть (и даже получать удовольствие!). Поиск конкретной функции или переменной может оказаться непростой задачей, когда ваш код составляет примерно футбольное поле в 20 миллионов строк кода! Применяйте действенные инструменты просмотра кода. Я предлагаю инструменты FOSS (Free and Open Source Software) ctags(1) и cscope(1). Фактически, Makefile верхнего уровня имеет целями именно их:


make tags ; make cscope
 	   

Теперь мы закончили с Этапом 2, выделением дерева исходного кода! В качестве бонуса вы ознакомились с основами, относящимися к структуре исходного кода определённого ядра. Давайте теперь двинемся далее, к Этапу 3 и изучим как настраивать ядро Linux перед его сборкой.

Этап 3 - настройка ядра Linux

Конфигурирование нового ядра вероятно наиболее критичный шаг во всём процессе сборки ядра. Одна из имеющихся причин, по которой Linux является получившей признание её критиками операционной системой, это её универсальность. Распространённым заблуждением является представление о том, что существует отдельная база кода ядра Linux для сервера (корпоративного класса) , центра обработки данных, рабочей станции и крошечного встроенного устройства Linux - нет, все они пользуются одним и тем же унифицированным исходным кодом ядра Linux! Таким образом, тщательная настройка ядра под конкретный вариант применения (сервер, настольный, встроенный или гибридный/ индивидуальный компьютер) является мощными функциональной возможностью и требованием. И это именно то, во что мы погружаемся здесь.

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

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

Прежде всего, тем не менее, давайте подведём некую необходимую основу вод систему kbuild (kernel build).

Разбираемся с системой сборки kbuild

Та инфраструктура, которая применяется ядром Linux для настройки и построения самого ядра известна как система kbuild. Без погружения в кровопролитные подробности, такая система kbuild связывает воедино весь комплекс процесса настройки и построения через четыре ключевых компонента:

  • Символы CONFIG_FOO

  • Файл(ы) определения меню, именуемые Kconfig

  • Makefile (ы)

  • Собственно файл настроек всего ядра

Основные цели этих компонентов суммируются следующим образом:

Таблица 2-3. Главные компоненты системы сборки Kbuild
Компонента Kbuild Назначение, кратко

Символ настройки CONFIG_FOO

Всякий настраиваемый FOO ядра представляется неким макро CONFIG_FOO. В зависимости от выбора пользователя соответствующий макро разрешит одно из y, m или
n.
-y=yes: Подразумевает построение данной функциональной возможности в самом образе ядра
-m=module: Предполагает собрать его как обособленный объект, модуль ядра
-n=no: Имеет в виду отсутствие построения данной функциональной возможности
Обратите внимание, что CONFIG_FOO это цифробуквенная строка (как мы вскорости увидим, вы можете отыскать точное название варианта настройки при помощи параметра make menuconfig перемещаясь по вариантам настроек и выбирать соответствующую кнопку <Help>).

Файлы Kconfig

Именно здесь определяются символы CONFIG_FOO. Синтаксис самого kbuild предписывает его тип (Boolean, tristate, [alpha]numeric и тому подобное. Более того, для основанного на меню интерфейса пользователя (активируемого через один из make [menu|g|x]config), он определяет сами записи меню. Позднее, само собой, мы воспользуемся этой функциональной возможностью.

Makefile (ы)

Система kbuild применяет рекурсивный подход Makefile. Тот Makefile, который располагается в корневой папке исходного кода ядра именуется Makefile верхнего уровня, с наличием Makefile в каждой вложенной папке для сборки имеющегося в ней исходного кода. Унифицированный (vanilla) исходный код 5.4 в целом обладает более чем 2 500 Makefile!

Сам файл .config

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

Главное- получить рабочий файл .config. Как мы можем сделать это? Мы выполняем это итеративно. Начинаем мы с конфигурации "default" - основной темы нашего следующего раздела - и аккуратно продвигаемся по мере необходимости по своей настраиваемой конфигурации.

Достигаем установленной по умолчанию конфигурации

Итак, как вы определитесь с той первоначальной конфигурацией ядра, с которой начинать? Существуют различные технологии; несколько наиболее распространённых таковы:

  • Не указывайте ничего; сама система kbuild вытащит установленные по умолчанию настройки ядра.

  • Пользуйтесь имеющимися настройками ядра дистрибутива.

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

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

Это привносит существенный вопрос, где хранится конфигурация ядра по умолчанию?. Для выборки настроек по умолчанию система kbulid применяет перечень с приоритетами альтернативных схем. Такой приоритетный список (с первым обладающим наивысшим приоритетом) определяется в init/Kconfig:DEFCONFIG_LIST:


$ cat init/Kconfig
config DEFCONFIG_LIST
    string
    depends on !UML 
    option defconfig_list
    default "/lib/modules/$(shell,uname -r)/.config"
    default "/etc/kernel-config"
    default "/boot/config-$(shell,uname -r)"
    default ARCH_DEFCONFIG
    default "arch/$(ARCH)/defconfig"
config CC_IS_GCC
[...]
 	   

К вашему сведению, документация ядра по Kconfig (находящаяся здесь) описывает что представляет собой defconfig_list:


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

Из этого перечня вы можете видеть, что система kbuild сначала проверяет наличие файла .config в папке /lib/modules/$(uname -r). Если он находится, его значения будут применяться как используемые по умолчанию. В случае его отсутствия, следующая проверка выявляет присутствие файла /etc/kernel-config. При его наличии, по умолчанию его значения будут применяться его значения, а в случае его отсутствия, происходит переход к следующему варианту в последующем списке приоритетов, и так далее. Обратите внимание, что присутствие файла .config в самом корне дерева исходного кода ядра перечёркивает всё это!

Получение хорошей отправной точки для настройки ядра

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

Здесь, чтобы помочь вам разобраться с нюансами выбора верной отправной точки для настройки ядра (мы надеемся) типично:

  • Вначале применяйте подход для следования обычной небольшой встроенной системой Linux

  • Затем подход, при котором вы эмулируете имеющиеся настройки дистрибутива

  • Наконец, подход, при котором вы основываетесь на настройках ядра имеющихся (или прочих) модулей ядра системы (подход localmodconfig)

Давайте слегка более подробно изучим эти подходы.

Настройка ядра для типичных встроенных систем Linux

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

Примечательно, что сам по себе базовый код ядра предоставляет известные, проверенные и работающие файлы конфигурации ядра для различных аппаратных платформ. Нам просто нужно выбрать ту, которая соответствует (или ближе всего подходит) для нашей встраиваемой платы. Эти файлы настроек ядра представлены внутри дерева исходного кода ядра в каталоге arch/<arch>/configs/. Эти файлы настроек пребывают в формате Code<platformname>_defconfig.. Можно быстро взглянуть; обратите внимание на приводимый ниже снимок экрана, отображающий команду ls arch/arm/configs, выполняемую в базовом коде ядра Linux м5.4.

 

Рисунок 2-4


Содержимое arch/arm/configs в ядре Linux 5.4

Таким образом, скажем, когда вы настраиваете ядро Linux для аппаратной платформы, допустим, обладающей SoC (System on Chip) Samsung Exynos, будьте любезны не начинать с установленного по умолчанию файла настроек ядра x86-64 (или просто попробуйте с ним). Это не сработает. Даже если вы и управитесь с ним, такое ядро не будет собрано/ не заработает чисто. Подцепите более подходящий файл настроек: в вашем случае здесь, в качестве хорошей отправной точки, присутствует файл настроек arch/arm/configs/exynos_defconfig. Вы можете скопировать этот файл в .config в самом корне своего дерева исходного кода ядра и затем провести более тонкую настройку, необходимую под специфику вашего проекта.

В качестве другого примера, популярной платформой для хобби является Raspberry Pi (https:/​/​www.​raspberrypi.​org/). Сам файл настроек ядра - внутри его дерева исходного кода ядра - использует (в качестве основы): arch/arm/configs/bcm2835_defconfig. Данный файл отражает тот факт, что плата Raspberry Pi применяет SoC на базе Broadcom 2835. Вы можете отыскать относящуюся к нему компиляцию под Raspberry Pi здесь. Прервёмся, однако, мы рассмотрим по крайней мере некоторые из них в Главе 3, Сборка ядра Linux 5.4 из исходного кода - Часть II в разделе Сборка ядра для Raspberry Pi.

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

Простой способ для того чтобы узнать какой именно файл настроек подходит к какой из платформ состоит в том чтобы просто выполнить make help для самой целевой платформы. Последняя часть вывода отображает файлы с заголовком Специфичных для архитектуры целей (Architecture specific targets обратите внимание, что это служит для нестандартных ЦПУ и не работает для x86[-64]).

Аккуратная регулировка и настройка конфигурации ядра для продукта выступает важной частью работы, обычно выполняемой инженерами, работающими с некой платформой или в команде BSP ( Board Support Package, пакета поддержки платы).

Настройка ядра при помощи конфигурации дистрибутива как отправная точка

Типичной целевой системой для применения такого подхода выступают настольная или серверная система Linux.

Двигаясь далее, этот второй подход к тому же и скор:


cp /boot/config-5.0.0-36-generic ${LLKD_KSRC}/.config
		

Здесь мы просто копируем имеющийся файл настроек дистрибутива Linux (в данном случае гостевая ВМ Ubuntu 18.04.3 LTS) в файл .config в самый корень дерева исходного кода ядра, естественно, тем самым создавая необходимую стартовую точку настройки этого дистрибутива, который можно изменять далее (более общий вид этой команды: cp /boot/config-$(uname -r) ${LLKD_KSRC}/.config).

Регулировка настройки через подход localmodconfig

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

Этот третий рассматриваемый нами подход хорош для применения когда основная цель состоит в том чтобы приступить к настройке ядра, которое основано на имеющейся у вас системе и, таким образом, (обычно) относительно компактна по сравнению с типичной конфигурацией по умолчанию для настольной или серверной системой Linux. Здесь мы снабжаем свою систему kbuild неким моментальным снимком моделей ядра запущенных в настоящее время в вашей системе просто перенаправляя вывод lsmod(8) в некий временный файл, а затем предоставляя это файл под соответствующую сборку. Этого можно достичь следующим образом:


lsmod > /tmp/lsmod.now
cd ${LLKD_KSRC}
make LSMOD=/tmp/lsmod.now localmodconfig 
		

Утилита lsmod(8) просто перечисляет все модули своего ядра, которые в настоящий момент расположены в оперативной памяти системы (ядра). Мы рассмотрим это (намного) больше в Главе 4, Написание вашего первого модуля ядра - LKM, Часть I. Мы сохраняем её вывод в каком- то временном файле, который мы передаём через переменную среды LSMOD в целевой localmodconfig соответствующего Makefile. Основное задание этой цели состоит в настройке своего ядра таким образом, чтобы включать лишь базовую функциональность плюс ту функциональность, которая предоставляется этими модулями ядра и оставив этот остаток, на самом деле предоставляя нам разумное воспроизведение своего текущего ядра (или того ядра, которое предоставляет вывод соответствующей lsmod). Мы воспользуемся в точности этой технологией для настройки своего ядра 5.4 в своём следующем разделе Начинаем при помощи подхода localmodconfig.

Итак, на этом мы завершаем свои три подхода к настройке стартовой точки настройки ядра. Фактически мы лишь прикоснулись в общей поверхности. В самой рассматриваемой системе kbuild закодировано множество прочих методов выработки в явном виде конфигурации ядра определённым образом! Как? Через целевые конфигурации для make. Рассмотрите их в заголовке Configuration targets:


$ cd ${LKDC_KSRC}         # root of the kernel source tree
$ make help
Cleaning targets:
 clean             - Remove most generated files but keep the config and
                     enough build support to build external modules
 mrproper          - Remove all generated files + config + various backup     
                     files
 distclean         - mrproper + remove editor backup and patch files

Configuration targets:
 config           - Update current config utilising a line-oriented  
                    program
 nconfig          - Update current config utilising a ncurses menu based 
                    program
 menuconfig       - Update current config utilising a menu based program
 xconfig          - Update current config utilising a Qt based front-end
 gconfig          - Update current config utilising a GTK+ based front-end
 oldconfig        - Update current config utilising a provided .config as 
                    base
 localmodconfig   - Update current config disabling modules not loaded
 localyesconfig   - Update current config converting local mods to core
 defconfig        - New config with default from ARCH supplied defconfig
 savedefconfig    - Save current config as ./defconfig (minimal config)
 allnoconfig      - New config where all options are answered with no
 allyesconfig     - New config where all options are accepted with yes
 allmodconfig     - New config selecting modules when possible
 alldefconfig     - New config with all symbols set to default
 randconfig       - New config with random answer to all options
 listnewconfig    - List new options
 olddefconfig     - Same as oldconfig but sets new symbols to their
                    default value without prompting
 kvmconfig        - Enable additional options for kvm guest kernel support
 xenconfig        - Enable additional options for xen dom0 and guest   
                    kernel support
 tinyconfig       - Configure the tiniest possible kernel
 testconfig       - Run Kconfig unit tests (requires python3 and pytest)

Other generic targets:
  all             - Build all targets marked with [*]
[...]
$
		

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

Начинаем при помощи подхода localmodconfig

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

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

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

Как уже обсуждалось ранее, вначале получите моментальный снимок всех загруженных в настоящее время модулей ядра, а затем заставьте свою систему kbuild отработать его предписав целью соответствующий localmodconfig как- то так:


lsmod > /tmp/lsmod.now
cd ${LLKD_KSRC} ; make LSMOD=/tmp/lsmod.now localmodconfig 
		

Теперь нечто, что надлежит уяснить себе: когда мы в действительности выполняем команду make [...] localmodconfig, вполне возможно, и даже, скорее всего, будет именно так, что будет иметься разница в параметрах настроек между тем ядром, которое вы собираете в данный момент (версия 5.4) и тем ядром, в котором вы в действительности выполняете эту сборку (в нашем случае, $(uname -r) = 5.0.0-36-generic). В таких случаях ваша система kbuild будет отображать в окне консоли (в терминале) все отдельные новые параметры настроек и те доступные значения, в которые вы можете их установить.Далее она будет запрашивать своего пользователя выбор необходимого значения для всех новых встретившихся параметров при выполняемой сборке ядра. Вы будете наблюдать это как последовательности запросов и приглашений на ввод для ответа в своей командной строке.

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

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

Здесь, по крайней мере, мы получим самый простой выход: просто нажимайте клавишу [Enter] для принятия выбора, установленного по умолчанию, следующим образом:


$ uname -r
5.0.0-36-generic
$ make LSMOD=/tmp/lsmod.now localmodconfig 
using config: '/boot/config-5.0.0-36-generic'
vboxsf config not found!!
module vboxguest did not have configs CONFIG_VBOXGUEST
*
* Restart config...
*
*
* General setup
*
Compile also drivers which will not load (COMPILE_TEST) [N/y/?] n
Local version - append to kernel release (LOCALVERSION) [] 
Automatically append version information to the version string (LOCALVERSION_AUTO) [N/y/?] n
Build ID Salt (BUILD_SALT) [] (NEW) [Enter]
Kernel compression mode
> 1. Gzip (KERNEL_GZIP)
  2. Bzip2 (KERNEL_BZIP2)
  3. LZMA (KERNEL_LZMA)
  4. XZ (KERNEL_XZ)
  5. LZO (KERNEL_LZO)
  6. LZ4 (KERNEL_LZ4)
choice[1-6?]: 1
Default hostname (DEFAULT_HOSTNAME) [(none)] (none)
Support for paging of anonymous memory (swap) (SWAP) [Y/n/?] y
System V IPC (SYSVIPC) [Y/n/?] y
[...]
Enable userfaultfd() system call (USERFAULTFD) [Y/n/?] y
Enable rseq() system call (RSEQ) [Y/n/?] (NEW)
[...]
  Test static keys (TEST_STATIC_KEYS) [N/m/?] n
  kmod stress tester (TEST_KMOD) [N/m/?] n
  Test memcat_p() helper function (TEST_MEMCAT_P) [N/m/y/?] (NEW)
#
# configuration written to .config
#
$ ls -la .config
-rw-r--r-- 1 llkd llkd  140764 Mar  7 17:31 .config
$
		

После множества нажатий клавиши [Enter], задание вопросов благосклонно завершится и ваша система kbuild запишет вновь выработанную конфигурацию в соответствующий файл .config в текущем рабочем каталоге (мы усекли свой предыдущий вывод, поскольку он через-чур объёмен и нет никакой нужды воспроизводить его полностью).

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

  • Для обеспечения совершенно чистого состояния, выполните make mrproper или make distclean в корне своего дерева исходного кода ядра (полезно когда вы желаете начинать с чистого листа; не сомневайтесь, в один прекрасный день это случится! Обратите внимание, что при этом также удаляются файл(ы) настроек вашего ядра).

  • Здесь, в данной главе, все этапы настройки ядра и относящиеся к ним снимки экрана осуществлялись в гостевой ВМ Ubuntu 18.04.3 LTS x86-64, которую мы применяем в качестве своего хоста для сборки совершенно нового прекрасного ядра 5.4 Linux. Точные названия, наличие и содержимое всех элементов меню, а также внешний вид и поведение системы меню (интерфейса пользователя) могут и действительно разнятся на основе (a) собственно архитектуры (ЦПУ) и (b) значения версии ядра.

  • Как уже упоминалось ранее, в промышленной системе или проекте, соответствующей платформе или в команде BSP (Board Support Package), либо действительно в компании производителя встроенного Linux BSP, с которой у вас имеются партнёрские отношения, предоставят вам хорошо известный, рабочий и проверенный файл настроек ядра. Применяйте его в качестве отправной точки, скопировав его в свой файл .config в корне соответствующего дерева исходного кода ядра.

По мере того, как вы обзаведётесь опытом по сборке ядра, вы поймёте, что усилия по правильной настройке в первый раз конфигурации ядра (что критически важно!) являются высокими; и, естественно, то время, что требуется продолжительное время для сборки в самый первый раз. Однако, если всё сделано верно, тот процесс обычно становится намного проще - рецепт, который стоит повторять снова и снова.

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

Регулируем настройки своего ядра через создание UI menuconfig

Хорошо, отлично, теперь у нас имеется изначальный файл настроек ядра (.config), выработанный под нас при помощи цели Makefile localmodconfig, как это было подробно рассмотрено в нашем предыдущем разделе, который является хорошей отправной точкой. Теперь мы хотим дополнительно изучить и тонко отрегулировать настройки своего ядра. Один из способов для этого - на практике рекомендуемый - заключается в использовании цели Makefile menuconfig. Данная цель заставляет систему kbuild вырабатывать достаточно сложную исполняемую программу (на основе C, scripts/kconfig/mconf), которая представляет своему конечному пользователю аккуратный интерфейс пользователя на основе меню. В своём последующем блоке кода, когда мы активируем свою команду впервые, наша система kbuild собирает исполняемый mconf и активирует его:


$ make menuconfig
 UPD scripts/kconfig/.mconf-cfg
 HOSTCC scripts/kconfig/mconf.o
 HOSTCC scripts/kconfig/lxdialog/checklist.o
 HOSTCC scripts/kconfig/lxdialog/inputbox.o
 HOSTCC scripts/kconfig/lxdialog/menubox.o
 HOSTCC scripts/kconfig/lxdialog/textbox.o
 HOSTCC scripts/kconfig/lxdialog/util.o
 HOSTCC scripts/kconfig/lxdialog/yesno.o
 HOSTLD scripts/kconfig/mconf
scripts/kconfig/mconf Kconfig
		

Естественно, картинка, без всяких сомнений заменит тысячи слов, а потому вот как выглядит интерфейс пользователя menuconfig:

 

Рисунок 2-5


Главное меню настройки ядра через make menuconfig (в x86-64)

Как хорошо знают опытные разработчики, да и вообще любой, кто достаточно хорошо пользуется компьютером, что-то может пойти не так, как надо. Возьмём, к примеру, следующий сценарий - запуск make menuconfig в первый раз в только что установленной системе Ubuntu:


$ make menuconfig
 UPD     scripts/kconfig/.mconf-cfg
 HOSTCC  scripts/kconfig/mconf.o
 YACC    scripts/kconfig/zconf.tab.c
/bin/sh: 1: bison: not found
scripts/Makefile.lib:196: recipe for target 'scripts/kconfig/zconf.tab.c' failed
make[1]: *** [scripts/kconfig/zconf.tab.c] Error 127
Makefile:539: recipe for target 'menuconfig' failed
make: *** [menuconfig] Error 2
$
		

Успокойтесь, не паникуйте (пока). Внимательно прочтите полученное сообщение об ошибке (ошибках). Строка после YACC [...] даёт подсказку: /bin/sh: 1: bison: not found. А, поэтому просто установите bison(1) при помощи такой команды:


sudo apt install bison
		

Теперь всё должно быть нормально. Да, почти; снова в заново установленном свежем гостевом Ubuntu make menuconfig далее сообщает что не установлен и flex(1). Поэтому установите и его (вы, наверняка, предвосхитили и это, через sudo apt install flex). Кроме того, именно в Ubuntu вам потребуется установленным и пакет libncurses5-dev ( В Fedora выполните sudo dnf install ncurses-devel).

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

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

Двигаясь далее инфраструктура с открытым исходным кодом kbuild (кстати, повторно используемая в целом ряде проектов) предоставляет через свой интерфейс пользователя целый ряд подсказок. Значения стоящих перед записями меню символами таковы:

  • [.]: Внутренняя функциональная возможность ядра, Булев выбор (либо включён, либо нет):

    • [.]: Включён, функциональная возможность компилируется и строится (встраивается) в соответствующий образ ядра (y)

    • [ ]: Отключена, не собирается вовсе (n)

  • <.>: Некая функциональная возможность, которая способна пребывать в трёх состояниях (тройственная):

    • <^>: Включена, функциональная возможность компилируется и строится (встраивается) в соответствующий образ ядра (y)

    • <M>: Модуль, функциональная возможность компилируется и строится как некий модуль ядра (LKM, m)

    • < >: Отключена, не собирается вовсе (n)

  • {.}: Для данного параметра настройки имеется некая зависимость; следовательно, её требуется собрать (скомпилировать) либо как некий модуль (m), либо собрать (скомпилировать) в образе ядра (y).

  • -*-: Для данного элемента необходимо скомпилировать зависимость (y).

  • (...): Приглашение на ввод: требуется цифробуквенный ввод (при данном варианте нажатие на [Enter] выдаст приглашение на ввод).

  • <Menu entry> --->: Далее следует подменю (нажатие на [Enter] для этого элемента приведёт к перемещению по данному подменю).

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

Пример использования создания UI menuconfig

Чтобы получить представление о применении системы меню kbuild при помощи удобной цели menuconfig, давайте пошагово пройдём по соответствующему процессу навигации к элементу меню с тремя состояниями, именуемому Kernel .config support. По умолчанию оно отключено, поэтому давайте включим его; то есть превратим его в y, встраиваемым в образ нашего ядра. Мы можем обнаружить его в соответствующем пункте главного меню General Setup главного экрана.

Что именно даёт включение данной функциональной возможности? При включении в y (или, естественно, когда включается M, тогда становится доступным модуль ядра, как только он подгружается), тогда текущие параметры ядра можно просмотреть в любой момент времени двумя способами:

  • Исполнив имеющийся сценарий scripts/extract-ikconfig

  • Напрямую считывая содержимое псевдофайла /proc/config.gz (естественно, он сжат gzip(1)

    ; прежде всего раскройте его, а потом и читайте))

В качестве некого обучающего упражнения мы теперь изучим как настраивать наше ядро Linux 5.4 (для архитектуры x86-64) для соответствующих вариантов настроек ядра со значениями, отображаемые в приводимой далее таблице. Пока не обращайте внимания на значение каждого из этих вариантов; они приводятся просто для того, чтобы попрактиковаться в общей системе настроек ядра:

Таблица 2-4. Элементы конфигурации
Функциональная возможность Воздействие и место в UI make menuconfig Выбор кнопки <Help> для просмотра параметра CONFIG_<FOO> в точности Значение: изначальное -> новое значение

Локальная версия

Устанавливает компонент -EXTRAVERSION значения выпуска/ версии ядра (видимого через uname -r); General Setup / Local version - append to kernel release.

CONFIG_LOCALVERSION

(none) -> -llkd01

Поддержка файла настроек ядра

Позволяет вам наблюдать значения подробностей настроек текущего ядра General Setup / Kernel .config support.

CONFIG_IKCONFIG

n -> y

Аналогично предыдущему, плюс доступ через procfs

Позволяет вам наблюдать значения подробностей настроек текущего ядра через proc filesystem (procfs) General Setup / Enable access to .config through /proc/config.gz.

CONFIG_IKCONFIG_PROC

n -> y

Профилирование ядра

Поддержка профилирования ядра; General Setup / Profiling support.

CONFIG_PROFILING

y -> n

Радиопереключателя HAM

Поддержка радиопереключателя HAM; Networking support / Amateur Radio support.

CONFIG_HAMRADIO

y -> n

Поддержка VirtualBox

(Пара)виртуальная поддержка для VirtualBox; Device Drivers / Virtualization drivers / Virtual Box Guest integration support.

CONFIG_PROFILING

n -> m

Драйверы ввода/ вывода пространства пользователя (UIO)

Поддержка UIO; Device Drivers / Userspace I/O Drivers.

CONFIG_UIO

n -> m

Предыдущее плюс UIO драйвер платформы с общей обработкой IRQ

UIO драйвер платформы с общей обработкой IRQ; Device Drivers / Userspace I/O Drivers / Userspace I/O platform driver with generic IRQ handling.

CONFIG_UIO_PDRV_GENIRQ

n -> m

Поддержка файловой системы MS DOS

File systems / DOS/FAT/NT Filesystems / MSDOS fs support.

CONFIG_MSDOS_FS

n -> m

Безопасность: LSM

Отключает LSM; Security options / Enable different security models
ЗАМЕТЬТЕ: обычно безопаснее оставлять это ВКЛЮЧЁННЫМ в промышленных системах!.

CONFIG_SECURITY

y -> n

Отладка ядра: сведения об использовании стека

Kernel hacking / Memory Debugging / Stack utilization instrumentation.

CONFIG_DEBUG_STACK_USAGE

n -> y

Как именно вам воспринимать эту таблицу? Давайте выберем в качестве образца её первую строку; мы пройдёмся по ней столбец за столбцом:

  • Первый столбец определяет функциональную возможность, которую мы желаем изменять (редактировать/ включить/ запретить). Это именно самая последняя строка значения версии ядра (которую вы можете видеть в выводе uname -r). Она именуется компонентом -EXTRAVERSION значения выпуска (за подробностями обратитесь к разделу Номенклатура выпусков ядра)

  • Второй столбец описывает два момента:

    • Во- первых, что мы намерены делать. Здесь мы собираемся установить компонент -EXTRAVERSION строки значения выпуска ядра.

    • Во- вторых, местоположение этого параметра конфигурации ядра внутри отображаемого интерфейса пользователя menuconfig. Здесь он находится внутри подменю General Setup и под тем, что мы именуем элементом меню Local version - append to kernel release. Мы записываем это как General Setup / Local version - append to kernel release.

  • Третий столбец определяет название параметра настройки ядра как CONFIG_<FOO>. В случае необходимости вы можете найти его внутри соответствующей системы меню. В данном случае он именуется как CONFIG_LOCALVERSION

  • Четвёртый столбец отображает первоначальное значение данного параметра конфигурации ядра и то значение, на которое мы бы хотели его изменить (своё "новое" значение). Это отображается в формате оригинальное значение -> новое значение. В нашем образце это (none) -> -llkd01, подразумевая, что первоначальное значение строки компонента -EXTRAVERSION было пустым и мы бы желали заменить его на своё значение -llkd01.

С другой стороны, для некоторых отображённых нами элементов это может быть не совсем очевидно - скажем, n -> m; что это значит? n -> m подразумевает, что вам следует изменить исходное значение с n (не выбрано) на m (выбрано для сборки модуля ядра). Точно так же, строка y -> n означает изменение параметра конфигурации с включённого на отключённый.

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

Вы можете отыскать параметры для настроек ядра внутри системы интерфейса пользователя menuconfig нажав клавишу / (также как и в vi; мы покажем это дополнительно в наших последующих разделах).

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

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

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

Обратите внимание на то, что в зависимости от применяемого вами в настоящий момент дистрибутива Linux и его модулей ядра (помните, мы воспользовались для выработки первоначальных настроек lsmod(8)), реальные значения и установки по умолчанию, которые вы наблюдаете при настройке вашего ядра могут отличаться от тех, что имеются в нашем дистрибутиве Ubuntu 18.04.3 LTS (запущенном в ядре 5.0.0-36-generic), как это мы применили и показали ранее.

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

  1. Измените каталог на корневой в своём дереве исходного кода ядра (куда бы вы его не раскрутили его на своём диске):

    
    cd ${LLKD_KSRC}
    		
  2. Настройте изначальный файл настроек ядра на основе нашего описанного ранее (в разделе Регулировка настройки через подход localmodconfig) третьего подхода:

    
    lsmod > /tmp/lsmod.now
    make LSMOD=/tmp/lsmod.now localmodconfig 
    		
  3. Запустите интерфейс пользователя:

    
    make menuconfig
    		
  4. После того как загрузится интерфейс пользователя menuconfig, перейдите в элемент меню General Setup. Как правило, это второй элемент для x86-64. Перемещайтесь по нему при помощи клавиш клавиатуры со стрелками и входите в них нажатием клавиши Enter.

  5. Теперь вы внутри элемента меню General Setup. Прокрутите позиции меню вниз нажатием клавиши со стрелкой вниз несколько раз. Мы спустились вниз к представляющему для нас интерес меню - Kernel .config support - и выделили его% ваш экран должен выглядеть как- то так:

     

    Рисунок 2-6


    Настройка ядра через make menuconfig; General setup / Kernel .config support
    [Совет]Совет

    Для унифицированного ядра Linux 5.4.0 в x86-64, General Setup / Kernel .config support это 20й элемент меню с самого верха меню General Setup.


  6. После того как мы оказались в элементе меню Kernel .config support, мы можем обнаружить (в своём предыдущем снимке экрана) из его префикса <M>, что это элемент меню с тремя состояниями, который установлен изначально на вариант <M> для модуля.

  7. Оставляя выделенным данный параметр (Kernel .config support), воспользуйтесь клавишей стрелки вправо чтобы переместиться к кнопке < Help > в планке инструментов внизу и нажмите клавишу Enter при нахождении на кнопке < Help >. Ваш экран теперь должен выглядеть как- то так:

     

    Рисунок 2-7


    Настройка ядра через make menuconfig; образец экрана подсказки

    Этот экран подсказки достаточно информативен. Действительно, несколько экранов подсказок настроек ядра очень хорошо заполнены и в самом деле полезны. К сожалению, часть из них отсутствует.

  8. Хорошо, дальше нажмите Enter на кнопке < Help > с тем, чтобы мы вернулись обратно к своему предыдущему экрану.

  9. Затем переключите элемент меню Kernel .config support, нажав клавишу пробела (мы предполагаем, что изначально это <M>; то есть он настроен на модуль). Одно нажатие на пробел заставит ваши элементы интерфейса пользователя выглядят следующим образом:

    
    <*> Kernel .config support
    [ ] Enable access to .config through /proc/config.gz (NEW)
    		

    Обратите внимание на то, как он превратился в <*>, подразумевая что данная функциональная возможность будет встроена в сам образ ядра (фактически, она будет всегда включена). А пока давайте оставим её в этом состоянии (естественно, повторное нажатие на пробел снова переключит её сначала в отключённое состояние, < >, а затем обратно к первоначальному состоянию <M>).

  10. Теперь, с установленным состоянием элемента <*> (yes), прокрутите вниз к следующему элементу меню, [*] Enable access to .config through /proc/config.gz, и включите его; теперь должен появиться следующий экран, который выглядит как- то так (мы распахнули его только до относящейся к делу части):

     

    Рисунок 2-8


    Настройка ядра через make menuconfig; переключение некого Булева параметра конфигурации в состояние включённого

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

    Вы всегда можете воспользоваться клавишей стрелки вправо чтобы перейти к < Help > и просмотреть экран подсказки также и для этого элемента.

    Здесь мы не изучаем все оставшиеся меню настройки ядра; я оставляю это вам чтобы настроить в соответствии с тем, как это показано в нашей предыдущей таблице.

  11. Обратно в главное меню (домашний экран), воспользуйтесь клавишей правой стрелки чтобы переместиться к кнопке < Exit > и нажмите на ней Enter. Всплывёт окно диалога:

     

    Рисунок 2-9


    Настройка ядра через make menuconfig; диалог сохранения

    Он достаточно прост, не так ли? Нажмите Enter на кнопке < Yes > для сохранения и выхода. Если вы выберете < No >, вы утратите все изменения конфигурации (выполненные в этом сеансе). Или же можете нажать клавишу Esc дважды чтобы избавиться от этого диалога и продолжить работу с настройкой своего ядра.

  12. Сохраняемся и выходим. При нахождении на клавише < Yes >, нажмите Enter. Ваше меню системы интерфейса пользователя сохранит вашу новую конфигурацию ядра и осуществит выход; мы вернёмся обратно в приглашение своей консоли (оболочки или окна терминала).

Но где сохраняется новая конфигурация ядра? Это важно: конфигурация вашего ядра записывается в простом текстовом файле ASCII в самом корне дерева исходного кода ядра, причём с названием .config. То есть он сохраняется в ${LLKD_KSRC}/.config.

Как уже упоминалось ранее, всякий отдельный параметр настройки ядра ассоциируется с некой переменной конфигурации в виде CONFIG_<FOO>, где <FOO>, конечно же, заменяется неким подходящим названием. Внутренне это превращается в макрос, который собирает систему и несомненно используется исходным кодом вашего ядра. Например, рассмотрим это для параметра Kernel .config support:


$ grep IKCONFIG .config
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
$
		

Ага! Эта конфигурация теперь отражает тот факт, что мы выполнили следующее:

  • Включили функциональную возможность CONFIG_IKCONFIG (=y указывает что она включена и будет встроена в образ самого ядра).

  • Соответствующий (псевдо) файл /proc/config.gz теперь станет доступным, поскольку CONFIG_IKCONFIG_PROC=y.

[Предостережение]Предостережение

Лучше НЕ пытаться изменять свой файл .config вручную (самостоятельно). Существуют некоторые взаимозависимости, о которых вы можете не знать; для его изменения всегда пользуйтесь системой меню kbuild (мы предполагаем через make menuconfig).

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

Дополнительно о kbuild

Создание или изменение соответствующего файла .config внутри самого корня дерева исходного кода ядра через make menuconfig или иными способами это не окончательный шаг в том как система kconfig работает со своей конфигурацией. Нет, теперь она продолжает внутренним образом активируя цель с названием syncconfig, которая ранее (ошибочно) именовалась silentoldconfig. Эта цель заставляет kbuild вырабатывать несколько файлов заголовков в include/config, а также файл заголовка include/generated/autoconf.h, который хранит конфигурацию обрабатываемого ядра в виде макроса C, тем самым позволяя как Makefile(ам) ядра и коду ядра принимать решения на основе того, будет или нет доступной некая функциональная возможность ядра.

Двигаясь далее, что если вы ищете определённый параметр конфигурации ядра, но испытываете трудности с определением его местоположения? Без проблем, система интерфейса пользователя menuconfig обладает функциональностью Search Configuration Parameter. Так же как и в знаменитом редакторе vi(1) нажмите клавишу / (прямого слэша) чтобы получить всплывшим диалог поиска, затем введите искомый вами термин с предшествующим ему CONFIG_ или без него и выберите кнопку < Ok > для запуска поиска.

Следующая пара снимков экрана отобразят диалог поиска и результирующий диалог (в качестве образца мы выполняем поиск vbox):

 

Рисунок 2-10


Настройка ядра через make menuconfig; поиск параметров настройки

Результирующий диалог для нашего предыдущего поиска представляет интерес. Он раскрывает несколько моментов в относящихся к параметрам настройки сведениям:

  • Директиву настройки (просто добавьте префикс CONFIG_ к тому, что он отображает в Symbol:)

  • Тип настройки (Булево, с тремя состояниями, цифробуквенный и тому подобное)

  • Строку приглашения на ввод

  • Что важно, его местоположение в самой системе меню (а потому вы можете отыскать его)

  • Его внутренние зависимости, если они имеются

  • Любые варианты настроек, которые он выбирает автоматически (включает) сам по себе в случае его выбора

Ниже приводится снимок экрана получаемого в результате диалога:

 

Рисунок 2-11


Настройка ядра через make menuconfig; результирующий диалог предыдущего поиска

Все эти сведения присутствуют в неком текстовом файле ASCII, применяемом системой kbuild для сборки интерфейса пользователя системного меню - этот файл носит название Kconfig (в действительности имеется несколько таковых). Их местоположение, также отображается (в строке Defined at ...).

Поиск отличий в настройках

В тот момент, когда надлежит записать полученный файл настроек ядра .config, система kbuild проверяет существует ли он уже и, если так, выполнить его резервного копирования с именем .config.old. Зная это, мы всегда сможем различить их чтобы увидеть внесённые нами изменения. Однако применение для этого обычной утилиты diff(1) затрудняет восприятие имеющихся отличий. Само ядро предлагает лучший способ, некий сценарий на основе консоли, который предназначен именно для этого. Сценарий scripts/diffconfig (в дереве исходного кода ядра) действительно полезнее в этом. Чтобы разобраться чем, давайте просто запустим его экран подсказки:


$ scripts/diffconfig --help
Usage: diffconfig [-h] [-m] [<config1> <config2>]

Diffconfig is a simple utility for comparing two .config files.
Using standard diff to compare .config files often includes extraneous and
distracting information. This utility produces sorted output with only the
changes in configuration values between the two files.

Added and removed items are shown with a leading plus or minus, respectively.
Changed items show the old and new values on a single line.
[...]
		

Теперь давайте попробуем:


$ scripts/diffconfig .config.old .config
-AX25 n
-DEFAULT_SECURITY_APPARMOR y
-DEFAULT_SECURITY_SELINUX n
-DEFAULT_SECURITY_SMACK n
[...]
-SIGNATURE y
 DEBUG_STACK_USAGE n -> y
 DEFAULT_SECURITY_DAC n -> y
 FS_DAX y -> n
 HAMRADIO y -> n
 IKCONFIG m -> y
 IKCONFIG_PROC n -> y
 LOCALVERSION "" -> "-llkd01"
 MSDOS_FS n -> m
 PROFILING y -> n
 SECURITY y -> n
 UIO n -> m
+UIO_AEC n
 VBOXGUEST n -> m
[...]
$
		

Если вы выполнили изменения настроек ядра, как это было показано в нашей предыдущей таблице, вы должны увидеть вывод, аналогичный тому, что показан в нашем предыдущем блоке кода через сценарий diffconfig. Это чётко показывает нам в точности какие параметры настроек мы изменили и как.

Прежде чем мы завершим, некое краткое замечание о чём- то критически важном: безопасности ядра. В то время как технологии упрочения безопасности в пространстве пользователя существенно возросли, технологии усиления безопасности фактически играют роль догоняющих. Тщательная настройка параметров конфигурации ядра на самом деле играет ключевую роль при определении уровня безопасности данного ядра Linux; основная проблема состоит в том, что имеется так много вариантов (а на самом деле и мнений), что зачастую будет затруднительно (перекрёстно) проверить что является хорошей идеей с точки зрения безопасности, а что нет. Александр Попов написал очень полезный сценарий Python с названием kconfig-hardened-check; его можно запустить для проверки и сравнения представленной конфигурации ядра (через обычный файл настроек) с набором предопределяемых параметров упрочения (из различных проектов безопасности ядра Linux: хорошо известный проект KSPP - Kernel Self Protection Project, самое последнее исправление grsecurity, OS CLIP и LSM блокировки безопасности). Отыщите kconfig-hardened-check в репозитории GitHub и испробуйте его!.

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

Индивидуализация меню ядра - добавление вашего собственного элемента меню

Итак, скажем, вы разрабатываете некий драйвер устройства, некий экспериментальный класс планирования, индивидуальный обратный вызов debugfs (отладки файловой системы), или некую иную крутую функциональную возможность ядра. Как вы предоставите возможность прочим членам своей команды - или, раз уж на то пошло, своему клиенту - узнать что эта новая фантастическая функциональность имеется и позволить им выбирать её (как встроенную, так и в виде модуля ядра) и, тем самым, собрать её и воспользоваться ею? Ответ состоит в том, чтобы вставить новый пункт меню в соответствующее место имеющемся меню настроек ядра.

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

Файлы Kconfig*

Файл Kconfig в самом корне дерева исходного кода ядра применяется для заполнения первоначального экрана интерфейса пользователя menuconfig. Взгляните на него, если пожелаете. Он работает выбирая в качестве источников различные прочие файлы Kconfig в различных папках вашего дерева исходного кода ядра. Приводимая далее таблица суммирует наиболее важные файлы Kconfig* и то, какие меню они обслуживают в интерфейсе пользователя kbuild:

Таблица 2-5. Элементы меню настроек ядра и соответствующий файл Kconfig*, определяющий элемент
Меню Местоположение файла Kconfig для него

Главное меню, первоначальный экран

Kconfig

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

init/Kconfig

Типы процессора и функциональные возможности + Параметры шины + Эмуляции исполняемого кода
(специфичное для архитектуры; ранее заголовок меню представлен для x86; в общем виде этот файл Kconfig расположен здесь: arch/<arch>/Kconfig)

arch/<arch>/Kconfig

Управление питанием

kernel/power/Kconfig

Драйверы встроенного ПО

drivers/firmware/Kconfig

Виртуализация

arch/<arch>/kvm/Kconfig

Общие параметры зависимости от архитектуры

arch/Kconfig

Включение блочного уровня + Планировщики ввода/ вывода

block/Kconfig

Форматы исполняемых файлов

fs/Kconfig.binfmt

Параметры управления памятью

mm/Kconfig

Сетевая поддержка

net/Kconfig, net/*/Kconfig

Драйверы устройств

drivers/Kconfig, drivers/*/Kconfig

Файловые системы

fs/Kconfig, fs/*/Kconfig

Параметры безопасности

security/Kconfig, security/*/Kconfig*

API криптографии

crypto/Kconfig, crypto/*/Kconfig

Библиотечные подпрограммы

lib/Kconfig, lib/*/Kconfig*

Проникновение в ядро

lib/Kconfig.debug, lib/Kconfig.*

Обычно некий отдельный файл Kconfig рулит отдельным меню. Теперь, давайте приступим к реальному добавлению элемента меню.

Создание нового элемента меню в файле Kconfig

В качестве тривиального примера давайте добавим свой собственный Булев макетный параметр конфигурации внутри своего меню General Setup. Мы хотим чтобы названием этой конфигурации было CONFIG_LLKD_OPTION1. Как можно видеть из нашей предыдущей таблицы, соответствующим файлом Kconfig для изменения выступает init/Kconfig, который является файлом мета меню, который задаёт меню General Setup.

Давайте займёмся этим:

  1. Чтобы пребывать в безопасности, всегда выполняйте резервное копирование:

    
    cp init/Kconfig init/Kconfig.orig
    		
  2. Теперь внесите изменения в файл init/Kconfig:

    
    vi init/Kconfig
    		

    Прокрутите вниз до соответствующего местоположения внутри этого файла; здесь мы выбрали вставку записи сразу после параметра CONFIG_LOCALVERSION_AUTO. Следующий снимок экрана отображает нашу новую запись:

     

    Рисунок 2-12


    Редактирование init/Kconfig и вставка нашей собственной записи меню

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

    Мы предоставили предыдущий текст как некий фрагмент кода в первоначальном файле init/Kconfig в дереве исходного кода GitHub нашей книги. Найдите его в ch2/Kconfig.patch.

    Наш новый элемент начинается с ключевого слова config, за которым следует часть FOO вашей новой переменной конфигурации CONFIG_LLKD_OPTION1. Теперь же, просто считайте тот оператор, который мы сделали в своём файле Kconfig, отвечающий за эту запись. Дополнительные сведения по языку/ синтаксису Kconfig расположены в следующем разделе Некоторые подробности по языку самого Kconfig.

  3. Сохраните этот файл и покиньте этот редактор.

  4. (Повторно) настройте своё ядро. Перейдите к нашему новому элементу меню и включите эту функциональность (обратите внимание как, в последующем усечённом снимке экрана он выделен и по умолчанию имеет значение off):

    
    make menuconfig
    [...]
    		

    Вот соответствующий вывод:

     

    Рисунок 2-13


    Настройка ядра через make menuconfig, отображающая нашу новую запись меню

  5. Включите его (перебирая варианты пробелом), затем сохраните и покиньте систему меню.

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

    Пока пребываете там, нажмите кнопку < Help >. Вы должны обнаружить "подсказку", которую мы предоставили внутри своего файла Kconfig.

  6. Убедитесь что наша функциональность была выбрана:

    
    $ grep "LLKD_OPTION1" .config
    CONFIG_LLKD_OPTION1=y
    $ grep "LLKD_OPTION1" include/generated/autoconf.h
    $
    		

    Мы обнаружили, что в конце концов он был установлен в on внутри нашего файла .config, но это (всё ещё!) не внутри внутреннего автоматически выбираемого файла заголовка ядра. Это произойдёт при сборке данного ядра.

  7. Соберите своё ядро (не беспокойтесь; все подробности по сборке ядра находятся в нашей следующей главе. Вы всегда вначале можете ознакомиться с Главой 3, Сборка ядра Linux 5.4 из исходного кода - Часть II, а затем вернуться обратно сюда, если пожелаете...):

    
    make -j4
    		
  8. Завершив всё это, повторно проверьте свой заголовок autoconf.h на присутствие нашего нового параметра конфигурации:

    
    $ grep "LLKD_OPTION1" include/generated/autoconf.h
    #define CONFIG_LLKD_OPTION1 1
    		

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

Вот некий быстрый пример того как это могло бы выглядеть. В Makefile верхнего уровня ядра (или где- то ещё), приводимая ниже строка гарантирует что наш собственный код (приводимый далее расположен внутри исходного файла llkd_option1.c) будет скомпилирован в самом ядре во время его сборки. Добавьте следующую строку в самый конец подходящего Makefule:


obj-${CONFIG_LLKD_OPTION1}  +=  llkd_option1.o
		
[Совет]Совет

Пока не беспокойтесь относительно довольно странного синтаксиса Makefile ядра. Несколько следующих глав прольют на него некоторый свет.

Кроме того, вам надлежит осознать, что та же самая конфигурация может применяться как обычный макрос C внутри некой части кода: к примеру, мы могли бы делать такие вещи:


#ifdef CONFIG_LLKD_OPTION1
    do_our_thing();
#endif
		

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


if (IS_ENABLED(CONFIG_LLKD_OPTION1)) {
do_our_thing();
}
		
[Замечание]Замечание

Я настоятельно советую вам почаще обращаться к руководствам по стилю программирования ядра Linux и, естественно, следовать им!

Некоторые подробности по языку самого Kconfig

Наше применение языка Kconfig до сих пор это просто лишь верхушка пресловутого айсберга. Дело заключается в том, что система kbuild применяет язык (или синтаксис) Kconfig для выражения и создания меню при помощи простых текстовых директив ASCII. Этот язык содержит записи меню, атрибуты (обратные) зависимости, ограничения видимости, тексты справок и тому подобное.

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

Рекомендуем вам за подробностями обращаться к документации по конструкциям и синтаксису языка Kconfig за полными подробностями.

Краткое (и неполное) упоминание наиболее употребимых конструкций Kconfig приводится в нашей следующей таблице:

Таблица 2-6. Ряд конструкций Kconfig
Конструкция Значение

config <FOO>

Определяет здесь название соответствующей записи меню (в виде CONFIG_FOO) просто поместите часть FOO.

Атрибуты меню

 

bool ["<description>"]

Определяет данный параметр конфигурации как Булев; его значение в .config будет либо Y (встраивается в сам образ ядра), либо не существует (будет отображаться как запись в комментарии).

tristate ["description"]

Определяет данный параметр конфигурации как с тремя состояниями; его значение в .config будет либо Y, M (собирается как модуль ядра), либо не существует (будет отображаться как запись в комментарии).

int ["description"]

Определяет данный параметр конфигурации как целое значение.

range x-y

Диапазон целых значений от x до y.

default <value>

Определяет значение по умолчанию; в случае необходимости применяет y, m, n или иное.

prompt "<description>"

Некая последовательность описывает значение конфигурации ядра.

depends on "expr"

Определяет некую зависимость для этого элемента меню: может обладать несколькими при помощи вида синтаксиса depends on FOO1 && FOO2 && (FOO3 || FOO4).

select <config> [if "expr"]

Определяет обратную зависимость.

help "<help-text>"

Текст для отображения при выборе кнопки < Help >.

Чтобы помочь разобраться с этим синтаксисом, ниже приводятся несколько образцов из lib/Kconfig.debug (того файла, который описывает элементы для Kernel Hacking - отладки ядра в действительности - раздела интерфейса пользователя):

  1. Мы начнём с простого (параметра CONFIG_DEBUG_INFO):

    
    config DEBUG_INFO
        bool "Compile the kernel with debug info"
        depends on DEBUG_KERNEL && !COMPILE_TEST
        help
          If you say Y here the resulting kernel image will include
          debugging info resulting in a larger kernel image. [...]
    		
  2. Далее давайте взглянем на параметр CONFIG_FRAME_WARN. Обратите внимание на range и синтаксис условного значения по умолчанию:

    
    config FRAME_WARN
        int "Warn for stack frames larger than (needs gcc 4.4)"
        range 0 8192
        default 3072 if KASAN_EXTRA
        default 2048 if GCC_PLUGIN_LATENT_ENTROPY
        default 1280 if (!64BIT && PARISC)
        default 1024 if (!64BIT && !PARISC)
        default 2048 if 64BIT
        help
          Tell gcc to warn at build time for stack frames larger than this.
          Setting this too low will cause a lot of warnings.
          Setting it to 0 disables the warning.
          Requires gcc 4.4
    		
  3. Затем параметр CONFIG_HAVE_DEBUG_STACKOVERFLOW это образец Булева выражения; он либо включён, либо отключён. Значение параметра CONFIG_DEBUG_STACKOVERFLOW также булево. Обратите внимание каким образом он зависит от двух прочих параметров, разделённых булевым оператором И (&&):

    
    config HAVE_DEBUG_STACKOVERFLOW
            bool
    
    config DEBUG_STACKOVERFLOW
            bool "Check for stack overflows"
            depends on DEBUG_KERNEL && HAVE_DEBUG_STACKOVERFLOW
            ---help---
              Say Y here if you want to check for overflows of kernel, IRQ
              and exception stacks (if your architecture uses them). This 
              option will show detailed messages if free stack space drops
              below a certain limit. [...]
    		

Отлично! Это завершает наше рассмотрение создания (или изменения) индивидуальных записей меню в настройках ядра, а в конечном итоге и саму главу.

Выводы

В этой главе мы вначале изучили как получать для вас самих дерево исходного кода ядра. Затем вы разобрались с его номенклатурой выпуска (или версии), различные типы ядер Linux (деревья -next, деревья -rc/ основной линии, стабильные, LTS, SLTS и дистрибутивы), а также рабочий поток разработки основы ядра. По ходу дела вы даже получили быстрый тур по дереву исходного кода ядра с тем, чтобы стала более ясной его схема. Далее вы увидели как извлекать это сжатое дерево исходного кода ядра на диск и, что критически важно, как настраивать само ядро - некий ключевой шаг в данном процессе. Более того, вы изучили как персонализировать меню своего ядра, добавляя в него свои собственные записи и слегка систему kbuild, а также, помимо прочего, используемые ею ассоциируемые файлы Kconfig.

Полезно знать как получать и настраивать ядро Linux. Мы только приступили к этому долгому и увлекательному путешествию. Вы осознаете, что с получением бо́льшего опыта и знаний о внутреннем устройстве ядра, драйверов и аппаратного обеспечения вашей целевой системы ваши способности тонкой настройки ядра в соответствии с целями вашего проекта станут лишь лучше.

Здесь мы одолели полпути; предлагаю вам сначала переварить это материал и, что важно, попробовать описанные в этой главе этапы, поработать над вопросами, упражнениями и просмотреть раздел последующего чтения. После этого, в своей следующей главе, давайте соберём ядро 5.4.0 и удостоверимся в нём!

Вопросы

В заключение, вот вам список вопросов, которые проверят ваши знания относительно материалов этой главы. Некоторые из ответов на эти вопросы вы сможете найти в репозитории GitHub этой книги.

Дальнейшее чтение

Чтобы помочь вам глубже окунуться в предмет при помощи полезных материалов, мы предоставляем достаточно подробный список справочных материалов и интернет ссылок (а временами даже книг) в документе Последующего чтения в репозитории GitHub данной книги.