Где хранится ядро linux

Обновлено: 04.07.2024

Ядро Linux — ядро операционной системы, соответствующее стандартам POSIX, составляющее основу операционных систем семейства Linux.

Дистрибутив Arch Linux основан на ядре Linux. Помимо основной стабильной (stable) версии в Arch Linux можно использовать некоторые альтернативные ядра. В статье описываются доступные в официальных репозиториях версии ядер, возможные патчи, а также способы, которыми пользователи могут скомпилировать собственное ядро.

Пакет ядра устанавливается в файловую систему в каталоге /boot/ . Для загрузки нужного ядра при запуске системы необходимо соответствующим образом настроить загрузчик.

Contents

Официальные ядра

Помощь при работе с официальными ядрами можно найти на форуме и в баг-трекере.

Компиляция

Скомпилировать собственное ядро можно двумя способами:

/Arch Build System Преимущества — наличие готового PKGBUILD для пакета linux и удобство системы управления пакетами. /Традиционная компиляция Ручная загрузка архива файлов с исходными кодами ядра и их компиляция.

  • Лучший способ повысить производительность — адаптировать ядро под свою систему, в первую очередь под архитектуру и тип процессора.
  • Если оставить в ядре только действительно нужные вам функции, то удастся уменьшить его размер и, следовательно, время сборки. Например, удалите из него Bluetooth, Video4Linux, 1000Mbit Ethernet и прочие вещи, которые на вашей машине точно не понадобятся.

Файлы конфигурации пакетов с ядрами Arch можно найти в исходниках (например, файл [1] из linux ). Если включена опция ядра CONFIG_IKCONFIG_PROC , то файл /proc/config.gz содержит настройки ядра, которое работает на вашей машине в данный момент.

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

Неофициальные ядра

Отладка регрессий

Прежде всего проверьте ядро linux-mainline AUR на предмет того, не была ли проблема уже решена. В прикреплённом комментарии указан репозиторий с уже собранными ядрами, так что собирать ядро вручную не придётся.

Если проблема проявляется не слишком часто, то имеет смысл попробовать LTS-ядро ( linux-lts ). Старые версии LTS-ядер можно найти в архиве Arch Linux.

Если избавиться от проблемы не удалось, попробуйте локализовать баг в linux-git AUR , после чего сообщите о нём в баг-трекер ядра. Важно проверять ванильное непропатченное ядро, чтобы убедиться, что причиной ошибки является не патч. Если проблемы вызывает патч, то сообщите об этом его автору.

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

Так что же делает ядро Linux и почему оно так востребовано? Мы рассмторим архитектуру ядра, его основные задачи и интерфейсы. Это поможет понять его преимущества и недостатки.

Что такое ядро Linux

1. На чём написано ядро

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

2. Архитектура ядра

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


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

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

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

Интерфейсы, имена переменных и структура каталогов системы определяются стандартами POSIX, что делает Linux UNIX-подобной системой. Линус Торвальдс, создатель ядра, выбрал UNIX по той причине, что имелась база приложений, необходимых для функционирования операционной системы, утилиты GNU. Однако, он не разделяет идеи философии UNIX, одна программа – одно действие, текстовый вывод информации как универсальный интерфейс. По его мнению они не отражают запросы современных пользователей.

3. Что делает ядро

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

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

Драйверы занимают большую часть ядра. Некоторые из них представлены сразу в виде бинарных файлов, что противоречит идеям фонда СПО. Версия ядра без закрытых драйверов называется Linux-libre, на практике его использование крайне затруднительно, так как собрать компьютер на основе комплектующих только с открытыми драйверами у вас едва ли получится.

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

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

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

Несмотря на то, что ядро контролирует все процессы, само по себе оно ничего не делает, ему нужны пользовательские программы и их процессы. Среди базовых приложений стоит отметить утилиты проекта GNU, без них не обходится ни один дистрибутив Linux. Например, командная оболочка Bash позволит вам вводить команды в консоли.

4. Версии ядра

