Глава 2. Сборка ядра Linux 5.4 из исходного кода - Часть I
Содержание
- Глава 2. Сборка ядра Linux 5.4 из исходного кода - Часть I
- Технические требования
- Предварительные замечания относительно сборки ядра
- Этапы сборки ядра из исходного кода
- Этап 1 - получение дерева исходного кода ядра Linux
- Этап 2 - выделение необходимого дерева исходного кода
- Этап 3 - настройка ядра Linux
- Индивидуализация меню ядра - добавление вашего собственного элемента меню
- Выводы
- Вопросы
- Дальнейшее чтение
Сборка ядра 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
указывают на их необязательность. Приводимая далее таблица суммирует значения всех компонентов в значении номера выпуска:
# компонента выпуска | Значение | Образцы номеров |
---|---|---|
|
Основной или старший номер; в настоящий момент мы пребываем в последовательности ядра 5.x, следовательно значение сташего номера это 5. |
|
|
Младший номер, иерархически под старшим номером. |
|
|
Иерархически под младшим номером - также именуется ABI или ревизией - применяется к стабильному ядру в случае, когда требуются существенные исправления ошибок/ безопасности. |
|
|
Также именуемый |
Разнятся; Ubuntu применяет |
Итак, теперь мы можем интерпретировать номер выпуска ядра своего дистрибутива 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) В качестве интересного упражнения настройки своего ядра, позднее мы изменим компонент (b) Исторически, в в ядрах вплоть до 2.6 (иначе говоря, теперь уже это устарело), младший номер скрывал особое значение; когда его номер был чётным, это указывало на стабильный выпуск ядра, в случае нечётного это был нестабильный, или бета выпуск. Это уже не так. |
Здесь мы предоставим краткий обзор типичного рабочего потока разработки ядра. Всякий, кто как и вы, заинтересован в разработке ядра, обязан по крайней мере минимально представлять себе этот процесс.
Замечание | |
---|---|
Подробное описание можно обнаружить внутри самой документации ядра здесь . |
Распространённым заблуждением, в особенности в его младенческие годы, было то, что ядро Linux разрабатывается очень специальным образом. Это вовсе не так! Процесс разработки ядра (в целом) превратился в хорошо промасленную систему с тщательно задокументированным процессом и ожиданием того, что участник разработки ядра должен знать его, чтобы правильно им пользоваться. Я отсылаю вас к предыдущей ссылке за полными сведениями.
Чтобы мы могли взглянуть на типичный цикл разработки, представим себе, что у нас имеется самое последний Git дерева ядра основной линии Linux, клонированный в нашу систему.
Замечание | |
---|---|
Относящиеся к использованию мощного инструмента SCM
(Source Code Management, управления исходным кодом)
|
Как уже упоминалось ранее, поскольку на момент написания этих строк ядро 5.4 это
самая последняя версия LTS
(Long-Term Stable, долгосрочной стабильности), поэтому мы можем применять её в
последующих материалах. Итак, как это произошло? Очевидно, что она эволюционировала из ядер rc
(release candidate, кандидатов выпуска) и предшествующие ему предыдущие выпуски ядра,
которыми в данном случае были бы ядра v5.4-rc'n' и стабильное
v5.3, которое было перед ним. Для получения читаемого персоналом журнала тэгов в упорядоченном по датам дереве
Git ядра мы пользуемся командой git log
, которая следует далее. Здесь нас всего лишь интересует та работа,
которая привела к выпуску нашего ядра 5.4 LTS, поэтому мы намеренно усекли приводимый ниже вывод, чтобы показать лишь эту часть:
Совет | |
---|---|
Команда |
$ 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 дней).
То же самое можно визуально увидеть через страницу выпусков:
Наш предыдущий снимок экрана это частичный снимок экрана, который показывает как различные кандидаты выпуска ядра
v5.4-rc'n' в конечном итоге привели к выпуску дерева LTS 5.4 (5 ноября 2019 и при этом
v5.4-rc'8' был последним выпуском rc
). Эта работа на самом
деле никогда не прекращается: в начале декабря 2019 вышел в свет кандидат выпуска v5.5-rc'1'.
В общем случае, выбрав в качестве примера последовательность ядра 5.x (то же самое остаётся справедливым для всех прочих самых последних
серий основного
ядра), рабочий поток разработки ядра выглядит следующим образом:
-
Выполняется стабильный выпуск 5.x. Тем самым, начинается окно слияния для следующего (в основной ветке) ядра 5.x+1.
-
Окно слияния остаётся открытым примерно 2 недели и в основной ветке сливаются новые исправления.
-
Когда (как правило) 2 недели проходят, это окно слияний закрывается.
-
Стартуют ядра
rc
(синоним предваряющих исправлений основной ветки). 5.x+1-rc1, 5.x+1-rc2, ... 5.x+1-rcn. Этот процесс требует около 6 - 8 недель. -
Появляется новый стабильный выпуск: выпускается новое стабильное 5.x+1 ядро.
-
Этот выпуск пассивно обрабатывается "командой стабильности"
-
Существенные исправления ошибок или проблем безопасности в результате приводят к выпускам 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 из исходного кода. Поскольку объяснение каждого из них слишком изобилует деталями, вы можете возвращаться к этому резюме чтобы представлять себе картину целиком. Эти шаги таковы:
-
Получить дерево исходного кода ядра Linux в виде одного из следующих вариантов:
-
Выгрузка исходного кода конкретного ядра виде некого сжатого файла
-
Клонирование некого дерева Git (ядра)
-
-
Раскрыть дерево исходного кода полученного ядра в неком местоположении в вашем домашнем каталоге (если вы получили ядро клонированием дерева Git, пропускайте этот шаг).
-
Настройка Выберите варианты поддержки своего ядра которые требуются для вашего нового ядра,
make [x|g|menu]config
, причём предпочтительным способом выступаетmake menuconfig
. -
Сборка необходимых загружаемых моделей ядра и всех DTB (Device Tree Blobs, BLOB-ов дерева устройств) при помощи
make [-j'n'] all
. Это выполняет сборку соответствующего образа сжатия ядра (arch/
), образа ядра без сжатия/boot/[b|z|u]image vmlinux
System.map
, объектов модуля самого ядра и всех файлов настроек DTB. -
Установка только что собранных модулей при помощи
sudo make modules_install
. Этот этап устанавливает модули по умолчанию в/lib/modules/$(uname -r)/
. -
Настройка начального загрузчика GRUB и образа
initramfs
(ранее носившая названиеinitrd
) (специфичного для x86):sudo make install
:-
Здесь создаётся и устанавливается образ
initramfs
(initrd
) в/boot
. -
Это обновляет файл настрое начального загрузчика на запуск нового ядра (первой записи).
-
-
Индивидуальная настройка меню начального загрузчика GRUB (не обязательно).
Эта глава, будучи первой из двух по данной теме, по сути дела рассмотрит шаги с 1 по 3, также рассматривая множество необходимых лежащих в основе материалов. Наша следующая глава осветит все остальные этапы, с 4 по 7. Итак, давайте приступим к этапу 1.
В этом разделе мы рассмотрим два проторённых пути, которыми мы имеем возможность получения дерева исходного кода 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
):
Совет | |
---|---|
Быстрое напоминание: мы также предоставляем файл 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
Совет | |
---|---|
Если предыдущая утилита |
Это безопасно выгрузит сжатое дерево исходного кода ядра в папку вашего компьютера ~/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).
Для такого как вы разработчика, который работает над развитием кодом восходящего потока и желающим вносить свой вклад в него, вы
обязаны работать с самой последней версией базового кода ядра 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=3 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Если вы намерены работать с этим деревом Git основной линии, пожалуйста, пропустите раздел Этап 2
- выделение необходимого дерева исходного кода (поскольку операция git clone
в любом случае раскроет
необходимое дерево исходного кода) и продолжайте со следующим разделом Этап 3 - настройка ядра
Linux.
Как уже упоминалось ранее, этот раздел предназначен тем, кто выгрузил определённое ядро 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 для
выполнения подобных действий.
Совет | |
---|---|
Не забывайте про |
Вы заметили? Мы выделили дерево исходного кода своего ядра в любом каталоге из своего домашнего каталога
(или даже вообще где угодно), в то время как в прошлые дни это дерево всегда раскрывалось в местоположении доступном для записи root (чаще всего, в
/usr/src/
). В наши дни просто скажите (этому) нет.
Если всё чего вы желаете, это продолжение выполнения рецепта сборки необходимого ядра, пропустите наш следующий раздел и пройдите далее. Если это интересно (а мы надеемся н это!), наш следующий раздел представляет сбой краткое, но важное, отклонение к рассмотрению всей структуры и схемы дерева исходного кода соответствующего ядра.
В вашей системе теперь доступен исходный код необходимого ядра! Круто, давайте бегло посмотрим на него:
Отлично! Насколько оно большое? Быстрый 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 футов дерева исходного кода ядра. В нашей следующей таблице суммируются обширное разбиение на категории и цели (наиболее) важных файлов и каталогов в корне дерева исходного кода ядра:
Название файла или каталога | Назначение |
---|---|
Файла верхнего уровня |
|
|
Это файл |
|
Лицензионные термины в соответствии с которыми выпущен исходный код данного ядра. Подавляющее большинство выпускается под хорошо знакомой лицензией GNU GPL v2 (записываемой как GPL-2.0)[1] |
|
ЧаВо: как- то неважно выглядит XYZ, с кем мне контактировать когда что- то
происходит? Это именно то в точности, что предоставляет данный файл - это список всех подсистем ядра, в самом деле, вплоть до уровня
отдельных компонентов (таких как определённый драйвер), его состояния, кто в данный момент сопровождает его, список адресов электронной
почты, вебсайт и тому подобное. Имеется даже вспомогательный сценарий для поиска определённой персоны или команды для обсуждения:
|
|
Это Makefile верхнего уровня; системный построитель ядра |
Каталоги основной подсистемы |
|
|
Центральная часть подсистемы ядра: расположенный здесь код имеет дело с жизненным циклом процесса/ потока, планированием ЦПУ, блокировками, контрольными группами (cgroup), таймерами, прерываниями, сигналами, модулями, трассировкой и т.п. |
|
Здесь обитает пакет кода управления памятью (mm, memory management). Мы слегка затронем его в Главе 6, Существенные моменты внутреннего устройства ядра - Процессы и Потоки, а также некоторые материаля связанные с ним охватываются в Главе 7, Внутреннее устройство управления памятью - Существенные моменты, а также в Главе 8, Выделение памяти ядра авторам модуля Часть I. |
|
Располагаемый здесь код реализует две ключевые функциональные возможности файловой системы: уровень абстракции -
VFS (Virtual Filesystem Switch,
переключатель виртуальной файловой системы) и драйверы индивидуальных файловых систем ( |
|
Путь кода, лежащего в основе блочного ввода/ вывода (VFS/ FS). Он содержит собственно код реализации кэширования страниц, общий уровень блочного ввода/ вывода, планировщики ввода/ вывода и тому подобное. |
|
Полная (буквально следуя Request For Comments - RFC) реализация стека сетевого протокола. Содержит высококачественную реализацию TCP, UDP, IP и многих прочих сетевых протоколов. |
|
Код подсистемы IPC (Inter-Process Communication, межпроцессного взаимодействия); охватывает такие механизмы IPC (и для SysV, и для POSIX), как очереди сообщений, совместную память, семафоры и тому подобное. |
|
Код аудио системы, также носящий название ALSA (Advanced Linux Sound Architecture). |
|
Собственно код виртуализации (гипервизора); здесь реализована популярная и мощная KVM (Kernel Virtual Machine, ВМ на основе ядра). |
Инфраструктура/ разное |
|
|
Здесь обитает особенный для архитектуры код (под словом arch - архитектура, мы подразумеваем ЦПУ). Linux начинался как небольшой хобби- проект для i386. В настоящее время это, скорее всего, наиболее переносимая операционная система (см. перечень портируемых систем по ссылке[3] сразу после этой таблицы). |
|
Данный каталог содержит реализацию шифров уровня ядра (алгоритма шифрования/ дешифрации, также известные как преобразования) и API ядра для обслуживания потребителей, которым требуются криптографические службы. |
|
Этот каталог содержит независимые от архитектуры заголовки ядра (также имеется ряд зависящих от
архитектуры заголовков в |
|
Это независимый от архитектуры код инициализации ядра; здесь находится, возможно, самое близкое к тому, что мы
получаем в функции main самого ядра (помните, ядро не является приложением): |
|
Ближайший аналог некой библиотеки для самого ядра. Важно осознавать, что само ядро
не поддерживает разделяемые библиотеки, как то делают прикладные приложения пространства пользователя.
Располагаемый здесь код автоматически связывается с основным файлом образа ядра и следовательно доступен этому ядру во время его исполнения
(внутри |
|
Здесь помещаются разнообразные сценарии, некоторые из которых применяются при сборке ядра, а многие для прочих целей (таких как статический/ динамический анализ и тому подобное; в основном Bash и Perl). |
|
Помещает LSM (Linux Security Module, модуль безопасности Linux), некую платформу Mandatory Access Control (MAC, мандатного контроля за доступом), которая имеет целью выставление более строгого контроля доступа для прикладных приложений пространства пользователя в пространство ядра, нежели это делает по умолчанию ядро (устанавливаемая по умолчанию модель носит название Discretionary Access Control (DAC, разграничительного контроля доступа). В настоящее время Linux поддерживает различные LSM; наиболее известными являются SELinux, AppArmor, Smack, Tomoyo, Integrity и Yama (обратите внимание, что LSM по умолчанию отключён)). |
|
Здесь располагаются различные инструменты, в основном, приложения (или сценарии) пространства пользователя,
которые "тесно связаны" с самим ядром (исключительным образцом служит |
Ниже приводятся важные пояснения по этой таблице:
-
[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)
|
Теперь мы закончили с Этапом 2, выделением дерева исходного кода! В качестве бонуса вы ознакомились с основами, относящимися к структуре исходного кода определённого ядра. Давайте теперь двинемся далее, к Этапу 3 и изучим как настраивать ядро Linux перед его сборкой.
Конфигурирование нового ядра вероятно наиболее критичный шаг во всём процессе сборки ядра. Одна из имеющихся причин, по которой Linux является получившей признание её критиками операционной системой, это её универсальность. Распространённым заблуждением является представление о том, что существует отдельная база кода ядра Linux для сервера (корпоративного класса) , центра обработки данных, рабочей станции и крошечного встроенного устройства Linux - нет, все они пользуются одним и тем же унифицированным исходным кодом ядра Linux! Таким образом, тщательная настройка ядра под конкретный вариант применения (сервер, настольный, встроенный или гибридный/ индивидуальный компьютер) является мощными функциональной возможностью и требованием. И это именно то, во что мы погружаемся здесь.
Совет | |
---|---|
В любом случае осуществляй те данный этап настройки ядра. Даже если вы чувствуете, что вам не требуются никакие изменения в существующей
(или установленной по умолчанию) конфигурации, очень важны выполнить данный этап хотя бы один раз как часть процесса сборки. В противном случае,
некоторые автоматически вырабатываемые здесь заголовки будут отсутствовать и вызывать проблемы. По крайнем мере, следует выполнить
|
Прежде всего, тем не менее, давайте подведём некую необходимую основу вод систему kbuild (kernel build).
Та инфраструктура, которая применяется ядром Linux для настройки и построения самого ядра известна как система kbuild. Без погружения в кровопролитные подробности, такая система kbuild связывает воедино весь комплекс процесса настройки и построения через четыре ключевых компонента:
-
Символы
CONFIG_FOO
-
Файл(ы) определения меню, именуемые
Kconfig
-
Makefile
(ы) -
Собственно файл настроек всего ядра
Основные цели этих компонентов суммируются следующим образом:
Компонента Kbuild | Назначение, кратко |
---|---|
Символ настройки |
Всякий настраиваемый |
Файлы |
Именно здесь определяются символы |
|
Система kbuild применяет рекурсивный подход Makefile. Тот Makefile, который располагается в корневой папке исходного кода ядра именуется Makefile верхнего уровня, с наличием Makefile в каждой вложенной папке для сборки имеющегося в ней исходного кода. Унифицированный (vanilla) исходный код 5.4 в целом обладает более чем 2 500 Makefile! |
Сам файл |
В конечном счёте его суть - фактическая настройка ядра - создаётся и хранится в корневой папке дерева
исходного кода ядра в текстовом файле ASCII с названием |
Главное- получить рабочий файл .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.
Таким образом, скажем, когда вы настраиваете ядро 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.
Совет | |
---|---|
Простой способ для того чтобы узнать какой именно файл настроек подходит к какой из платформ состоит в том чтобы просто выполнить
|
Аккуратная регулировка и настройка конфигурации ядра для продукта выступает важной частью работы, обычно выполняемой инженерами, работающими с некой платформой или в команде 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
. Как уже упоминалось, этот подход только задействованных модулей
ядра хорош для той цели, которая состоит в получении отправной точки настройки ядра в системе на основе 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 будет отображать в
окне консоли (в терминале) все отдельные новые параметры настроек и те доступные значения, в которые вы можете их установить.Далее она
будет запрашивать своего пользователя выбор необходимого значения для всех новых встретившихся параметров при выполняемой сборке ядра. Вы будете
наблюдать это как последовательности запросов и приглашений на ввод для ответа в своей командной строке.
Совет | |
---|---|
Соответствующее предложение на ввод будет сопровождаться суффиксом |
Здесь, по крайней мере, мы получим самый простой выход: просто нажимайте клавишу [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
в корне соответствующего дерева исходного кода ядра.
По мере того, как вы обзаведётесь опытом по сборке ядра, вы поймёте, что усилия по правильной настройке в первый раз конфигурации ядра (что критически важно!) являются высокими; и, естественно, то время, что требуется продолжительное время для сборки в самый первый раз. Однако, если всё сделано верно, тот процесс обычно становится намного проще - рецепт, который стоит повторять снова и снова.
Теперь давайте изучим как применять полезный и интуитивно понятный интерфейс пользователя для регулирования нашей конфигурации ядра.
Хорошо, отлично, теперь у нас имеется изначальный файл настроек ядра (.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
:
Как хорошо знают опытные разработчики, да и вообще любой, кто достаточно хорошо пользуется компьютером, что-то может пойти не так, как надо.
Возьмём, к примеру, следующий сценарий - запуск 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) для соответствующих вариантов настроек ядра со значениями, отображаемые в приводимой далее таблице. Пока не обращайте внимания на значение каждого из этих вариантов; они приводятся просто для того, чтобы попрактиковаться в общей системе настроек ядра:
Функциональная возможность | Воздействие и место в UI make menuconfig | Выбор кнопки <Help> для просмотра параметра CONFIG_<FOO> в точности | Значение: изначальное -> новое значение |
---|---|---|---|
Локальная версия |
Устанавливает компонент |
|
(none) -> |
Поддержка файла настроек ядра |
Позволяет вам наблюдать значения подробностей настроек текущего ядра
|
|
|
Аналогично предыдущему, плюс доступ через procfs |
Позволяет вам наблюдать значения подробностей настроек текущего ядра через
proc filesystem
(procfs)
|
|
|
Профилирование ядра |
Поддержка профилирования ядра;
|
|
|
Радиопереключателя HAM |
Поддержка радиопереключателя HAM;
|
|
|
Поддержка VirtualBox |
(Пара)виртуальная поддержка для VirtualBox;
|
|
|
Драйверы ввода/ вывода пространства пользователя (UIO) |
Поддержка UIO;
|
|
|
Предыдущее плюс UIO драйвер платформы с общей обработкой IRQ |
UIO драйвер платформы с общей обработкой IRQ;
|
|
|
Поддержка файловой системы MS DOS |
|
|
|
Безопасность: LSM |
Отключает LSM;
|
|
|
Отладка ядра: сведения об использовании стека |
|
|
|
Как именно вам воспринимать эту таблицу? Давайте выберем в качестве образца её первую строку; мы пройдёмся по ней столбец за столбцом:
-
Первый столбец определяет функциональную возможность, которую мы желаем изменять (редактировать/ включить/ запретить). Это именно самая последняя строка значения версии ядра (которую вы можете видеть в выводе
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
означает изменение параметра конфигурации с включённого на отключённый.
Совет | |
---|---|
Вы можете отыскать параметры для настроек ядра внутри системы интерфейса пользователя
|
Далее (собственно, в следующей главе) мы соберём ядро (и модули) с этими новыми параметрами настроек, загрузимся с ним и убедимся, что предыдущие параметры ядра были установлены так, как мы и хотели.
Но прямо сейчас мы ожидаем, что вы внесёте свой вклад: включите меню пользовательского интерфейса (при помощи обычного
make menuconfig
), затем пройдите по этой системе меню, найдите соответствующие параметры настроек
ядра и измените их, если это потребуется на то, что отражено в четвёртом столбце предыдущей таблицы.
Совет | |
---|---|
Обратите внимание на то, что в зависимости от применяемого вами в настоящий момент дистрибутива Linux и его модулей ядра
(помните, мы воспользовались для выработки первоначальных настроек |
В данном случае, чтобы обсуждение было разумным и компактным, мы покажем лишь полные подробности шагов по настройке второго и третьего
параметров конфигурации ядра, отражаемых нашей предыдущей таблицей (поддерживаемые .config
ядра).
Оставляем вам всё остальное. Итак, приступим:
-
Измените каталог на корневой в своём дереве исходного кода ядра (куда бы вы его не раскрутили его на своём диске):
cd ${LLKD_KSRC}
-
Настройте изначальный файл настроек ядра на основе нашего описанного ранее (в разделе Регулировка настройки через подход localmodconfig) третьего подхода:
lsmod > /tmp/lsmod.now make LSMOD=/tmp/lsmod.now localmodconfig
-
Запустите интерфейс пользователя:
make menuconfig
-
После того как загрузится интерфейс пользователя
menuconfig
, перейдите в элемент менюGeneral Setup
. Как правило, это второй элемент для x86-64. Перемещайтесь по нему при помощи клавиш клавиатуры со стрелками и входите в них нажатием клавишиEnter
. -
Теперь вы внутри элемента меню
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
.
-
После того как мы оказались в элементе меню
Kernel .config support
, мы можем обнаружить (в своём предыдущем снимке экрана) из его префикса<M>
, что это элемент меню с тремя состояниями, который установлен изначально на вариант<M>
для модуля. -
Оставляя выделенным данный параметр (
Kernel .config support
), воспользуйтесь клавишей стрелки вправо чтобы переместиться к кнопке< Help >
в планке инструментов внизу и нажмите клавишуEnter
при нахождении на кнопке< Help >
. Ваш экран теперь должен выглядеть как- то так:
Этот экран подсказки достаточно информативен. Действительно, несколько экранов подсказок настроек ядра очень хорошо заполнены и в самом деле полезны. К сожалению, часть из них отсутствует.
-
Хорошо, дальше нажмите
Enter
на кнопке< Help >
с тем, чтобы мы вернулись обратно к своему предыдущему экрану. -
Затем переключите элемент меню
Kernel .config support
, нажав клавишу пробела (мы предполагаем, что изначально это<M>
; то есть он настроен на модуль). Одно нажатие на пробел заставит ваши элементы интерфейса пользователя выглядят следующим образом:<*> Kernel .config support [ ] Enable access to .config through /proc/config.gz (NEW)
Обратите внимание на то, как он превратился в
<*>
, подразумевая что данная функциональная возможность будет встроена в сам образ ядра (фактически, она будет всегда включена). А пока давайте оставим её в этом состоянии (естественно, повторное нажатие на пробел снова переключит её сначала в отключённое состояние,< >
, а затем обратно к первоначальному состоянию<M>
). -
Теперь, с установленным состоянием элемента
<*>
(yes), прокрутите вниз к следующему элементу меню,[*] Enable access to .config through /proc/config.gz
, и включите его; теперь должен появиться следующий экран, который выглядит как- то так (мы распахнули его только до относящейся к делу части):Рисунок 2-8
Настройка ядра через make menuconfig; переключение некого Булева параметра конфигурации в состояние включённого
Совет Вы всегда можете воспользоваться клавишей стрелки вправо чтобы перейти к
< Help >
и просмотреть экран подсказки также и для этого элемента.Здесь мы не изучаем все оставшиеся меню настройки ядра; я оставляю это вам чтобы настроить в соответствии с тем, как это показано в нашей предыдущей таблице.
-
Обратно в главное меню (домашний экран), воспользуйтесь клавишей правой стрелки чтобы переместиться к кнопке
< Exit >
и нажмите на нейEnter
. Всплывёт окно диалога:
Он достаточно прост, не так ли? Нажмите
Enter
на кнопке< Yes >
для сохранения и выхода. Если вы выберете< No >
, вы утратите все изменения конфигурации (выполненные в этом сеансе). Или же можете нажать клавишуEsc
дважды
чтобы избавиться от этого диалога и продолжить работу с настройкой своего ядра. -
Сохраняемся и выходим. При нахождении на клавише
< 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
.
Предостережение | |
---|---|
Лучше НЕ пытаться изменять свой файл |
На самом деле, во время нашего быстрого приключения в системе 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
):
Результирующий диалог для нашего предыдущего поиска представляет интерес. Он раскрывает несколько моментов в относящихся к параметрам настройки сведениям:
-
Директиву настройки (просто добавьте префикс
CONFIG_
к тому, что он отображает вSymbol:
) -
Тип настройки (Булево, с тремя состояниями, цифробуквенный и тому подобное)
-
Строку приглашения на ввод
-
Что важно, его местоположение в самой системе меню (а потому вы можете отыскать его)
-
Его внутренние зависимости, если они имеются
-
Любые варианты настроек, которые он выбирает автоматически (включает) сам по себе в случае его выбора
Ниже приводится снимок экрана получаемого в результате диалога:
Все эти сведения присутствуют в неком текстовом файле 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
в самом корне дерева исходного кода ядра применяется для заполнения первоначального экрана
интерфейса пользователя menuconfig
. Взгляните на него, если пожелаете. Он работает выбирая в качестве
источников различные прочие файлы Kconfig
в различных папках вашего дерева исходного кода ядра. Приводимая
далее таблица суммирует наиболее важные файлы Kconfig*
и то, какие меню они обслуживают в интерфейсе
пользователя kbuild:
Меню | Местоположение файла Kconfig для него |
---|---|
Главное меню, первоначальный экран |
|
Общая установка + Включение поддержки загружаемых модулей |
|
Типы процессора и функциональные возможности +
Параметры шины + Эмуляции исполняемого кода |
|
Управление питанием |
|
Драйверы встроенного ПО |
|
Виртуализация |
|
Общие параметры зависимости от архитектуры |
|
Включение блочного уровня + Планировщики ввода/ вывода |
|
Форматы исполняемых файлов |
|
Параметры управления памятью |
|
Сетевая поддержка |
|
Драйверы устройств |
|
Файловые системы |
|
Параметры безопасности |
|
API криптографии |
|
Библиотечные подпрограммы |
|
Проникновение в ядро |
|
Обычно некий отдельный файл Kconfig
рулит отдельным меню. Теперь, давайте приступим к реальному добавлению
элемента меню.
В качестве тривиального примера давайте добавим свой собственный Булев макетный параметр конфигурации внутри своего меню
General Setup
. Мы хотим чтобы названием этой конфигурации было
CONFIG_LLKD_OPTION1
. Как можно видеть из нашей предыдущей таблицы, соответствующим файлом
Kconfig
для изменения выступает init/Kconfig
, который
является файлом мета меню, который задаёт меню General Setup
.
Давайте займёмся этим:
-
Чтобы пребывать в безопасности, всегда выполняйте резервное копирование:
cp init/Kconfig init/Kconfig.orig
-
Теперь внесите изменения в файл
init/Kconfig
:vi init/Kconfig
Прокрутите вниз до соответствующего местоположения внутри этого файла; здесь мы выбрали вставку записи сразу после параметра
CONFIG_LOCALVERSION_AUTO
. Следующий снимок экрана отображает нашу новую запись:
Совет Мы предоставили предыдущий текст как некий фрагмент кода в первоначальном файле
init/Kconfig
в дереве исходного кода GitHub нашей книги. Найдите его вch2/Kconfig.patch
.Наш новый элемент начинается с ключевого слова
config
, за которым следует частьFOO
вашей новой переменной конфигурацииCONFIG_LLKD_OPTION1
. Теперь же, просто считайте тот оператор, который мы сделали в своём файлеKconfig
, отвечающий за эту запись. Дополнительные сведения по языку/ синтаксисуKconfig
расположены в следующем разделе Некоторые подробности по языку самого Kconfig. -
Сохраните этот файл и покиньте этот редактор.
-
(Повторно) настройте своё ядро. Перейдите к нашему новому элементу меню и включите эту функциональность (обратите внимание как, в последующем усечённом снимке экрана он выделен и по умолчанию имеет значение off):
make menuconfig [...]
Вот соответствующий вывод:
-
Включите его (перебирая варианты пробелом), затем сохраните и покиньте систему меню.
Совет Пока пребываете там, нажмите кнопку
< Help >
. Вы должны обнаружить "подсказку", которую мы предоставили внутри своего файлаKconfig
. -
Убедитесь что наша функциональность была выбрана:
$ grep "LLKD_OPTION1" .config CONFIG_LLKD_OPTION1=y $ grep "LLKD_OPTION1" include/generated/autoconf.h $
Мы обнаружили, что в конце концов он был установлен в on внутри нашего файла
.config
, но это (всё ещё!) не внутри внутреннего автоматически выбираемого файла заголовка ядра. Это произойдёт при сборке данного ядра. -
Соберите своё ядро (не беспокойтесь; все подробности по сборке ядра находятся в нашей следующей главе. Вы всегда вначале можете ознакомиться с Главой 3, Сборка ядра Linux 5.4 из исходного кода - Часть II, а затем вернуться обратно сюда, если пожелаете...):
make -j4
-
Завершив всё это, повторно проверьте свой заголовок
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
до сих пор это просто лишь верхушка пресловутого айсберга. Дело
заключается в том, что система kbuild применяет язык (или синтаксис) Kconfig для выражения и создания меню при помощи простых текстовых директив
ASCII. Этот язык содержит записи меню, атрибуты (обратные) зависимости, ограничения видимости, тексты справок и тому подобное.
Замечание | |
---|---|
Рекомендуем вам за подробностями обращаться к документации по конструкциям и синтаксису языка |
Краткое (и неполное) упоминание наиболее употребимых конструкций Kconfig
приводится в нашей следующей
таблице:
Конструкция | Значение |
---|---|
|
Определяет здесь название соответствующей записи меню (в виде |
Атрибуты меню |
|
|
Определяет данный параметр конфигурации как Булев;
его значение в |
|
Определяет данный параметр конфигурации как с тремя состояниями;
его значение в |
|
Определяет данный параметр конфигурации как целое значение. |
|
Диапазон целых значений от |
|
Определяет значение по умолчанию; в случае необходимости применяет |
|
Некая последовательность описывает значение конфигурации ядра. |
|
Определяет некую зависимость для этого элемента меню: может обладать несколькими при помощи вида
синтаксиса |
|
Определяет обратную зависимость. |
|
Текст для отображения при выборе кнопки < Help >. |
Чтобы помочь разобраться с этим синтаксисом, ниже приводятся несколько образцов из lib/Kconfig.debug
(того файла, который описывает элементы для Kernel Hacking
- отладки ядра в действительности - раздела
интерфейса пользователя):
-
Мы начнём с простого (параметра
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. [...]
-
Далее давайте взглянем на параметр
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
-
Затем параметр
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 данной книги.