Запись версии ядра можно представить в виде: A.B.C-D.

  • A – это версия ядра, изначально планировалось повышать номер только после значительной переработки ядра, но сейчас это делают после достаточного количества правок и нововведений примерно два раза за десятилетие.
  • B – это ревизия ядра, обновление происходит каждые 2-3 месяца. Некоторые из них получают долгосрочную поддержку (LTS – long term support). Последним таким ядром стало 5.10. Каждая ревизия имеет большой список изменений, которые сначала проверяют тестировщики.
  • C и D отвечают за небольшие правки в коде ядра. С увеличивается в том случае, если были обновлены драйверы устройств, а D – когда вышел очередной патч безопасности. Эти номера могут меняться практически каждый день.

Узнать версию ядра можно с помощью команды:

5. Где хранятся файлы ядра

8C3vNCEd+UxpcAAAAASUVORK5CYII=

Файлы ядра хранятся в каталоге /boot. Непосредственно само ядро находится в запакованном виде в файле vmlinuz, где z как раз и указывает на то, что ядро сжато для экономии места. Файл initrd.img – это первичная файловая система, которая монтируется перед тем, как подключить реальные накопители к виртуальной файловой системе VFS. Там же содержатся дополнительные модули ядра, поэтому этот файл может быть больше самого ядра. В файле system.map можно найти адреса функций и процедур ядра, что будет полезно при отладке.

Выводы

Подведём итоги. Теперь вы знаете что такое ядро Linux. Ядро — это самая привилегированная программа на компьютере. Если говорить конкретно о ядре Linux, то оно монолитное. Иными словами, в режиме ядра работает всё необходимое для управления ресурсами компьютера. В пользовательском режиме также имеются программы для управления, но они лишь расширяют возможности ядра.

Соответствие стандартам POSIX позволило перенести ядро на множество платформ. Но следование философии UNIX во многих аспектах дистрибутивов Linux имеет как плюсы, так и минусы. Простые приложения с выводом в терминал хорошо подходят для серверов, но для домашнего использования такой подход едва ли может привлечь широкие массы.

К примеру, Android использует ядро Linux, но не утилиты GNU и в целом не пытается стать похожим на UNIX, что во многом обеспечило его популярность. Так что ядро – это лишь инструмент, а цели могут быть любыми, от запуска терминала и до создания суперкомпьютеров.

В 1991 году Linus Torvalds разработал первую версию ядра Linux. Он выложил исходный код ядра в открытый доступ, после чего другие люди начали вносить свой вклад в его развитие. В разработке одной из версий ядра (а именно, версии 2.6.27, выпущенной в ноябре 2008 года) поучаствовало более 4000 разработчиков.

Для основных версий ядра Linux используются четные и нечетные номера. Ранее существовало разделение версий, в соответствии с которым версии 2.0 , 2.2 , 2.4 и 2.6 считались стабильными. В то же время версии 2.1 , 2.3 и 2.5 считались нестабильными (или разрабатываемыми). Начиная с выпуска версии ядра 2.6.0 в январе 2004 года вся разработка велась в рамках ветки 2.6. Версия ядра 2.7.0 так и не была выпущена и, судя по заявлениям главного разработчика ядра, которым все также является Linus Torvalds, схема разделения версий ядра на четные/стабильные и нечетные/разрабатываемые не используется и не будет использоваться в будущем.

28.1.2. Команда uname -r

Для того, чтобы узнать текущую версию ядра Linux, следует использовать команду uname -r таким образом, как показано ниже.

В первом примере показан вывод данной команды в системе с ядром Linux основной версии 2.6 и дополнительной версии 24 . Остальная часть строки -22-generic является специфичной для дистрибутива (в данном случае используется дистрибутив Ubuntu).

При выполнении этой же команды в дистрибутиве Red Hat Entrprise Linux можно получить информацию о более старом ядре (версии 2.6.18), причем строка -92.1.17.el5 также является специфичной для дистрибутива.

28.1.3. Файл /proc/cmdline

Параметры, которые были переданы ядру ОС в процессе загрузки системы, могут быть получены из файла /proc/cmdline .

28.1.4. Однопользовательский режим

В случае передачи ядру Linux параметра single будет осуществляться загрузка системы в однопользовательском режиме . В данном случае после загрузки ядра Linux будет запущена командная оболочка bash с привилегиями пользователя root (ввода пароля не потребуется).

В некоторых дистрибутивах данная возможность заблокирована (на этапе компиляции ядра ОС).

28.1.5. Параметр init=/bin/bash

Обычно ядро ОС запускает бинарный файл, путь к которому передан с помощью параметра init , создавая таким образом первый процесс-демон. Добавление параметра init=/bin/bash к строке параметров ядра позволяет вызывать командную оболочку bash (снова с правами пользователя root без необходимости ввода пароля).

28.1.6. Файл журнала /var/log/messages

Ядро ОС в процессе загрузки передает демону syslogd информацию о множестве выполняемых действий, которая сохраняется в файле журнала /var/log/messages . Из данного файла журнала можно извлечь информацию о процессе загрузки ядра, включая информацию обо всех устройствах, которые были идентифицированы в процессе загрузки системы.

А в данном примере показан фрагмент файла /var/log/messages , который может использоваться для извлечения информации о дисковом устройстве, представленном файлом устройства /dev/sda .

28.1.7. Утилита dmesg

28.2. Исходный код ядра Linux

Архивы исходного кода всех версий ядра Linux расположены по пути pub/linux/kernel/.

28.2.2. Директория /usr/src

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

В первую очередь давайте рассмотрим структуру поддиректорий директории /usr/src в дистрибутиве Debian . В данном случае в этой директории можно обнаружить две версии полного исходного кода ядра Linux. При поиске определенного файла (e1000_main.c) исходного кода с помощью утилиты find можно получить полный путь к этому файлу.

Данная структура поддиректорий очень похожа на структуру поддиректорий директории /usr/src в дистрибутиве Ubuntu за тем исключением, что в данном случае в директории расположен исходный код одной версии ядра (и эта версия более новая).

Теперь давайте рассмотрим содержимое директории /usr/src в дистрибутиве Red Hat Entrprise Linux .

Нам придется погрузиться немного глубже в дерево директорий для того, чтобы добраться до исходного кода ядра ОС в дистрибутиве Red Hat!

28.2.3. Загрузка исходного кода ядра ОС

Установка пакета программного обеспечения с исходным кодом ядра ОС в дистрибутиве Debian осуществляется достаточно просто с помощью команды aptitude install linux-source . В первую очередь вы можете осуществить поиск всех пакетов программного обеспечения с именами linux-source таким образом, как показано в примере ниже.

После этого вы можете использовать команду aptitude install для загрузки и установки пакета программного обеспечения с исходным кодом ядра Linux из состава дистрибутива Debian.

После того, как утилита aptitude закончит работу, вы обнаружите новый файл с именем /usr/src/linux-source-<версия>.tar.bz2 в файловой системе вашего компьютера.

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

И после того, как утилита aptitude завершит свою работу, мы получим файл /usr/src/linux-source-<версия>.tar.bz2 .

Red Hat Enterprise Linux

Для загрузки пакета исходного кода ядра ОС дистрибутива RHEL следует использовать длинную команду (команда должна располагаться в одной строке без завершающего символа \).

После того, как утилита wget закончит свою работу, вы получите файл с расширением .rpm размером в 60 Мб.

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

В первую очередь мы должны выполнить команду rpm -i kernel-2.6.9-42.EL.src.rpm для установки загруженного пакета программного обеспечения дистрибутива Red Hat.

После этого мы должны перейти в директорию SPECS и задействовать утилиту rpmbuild .

Утилита rpmbuild поместит исходный код ядра Linux дистрибутива RHEL в директорию /usr/src/redhat/BUILD/kernel-<версия>/ .

28.3. Файлы, используемые в процессе загрузки ядра ОС

28.3.1. Файл vmlinuz

Файл vmlinuz из директории /boot является сжатым исполняемым файлом ядра ОС.

28.3.2. Файл initrd

Ядро ОС использует файл initrd (Initial RAM disk - диск в оперативной памяти для начальной инициализации) в процессе загрузки системы. Данный диск монтируется до момента окончания загрузки ядра ОС и может содержать дополнительные драйверы и модули ядра ОС. На самом деле, данный файл является сжатым архивом формата CPIO , поэтому вы можете просмотреть его содержимое следующим образом.

28.3.3. Файл System.map

Файл System.map содержит таблицу символов и изменяется при каждой компиляции ядра ОС. Таблица символов также присутствует в файле /proc/kallsyms (до выпуска ядра Linux версии 2.6 данный файл носил имя /proc/ksyms).

28.3.4. Файл .config

Последним файлом, копируемым в директорию /boot, является файл со значениями параметров конфигурации ядра ОС, используемый в процессе его компиляции. Данный файл не должен находиться директории /boot для корректного функционирования ядра ОС, но размещение его копии в данной директории является обычной практикой. Благодаря его наличию появляется возможность осуществления повторной компиляции ядра ОС с использованием тех же значений параметров конфигурации, которые были использованы для компиляции существующего работоспособного ядра ОС.

28.4. Модули ядра Linux

28.4.1. Информация о модулях ядра Linux

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

28.4.2. Директория /lib/modules

Модули ядра ОС хранятся в директории /lib/modules/<версия-ядра-ос> . Для хранения модулей каждой версии ядра Linux, которая была скомпилирована для вашей системы, создается отдельная директория.

28.4.3. Файл <модуль>.ko

Имя файла, содержащего код модуля ядра ОС, обычно оканчивается на .ko . В данном примере показано расположение файлов модулей ядра ОС, предназначенных для поддержки протокола isdn.

28.4.4. Утилита lsmod

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

28.4.5. Файл /proc/modules

Файл /proc/modules содержит список всех модулей, загруженных ядром ОС. Список модулей ядра ОС из данного файла является слишком длинным для того, чтобы приводить его в данной книге, поэтому давайте используем утилиту grep для поиска модуля с именем vm .

Мы видим, что одновременно загружены модуля ядра ОС vmmon и vmnet. Вы можете получить ту же самую информацию и с помощью утилиты lsmod . На самом деле, утилита lsmod всего лишь читает содержимое файла /proc/modules и выводит его с соответствующим форматированием.

28.4.6. Зависимости модулей ядра ОС

Некоторые модули ядра ОС зависят от других модулей ядра ОС. В следующем примере вы можете увидеть, что модуль ядра ОС с именем nfsd зависит от модулей с именами exportfs, lockd и sunrpc.

28.4.7. Утилита insmod

Модули ядра ОС могут быть загружены в ручном режиме с помощью утилиты insmod . Это очень простой (и устаревший) способ загрузки модулей ядра ОС. В примере ниже показан процесс загрузки модуля ядра ОС с именем fat (реализующего поддержку файловой системы fat).

Утилита insmod не определяет зависимости между модулями ядра ОС, поэтому в следующем примере нам не удалось загрузить с помощью данной утилиты модуль с именем isdn (так как модуль с именем isdn зависит от модуля с именем slhc).

28.4.8. Утилита modinfo

Как вы можете увидеть в представленном ниже выводе утилиты modinfo , модуль ядра ОС с именем isdn зависит от модуля ядра ОС с именем slhc.

28.4.9. Утилита modprobe

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

В данном примере показан способ загрузки модуля с именем isdn с помощью утилиты modprobe с автоматической загрузкой модуля с именем shlc в фоновом режиме.

28.4.10. Файл /lib/modules/<версия-ядра-ос>/modules.dep

Зависимости модулей ядра ОС описаны в рамках файла с именем modules.dep .

28.4.11. Утилита depmod

Файл modules.dep может быть обновлен (повторно создан) с помощью утилиты depmod . В следующем примере не было добавлено никаких новых модулей ядра ОС, поэтому утилита depmod сгенерировала идентичный файл.

28.4.12. Утилита rmmod

По аналогии с утилитой insmod , утилита rmmod на сегодняшний день практически не используется.

28.4.13. Команда modprobe -r

В отличие от утилиты rmmod , утилита modprobe будет автоматически удалять неиспользуемые модуля ядра ОС.

28.4.14. Файл конфигурации /etc/modprobe.conf

Файл конфигурации /etc/modprobe.conf и специальные файлы конфигурации из директории /etc/modprobe.d могут содержать псевдонимы (для использования людьми), а также параметры (для зависимых модулей ядра ОС), используемые утилитой modprobe .

28.5. Компиляция ядра ОС

28.5.1. Дополнительная версия

Перейдите в директорию /usr/src/redhat/BUILD/kernel-2.6.9/linux-2.6.9/ и измените дополнительную версию ядра ОС, заменив значение параметра extraversion в файле с именем Makefile.

28.5.2. Команда make mrproper

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

28.5.3. Файл .config

Теперь скопируйте работоспособный файл с именем .config из директории /boot в директорию с исходным кодом вашего ядра ОС. Этот файл содержит значения параметров конфигурации, которые использовались при компиляции вашего текущего ядра ОС. Грубо говоря, данный файл содержит информацию о том, должны ли компилироваться определенные модули ядра ОС.

28.5.4. Команда make menuconfig

Теперь следует выполнить команду make menuconfig (или команду make xconfig в случае использования графического интерфейса). Запущенная утилита позволит вам установить, необходимо ли компилировать определенный модуль (m), включить код модуля в состав ядра ОС (*) или вообще не компилировать его (что позволит сократить размер ядра ОС). Если вы откажитесь от компиляции слишком большого количества модулей, ваше ядро ОС не будет работать корректно. Данные конфигурации будут сохранены в скрытом файле с именем .config.

28.5.5. Команда make clean

Выполните команду make clean для подготовки исходного кода ядра ОС к компиляции. Команда make clean позволяет удалить большую часть сгенерированных файлов, но сохраняет ваши файлы конфигурации ядра ОС. Исполнение команды make mrproper на данном этапе приведет к уничтожению файла .config, который был создан в результате исполнения команды make menuconfig .

28.5.6. Команда make bzImage

А теперь следует выполнить команду make bzImage , присесть и расслабиться, ожидая окончания процесса компиляции ядра ОС. Вы также можете использовать команду time make bzImage , чтобы получить информацию о времени, необходимым для компиляции ядра ОС, которая может понадобиться для планирования непродолжительной прогулки во время следующей компиляции.

Исполнение данной команды завершится выводом информации о пути к результирующему файлу bzImage (а также времени компиляции, если вы также использовали команду time ).

На данном этапе вы можете вручную скопировать результирующий файл в директорию /boot с помощью команды cp arch/i386/boot/bzImage /boot/vmlinuz-<версия-ядра-ОС> .

28.5.7. Команда make modules

Теперь следует выполнить команду make modules . На компиляцию всех модулей ядра ОС уйдет от 20 до 50 минут.

28.5.8. Команда make modules_install

Для копирования всех скомпилированных модулей ядра ОС в директорию /lib/modules следует всего лишь выполнить команду make modules_install (на установку модулей уйдет примерно 20 секунд). В примере ниже приведен список содержимого директории модулей перед исполнением упомянутой команды.

А это список содержимого этой же директории после исполнения этой команды. Обратите внимание на то, что в процессе исполнения команды make modules_install была создана новая директория для модулей нового ядра ОС.

28.5.9. Директория /boot

Нам все также необходимо скопировать исполняемый файл ядра ОС, файл System.map и наш файл со значениями параметров конфигурации ядра ОС в директорию /boot. Строго говоря, копировать файл со значениями параметров конфигурации ядра ОС с именем .config совсем не обязательно, но он может пригодиться в будущем при компиляции ядра ОС.

28.5.10. Утилита mkinitrd

Ядро ОС обычно использует файл initrd в процессе загрузки. Мы можем использовать утилиту mkinitrd для генерации этого файла. Убедитесь в том, что вы используете корректное имя ядра ОС!

28.5.11. Системный загрузчик

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

28.6. Компиляция отдельного модуля ядра ОС

28.6.1. Файл исходного кода hello.c

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

28.6.2. Файл Makefile

Файл для сборки модуля ядра ОС будет содержать следующие строки.

Для компиляции модуля необходимы только два описанных файла.

28.6.3. Команда make

В примере ниже представлен результат исполнения команды make .

Теперь у нас больше файлов.

28.6.4. Файл hello.ko

Следует использовать утилиту modinfo для проверки того, действительно ли файл с расширением .ko является модулем ядра ОС.

Отлично, значит мы можем загрузить наш модуль ядра ОС с именем "hello".

Наконец мы можем обнаружить небольшой сюрприз в файле журнала /var/log/messages .

Версии

Нумерация версий

Сначала версии нумеровались 0.01, 0.02, 0.03, . и до 1.0.

Затем начали использовать схему a.b.c (от версии 1.0 до версии 2.6). a — версия ядра, b — мажорная ревизия, c — минорная ревизия. Первое число изменялось при очень крупных переработках концепции ядра. Это было дважды в истории: в 1994 (version 1.0) и в 1996 (version 2.0). Чётность числа b определяла стабильность ядра: нечётные числа — разработческие версии, чётные числа — стабильные версии (например 1.2, 2.4 или 2.6). Минорная версия c увеличивалась при фиксах багов и при исправлениях в безопасности.

В 2004 г. после релиза 2.6.0 схема нумерации версий поменялась. Префикс 2.6 сохранялся в течение семи лет, последняя цифра увеличивалась с каждым релизом раз в два-три месяца. Иногда при срочных фиксах добавлялось четвёртое число (2.6.8.1). Чётно-нечётная схема упразднена. Разработческие версии имеют суффикс -rc.

Версия 3.0, выпущенная в 2011 г., не имела каких-то серьёзных изменений концепции. Следовала после версии 2.6.39. Считается, что Линус так решил, потому что число стало слишком большим, и чтобы заодно отметить 20-летие Linux.

Затем релизы продолжили идти по времени, но с увеличением уже второй цифры, а не третьей.

После 3.19 выпустили версию 4.0 (в 2015 г.). Затем после 4.20 вышла версия 5.0 (в марте 2019 г.). Переход к новым мажорным версиям тут не был связан с какими-то революционными изменениями. Линусу не нравятся большие номера версий. "I'm once more close to running out of fingers and toes," говорил Торвальдс.

По состоянию на 6 апреля 2020 г. последней стабильной версией ядра является версия 5.6.2.

Разработка

Код написан в основном на C с некоторыми расширениями gcc и на ассемблере (с использованием AT&T-синтаксиса GNU Assembler). Из-за наличия нестандартных хаков долгое время С-код собирался только компилятором GCC. Большим достижением для разработчиков альтернативного компилятора Clang стало то, что в 2019 году версия Clang 9.0 смогла наконец собрать всё ядро Linux под x86-64 без дополнительных патчей.

Изначально в разработке не использовалась автоматизированная система контроля версий из-за нелюбви Линуса к таким системам. В 2002 г. начали использовать BitKeeper, но это была коммерческая система. В 2005 г. Торвальдс и команда за две недели написали новую систему контроля версий — git.

Узнать версию ядра

Архитектура ядра Linux

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

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

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

Файлы и форматы

vmlinux

Это статически слинкованный исполняемый файл, содержащий ядро Linux в одном из поддерживаемых форматов (ELF, COFF или a.out).

Название vmlinux сложилось исторически. Традиционно в Unix образ ядра назывался unix. Префикс vm значит Virtual Memory.

Традиционно лежит в корне ФС. "Сырой" vmlinux может быть полезен при отладке.

vmlinux.bin

Можно встретить на некоторых системах. То же самое, но без символов и информации для релокации.

vmlinuz

Образ ядра обычно сжимают. Одна из причин — экономия места на диске (актуально для embedded). На некоторых системах I/O происходит медленнее, чем декомпрессия при помощи CPU меньшего объёма прочитанных с диска сжатых данных (вероятно, неактуально для SSD). В прошлом на размер накладывались жёсткие ограничения (невозможность адресовать диск далее 1024 цилиндра при загрузке).

Традиционное название файла — vmlinuz.

bzImage

Это формат образа (big zImage). Был разработан для того, чтобы преодолеть ограничения на размер адресуемых данных при загрузке на разных архитектурах.

Название может ввести в заблуждение. Этот образ не обязательно сжимается при помощи bzip2, может быть и другой алгоритм.

После компиляции ядра получается файл с именем bzImage, его обычно размещают для загрузки под именем vmlinuz:

System.map

System.map — файл, внутри которого находится символьная таблица адресов функций и процедур, используемых ядром. В этой таблице перечислены имена переменных и функций и их адреса в памяти компьютера. Эта таблица весьма полезна при отладке ядра в случае Kernel panic или Linux oops. System.map генерируется при компиляции ядра.

Initial RAM Disk

Initrd (сокращение от англ. Initial RAM Disk, диск в оперативной памяти для начальной инициализации) — временная файловая система, используемая ядром Linux при начальной загрузке. Initrd обычно используется для начальной инициализации перед монтированием «настоящих» файловых систем. В Linux Kernel HOWTO (руководстве о сборке ядра) пишут, что initrd призван решить проблему курицы и яйца для модульного ядра: для монтирования файловой системы необходим модуль для работы с диском и файловой системой, а для чтения модуля необходима файловая система, с которой этот модуль читается.

Зачем нужно

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

К тому же корневая ФС может быть на томе программного RAID, LVM, даже на NFS (для бездисковых машин).

initrd

  • A ramdev block device is created. It is a ram-based block device, that is a simulated hard disk that uses memory instead of physical disks.
  • The initrd file is read and unzipped into the device, as if you did zcat initrd | dd of=/dev/ram0 or something similar.
  • The initrd contains an image of a filesystem, so now you can mount the filesystem as usual: mount /dev/ram0 /root. Naturally, filesystems need a driver, so if you use ext2, the ext2 driver has to be compiled in-kernel.
  • Done!

initramfs

В ядре Linux 2.6 появилась новая концепция загрузочного диска — он представляет собой сжатый gzip'ом cpio-архив.

cpio (copy in and out) — архиватор и формат файла, похожий на tar. Не уменьшает объём данных, просто соединяет несколько файлов в один.

  • A tmpfs is mounted: mount -t tmpfs nodev /root. The tmpfs doesn't need a driver, it is always on-kernel. No device needed, no additional drivers.
  • The initramfs is uncompressed directly into this new filesystem: zcat initramfs | cpio -i, or similar.
  • Done!

Посмотреть внутрь

Модули ядра

Модули хранятся в каталоге "/lib/modules/<версия ядра>" в виде файлов с расширением «ko». Для получения списка всех модулей из дерева можно выполнить команду поиска всех файлов с расширением «ko» в каталоге с модулями текущего ядра:

Более детальную информацию о модуле можно получить при помощи команды modinfo:

Загрузить модуль в ядро можно при помощи двух команд: «insmod» и «modprobe», отличающихся друг от друга возможностью просчета и удовлетворения зависимостей.

  1. Команда insmod загружает конкретный файл с расширением «ko», при этом, если модуль зависит от других модулей, еще не загруженных в ядро, команда выдаст ошибку, и не загрузит модуль.
  2. Команда modprobe работает только с деревом модулей, и возможна загрузка только оттуда по имени модуля, а не по имени файла.

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

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

Чтобы его выгрузить, можно воспользоваться командой rmmod или той же командой modprobe с ключом -r. В качестве параметра обоим командам нужно передать только имя модуля. Если модуль не используется, то он будет выгружен, а если используется — будет выдана ошибка, и придется выгружать все модули, которые от него зависят.

Автоматизация

В современных ядрах при подключении оборудования модули подключаются автоматически, а это событие обрабатывается демоном udev, который создает соответствующий файл устройства в каталоге /dev. Все это выполняется в том случае, если соответствующий модуль корректно установлен в дерево модулей. В случае с файловыми системами ситуация та же: при попытке монтирования файловой системы ядро подгружает необходимый модуль автоматически, и выполняет монтирование. Если необходимость в модуле не на столько очевидна, ядро его не загружает самостоятельно. Например, для поддержки функции шифрования на loop устройстве нужно вручную подгрузить модуль «cryptoloop», а для непосредственного шифрования — модуль алгоритма шифрования, например «blowfish».

Для автоматической загрузки модулей в разных дистрибутивах предусмотрены разные механизмы. B Ubuntu — редактируем файл /etc/modules [1].

Читайте также: