Настройка Wi-Fi

Конфигурирование и компиляция ядра Linux. Исходные коды Linux

Конфигурирование и компиляция ядра Linux. Исходные коды Linux

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

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

Конфигурация ядра

Первый шаг - найти исходники ядра наиболее близкие к тому образу ядра, насколько это возможно. Наверное, получение правильной конфигурации - наиболее сложная составляющая всего процесса сборки модуля. Начните с того номера версии ядра, который может быть прочитан из /proc/version . Если, как я, вы собираете модуль для устройства Android, попробуйте ядра Android от Code Aurora, Cyanogen или Android, те, что наиболее ближе к вашему устройству. В моем случае, это было ядро msm-3.0. Заметьте, вам не обязательно необходимо искать в точности ту же версию исходников, что и версия вашего образа ядра. Небольшие отличия версии, наиболее вероятно, не станут помехой. Я использовал исходники ядра 3.0.21, в то время как версия имеющегося образа ядра была 3.0.8. Не пытайтесь, однако, использовать исходники ядра 3.1, если у вас образ ядра 3.0.x.

Если образ ядра, что у вас есть, достаточно любезен, чтобы предоставить файл /proc/config.gz , вы можете начать с этого, в противном случае, вы можете попытаться начать с конфигурацией по умолчанию, но в этом случае нужно быть крайне аккуратным (хотя я и не буду углубляться в детали использования дефолтной конфигурации, поскольку мне посчастливилось не прибегать к этому, далее будут некоторые детали относительно того, почему правильная конфигурация настолько важна).

Предполагая, что arm-eabi-gcc у вас доступен по одному из путей в переменной окружения PATH, и что терминал открыт в папке с исходными файлами ядра, вы можете начать конфигурацию ядра и установку заголовочных файлов и скриптов:

$ mkdir build $ gunzip config.gz > build/.config # или что угодно, для того, чтобы приготовить.config $ make silentoldconfig prepare headers_install scripts ARCH=arm CROSS_COMPILE=arm-eabi- O=build KERNELRELEASE=`adb shell uname -r`
Сборка silentoldconfig , наиболее вероятно, спросит, хотите ли вы включить те или иные опции. Вы можете выбрать умолчания, но это вполне может и не сработать.

Можно использовать что-нибудь другое в KERNELRELEASE , однако это должно совпадать в точности с версией ядра, с которого вы планируете подгружать модуль.

Написание простого модуля

Чтобы создать пустой модуль, необходимо создать два файла: исходник и Makefile . Расположите следующий код в файле hello.c , в некоторой отдельной директории:

#include /* Needed by all modules */ #include /* Needed for KERN_INFO */ #include /* Needed for the macros */ static int __init hello_start(void) { printk(KERN_INFO "Hello world\n"); return 0; } static void __exit hello_end(void) { printk(KERN_INFO "Goodbye world\n"); } module_init(hello_start); module_exit(hello_end);
Поместите следующий текст в файл Makefile в той же директории:

Obj-m = hello.o
Сборка модуля достаточна проста, однако на данном этапе полученный модуль не сможет загрузиться.

Сборка модуля

При обычной сборки ядра система сборки ядра создает файл hello.mod.c , содержимое которого может создать различные проблемы:

MODULE_INFO(vermagic, VERMAGIC_STRING);
Значение VERMAGIC_STRING определяется макросом UTS_RELEASE , который располагается в файле include/generated/utsrelease.h , генерируемом системой сборки ядра. По умолчанию, это значение определяется версией ядра и статуса git-репозитория. Это то, что устанавливает KERNELRELEASE при конфигурации ядра. Если VERMAGIC_STRING не совпадает с версией ядра, загрузка модуля приведет к сообщению подобного рода в dmesg:

Hello: version magic "3.0.21-perf-ge728813-00399-gd5fa0c9" should be "3.0.8-perf"
Далее, также имеем здесь определение структуры модуля:

Struct module __this_module __attribute__((section(".gnu.linkonce.this_module"))) = { .name = KBUILD_MODNAME, .init = init_module, #ifdef CONFIG_MODULE_UNLOAD .exit = cleanup_module, #endif .arch = MODULE_ARCH_INIT, };
Само по себе, это определение выглядит безобидно, но структура struct module , определенная в include/linux/module.h , несет в себе неприятный сюрприз:

Struct module { (...) #ifdef CONFIG_UNUSED_SYMBOLS (...) #endif (...) /* Startup function. */ int (*init)(void); (...) #ifdef CONFIG_GENERIC_BUG (...) #endif #ifdef CONFIG_KALLSYMS (...) #endif (...) (... plenty more ifdefs ...) #ifdef CONFIG_MODULE_UNLOAD (...) /* Destruction function. */ void (*exit)(void); (...) #endif (...) }
Это означает, что для того, чтобы указатель init оказался в правильном месте, CONFIG_UNUSED_SYMBOLS должен быть определен в соответствии с тем, что использует наш образ ядра. Что же насчет указателя exit, - это CONFIG_GENERIC_BUG , CONFIG_KALLSYMS , CONFIG_SMP , CONFIG_TRACEPOINTS , CONFIG_JUMP_LABEL , CONFIG_TRACING , CONFIG_EVENT_TRACING , CONFIG_FTRACE_MCOUNT_RECORD и CONFIG_MODULE_UNLOAD .

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

Static const struct modversion_info ____versions __used __attribute__((section("__versions"))) = { { 0xsomehex, "module_layout" }, { 0xsomehex, "__aeabi_unwind_cpp_pr0" }, { 0xsomehex, "printk" }, };
Эти определения берутся из файла Module.symvers , который генеруется в соответствии с заголовочными файлами.

Каждая такая запись представляет символ, требуемый модулю, и то, какую сигнатуру должен иметь символ. Первый символ, module_layout , зависит от того, как выглядит struct module , то есть, зависит от того, какие опции конфигурации, упомянутые ранее, включены. Второй, __aeabi_unwind_cpp_pr0 , - функция, специфичная ABI ARM, и последний - для наших вызовов функции printk .

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

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

Hello: disagrees about version of symbol symbol_name
Что значит, что нам нужен правильный, соответствующий образу ядра, файл Module.symvers , которым мы не располагаем.

Изучаем ядро

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

Ядро использует следующую функцию для поиска в своей таблицы символов (в kernel/module.c):

Bool each_symbol_section(bool (*fn)(const struct symsearch *arr, struct module *owner, void *data), void *data) { struct module *mod; static const struct symsearch arr = { { __start___ksymtab, __stop___ksymtab, __start___kcrctab, NOT_GPL_ONLY, false }, { __start___ksymtab_gpl, __stop___ksymtab_gpl, __start___kcrctab_gpl, GPL_ONLY, false }, { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, __start___kcrctab_gpl_future, WILL_BE_GPL_ONLY, false }, #ifdef CONFIG_UNUSED_SYMBOLS { __start___ksymtab_unused, __stop___ksymtab_unused, __start___kcrctab_unused, NOT_GPL_ONLY, true }, { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, __start___kcrctab_unused_gpl, GPL_ONLY, true }, #endif }; if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data)) return true; (...)
Структура, используемая в данной функции, определена в include/linux/module.h:

Struct symsearch { const struct kernel_symbol *start, *stop; const unsigned long *crcs; enum { NOT_GPL_ONLY, GPL_ONLY, WILL_BE_GPL_ONLY, } licence; bool unused; };
Примечание: данный код ядра не изменился значительно за последние четыре года (видимо, с момента рассматриваемого релиза ядра 3.0, - прим. пер.).

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

Данные эти статичны и постоянны, что означает, что они появятся в бинарнике ядра как есть. Сканируя ядро на предмет трех идущих друг за другом последовательностей состоящих из трех указателей в адресном пространстве ядра и следом идущих значений типа integer из определений в each_symbol_section , мы можем определить расположение таблиц символов и сигнатур, и воссоздать файл Module.symvers из бинарника ядра.

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

Теги: Добавить метки

История и архитектурная организация

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

Краткий обзор истории Linux

Хотя Linux, по всей видимости, является самой популярной операционной системой с открытым исходным кодом, на самом деле ее история в сравнении с другими операционными системами относительно коротка. На заре компьютерной эры программисты разрабатывали свои программы для "голой" аппаратуры, используя языки, понятные для этой аппаратуры. В отсутствие операционной системы использовать всю большую и дорогую вычислительную машину в каждый конкретный момент времени могло только одно приложение (и один пользователь). Первые операционные системы были разработаны в 1950-е годы, чтобы облегчить жизнь разработчиков. В качестве примера можно назвать General Motors Operating System (GMOS), разработанную для IBM 701, и FORTRAN Monitor System (FMS), созданную North American Aviation для IBM 709.

В 1960-е годы в Массачусетском Технологическом институте (MIT) и в ряде компаний была разработана экспериментальная операционная система Multics (Multiplexed Information and Computing Service) для машины GE-645. Один из разработчиков этой ОС, компания AT&T, отошла от Multics и в 1970 году разработала свою собственную систему Unics. Вместе с этой ОС поставлялся язык C. При этом C был разработан и написан так, чтобы обеспечить переносимость разработки операционной системы.

Двадцать лет спустя Эндрю Танненбаум (Andrew Tanenbaum) создал микроядерную версию UNIX® под названием MINIX (minimal UNIX), которая могла работать на небольших персональных компьютерах. Эта операционная система с открытым исходным кодом вдохновила Линуса Торвальдса (Linus Torvalds) на разработку первой версии Linux в начале 1990-х (см. Рис. 1).

Рис. 1. Краткая история основных выпусков ядра Linux

Linux быстро превратился из инициативы энтузиаста-одиночки во всемирный проект, в котором участвуют тысячи разработчиков. Одним из важнейших решений в судьбе Linux стало принятие лицензии GNU General Public License (GPL). GPL защитила ядро Linux от коммерческой эксплуатации и одновременно открыла путь к использованию разработок сообщества пользователей проекта GNU, основанного Ричардом Столлменом (Richard Stallman), объемы кода которого значительно превосходят даже объем ядра Linux. Это позволило использовать в Linux такие полезные приложения, как комплекс компиляторов GNU Compiler Collection (GCC) и различные командные оболочки.

Введение в ядро Linux

Перейдем к общему обзору архитектуры операционной системы GNU/Linux. Операционную систему можно условно разделить на два уровня, как показано на Рис. 2.

Рис. 2. Фундаментальная архитектура операционной системы GNU/Linux

На верхнем уровне находится пользовательское пространство (пространство приложений). Здесь исполняются приложения пользователя. Под пользовательским пространством располагается пространство ядра. Здесь функционирует ядро Linux.

Имеется также библиотека GNU C (glibc). Она предоставляет интерфейс системных вызовов, который обеспечивает связь с ядром и дает механизм для перехода от приложения, работающего в пространстве пользователя, к ядру. Это важно, поскольку ядро и пользовательское приложение располагаются в разных защищенных адресных пространствах. При этом, в то время как каждый процесс в пространстве пользователя имеет свое собственное виртуальное адресное пространство, ядро занимает одно общее адресное пространство. Более подробную информацию можно найти в литературе, ссылки на которую приведены в разделе " ".

Ядро Linux можно, в свою очередь, разделить на три больших уровня. Наверху располагается интерфейс системных вызовов, который реализует базовые функции, например, чтение и запись. Ниже интерфейса системных вызовов располагается код ядра, точнее говоря, архитектурно-независимый код ядра. Этот код является общим для всех процессорных архитектур, поддерживаемых Linux. Еще ниже располагается архитектурно-зависимый код, образующий т.н. BSP (Board Support Package - пакет поддержки аппаратной платформы). Этот код зависит от процессора и платформы для конкретной архитектуры.

Свойства ядра Linux

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

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

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

Основные подсистемы ядра Linux

Давайте рассмотрим некоторые основные компоненты ядра Linux, следуя структуре, изображенной на рис. 3.

Рис. 3. Один из возможных взглядов на архитектуру ядра Linux

Интерфейс системных вызовов

SCI - это тонкий уровень, предоставляющий средства для вызова функций ядра из пространства пользователя. Как уже говорилось, этот интерфейс может быть архитектурно зависимым, даже в пределах одного процессорного семейства. SCI фактически представляет собой службу мультиплексирования и демультиплексирования вызова функций. Реализация SCI находится в./linux/kernel, а архитектурно-зависимая часть - в./linux/arch. Более подробные сведения об этом компоненте можно найти в разделе .

Управление процессами

Управление процессами сконцентрировано на исполнении процессов. В ядре эти процессы называются потоками (threads); они соответствуют отдельным виртуализованным объектам процессора (код потока, данные, стек, процессорные регистры). В пространстве пользователя обычно используется термин процесс , хотя в реализации Linux эти две концепции (процессы и потоки) не различают. Ядро предоставляет интерфейс программирования приложений (API) через SCI для создания нового процесса (порождения копии, запуска на исполнение, вызова функций Portable Operating System Interface ), остановки процесса (kill, exit), взаимодействия и синхронизации между процессами (сигналы или механизмы POSIX).

Еще одна задача управления процессами - совместное использование процессора активными потоками. В ядре реализован новаторский алгоритм планировщика, время работы которого не зависит от числа потоков, претендующих на ресурсы процессора. Название этого планировщика - O(1) - подчеркивает, что на диспетчеризацию одного потока затрачивается столько же времени, как и на множество потоков. Планировщик O(1) также поддерживает симметричные многопроцессорные конфигурации (SMP). Исходные коды системы управления процессами находятся в./linux/kernel, а коды архитектурно-зависимой части - в./linux/arch). Более подробную информацию об этом алгоритме см. в разделе .

Управление памятью

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

Однако управление памятью - это значительно больше, чем просто управление буферами по 4 КБ. Linux предоставляет абстракции над этими 4 КБ буферами, например, механизм распределения slab allocator. Этот механизм управления базируется на 4 КБ буферах, но затем размещает структуры внутри них, следя за тем, какие страницы полны, какие частично заполнены и какие пусты. Это позволяет динамически расширять и сокращать схему в зависимости от потребностей вышележащей системы.

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

Виртуальная файловая система

Еще один интересный аспект ядра Linux - виртуальная файловая система (VFS), которая предоставляет общую абстракцию интерфейса к файловым системам. VFS предоставляет уровень коммутации между SCI и файловыми системами, поддерживаемыми ядром (см. Рис. 4).

Рис. 4. VFS предоставляет коммутационную матрицу между пользователями и файловыми системами

На верхнем уровне VFS располагается единая API-абстракция таких функций, как открытие, закрытие, чтение и запись файлов. На нижнем уровне VFS находятся абстракции файловых систем, которые определяют, как реализуются функции верхнего уровня. Они представляют собой подключаемые модули для конкретных файловых систем (которых существует более 50). Исходные коды файловых систем находятся в./linux/fs.

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

Сетевой стек

Сетевой стек по своей конструкции имеет многоуровневую архитектуру, повторяющую структуру самих протоколов. Вы помните, что протокол Internet Protocol (IP) - это базовый протокол сетевого уровня, располагающийся ниже транспортного протокола Transmission Control Protocol, TCP). Выше TCP находится уровень сокетов, вызываемый через SCI.

Уровень сокетов представляет собой стандартный API к сетевой подсистеме. Он предоставляет пользовательский интерфейс к различным сетевым протоколам. Уровень сокетов реализует стандартизованный способ управления соединениями и передачи данных между конечными точками, от доступа к "чистым" кадрам данных и блокам данных протокола IP (PDU) и до протоколов TCP и User Datagram Protocol (UDP). Исходные коды сетевой подсистемы ядра находятся в каталоге./linux/net.

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

Подавляющее большинство исходного кода ядра Linux приходится на драйверы устройств, обеспечивающие возможность работы с конкретными аппаратными устройствами. В дереве исходных кодов Linux имеется подкаталог драйверов, в котором, в свою очередь, имеются подкаталоги для различных типов поддерживаемых устройств, таких как Bluetooth, I2C, последовательные порты и т.д. Исходные коды драйверов устройств находятся в./linux/drivers.

Архитектурно-зависимый код

Хотя основная часть Linux независима от архитектуры, на которой работает операционная система, в некоторых элементах для обеспечения нормальной работы и повышения эффективности необходимо учитывать архитектуру. В подкаталоге./linux/arch находится архитектурно-зависимая часть исходного кода ядра, разделенная на ряд подкаталогов, соответствующих конкретным архитектурам. Все эти каталоги в совокупности образуют BSP. В случае обычного настольного ПК используется каталог i386. Подкаталог для каждой архитектуры содержит ряд вложенных подкаталогов, относящихся к конкретным аспектам ядра, таким как загрузка, ядро, управление памятью и т.д. Исходные коды архитектурно-зависимой части находятся в./linux/arch.

Помимо переносимости и эффективности, ядро Linux обладает целым рядом других интересных функций, которые не были освещены в вышеприведенном рассмотрении.

Linux, как широко используемая на практике операционная система с открытым исходным кодом, является отличной испытательной площадкой для новых протоколов и их усовершенствований. Linux поддерживает большое количество сетевых протоколов, включая традиционный TCP/IP и его высокоскоростные расширения (для сетей быстрее Gigabit Ethernet и 10 GbE). Linux также поддерживает такие протоколы, как Stream Control Transmission Protocol (SCTP), реализующий множество дополнительных функций, отсутствующих в TCP (применяется в качестве альтернативного протокола транспортного уровня).

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

Еще одно недавнее усовершенствование Linux - возможность ее использования в качестве операционной системы для других операционных систем (т.н. гипервизора). Недавно в ядро было внесено усовершенствование, получившее название Kernel-based Virtual Machine (KVM, виртуальная машина на базе ядра). В результате этой модификации в пространстве пользователя был реализован новый интерфейс, позволяющий исполнять поверх ядра с поддержкой KVM другие операционные системы. В таком режиме можно не только исполнять другие экземпляры Linux, но и виртуализовать Microsoft® Windows®. Единственное ограничение состоит в том, что используемый процессор должен поддерживать новые инструкции виртуализации. Более подробную информацию см. в разделе .

Дальнейшее изучение

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

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

Установка утилит

Для настройки и сборки ядра Linux вам потребуется установить несколько пакетов, которые понадобятся для сборки и настройки ядра:  kernel-package , build-essential , libncurses-dev . Сделать это можно командой:

sudo apt-get install build-essential kernel-package libncurses-dev

Скачиваем исходный код ядра

Теперь нужно скачать исходный код ядра. Мы будем скачивать ядро для Ubuntu. Вы можете скачать определенную версию ядра, например, ту, которую вы в данный момент используете или же скачать самую последнюю версию. Для того, чтобы определить версию ядра Linux, которую вы используете, выполните команду uname с параметром -r:

Uname -r

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

$uname -r 2.6.27-11-generic

Имя пакета, содержащего исходные коды ядра обычно имеет следующий вид: linux-source-Версия. Например, для ядра версии 2.6.24: linux-source-2.6.24. Самая последняя версия ядра в репозиториях Ubuntu называется просто linux-source, без указания версии на конце. Для установки исходных кодов последней версии ядра Ubuntu Linux, выполните команду:

sudo apt-get install linux-source

Эта команда скачивает исходники ядра и размещает их в директории /usr/src . На момент написания заметки последняя версия ядра, которая была скачана — 2.6.27, ее мы и будем использовать. Если мы теперь перейдем в директорию /usr/src и выполним команду ls , то увидим, что среди файлов присутствует файл linux-source-2.6.27.tar.bz2. Это и есть исходные коды ядра Linux (ядра Ubuntu).

Распаковываем исходный код ядра

Перейдем в директорию /usr/src и разархивируем ядро. Для этого выполните следующие команды:

Cd /usr/src sudo tar xjf linux-source-2.6.27.tar.bz2 sudo ln -s linux-source-2.6.27 linux

Конфигурация ядра

Теперь перейдем к конфигурированию ядра. Чтобы не создавать конфигурацию с нуля, возьмем за основу конфигурацию ядра, которая в данный момент используется. Получить текущую конфигурацию можно выполнив команду make oldconfig . Выполните в терминале:

Cd /usr/src/linux sudo make oldconfig

В результате выполнения команды make oldconfig создастся файл.config , содержащий параметры конфигурации ядра.

Получить справку по всем параметрам make для ядра Linux вы можете, выполнив команду make help .

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

Sudo make menuconfig

Перед вами появится интерфейс, в котором вы можете включать или отключать определенные опции ядра:

Для примера я включу опцию «NTFS write support». Для этого, нажимая кнопку Вниз, найдите пункт «File systems» и нажмите Enter .

Вы окажетесь в меню настройки файловых систем. Найдите в этом списке пункт «DOS/FAT/NT Filesystems» и нажмите Enter .

Перейдите к пункту «NTFS write support» и нажмите Пробел, рядом с пунктом появится звездочка, означающая, что данная опция будет включена в ядро.

Теперь выберите «Exit» (нажав кнопку Вправо и затем Enter) и выйдите из утилиты. Перед выходом из утилиты выскочит сообщение с вопросом — сохранить проделанные изменения, выберите Yes.

Компиляция ядра

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

Sudo make-kpkg clean

Наконец, чтобы запустить компиляцию ядра, выполним команду:

Sudo make-kpkg --initrd --append-to-version=-mykernel kernel_image kernel_headers

Ключ -append-to-version используется, чтобы добавить к имени файла образа ядра, который мы получим после компиляции, строку -mykernel , чтобы было проще идентифицировать свое ядро. Вместо -mykernel вы можете использовать любой префикс.

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

Установка (инсталляция) ядра

После компиляции ядра вы получили на выходе два файла: linux-image-2.6.27.18-mykernel_2.6.27.18-mykernel-10.00.Custom_i386.deb, linux-headers-2.6.27.18-mykernel_2.6.27.18-mykernel-10.00.Custom_i386.deb. Мы воспользуемся командной dpkg -i , которая автоматически установит ядро и пропишет его в ваш загрузчик GRUB (в файл  /boot/grub/menu.lst). Отмечу, что ядро будет установлено, как ядро по умолчанию, поэтому если оно у вас не загрузится вам нужно будет загрузиться, используя ваше предыдущее ядро (оно должно быть в списке меню GRUB при загрузке компьютера) и вручную изменять файл menu.lst . Итак, для установки ядра выполните команды:

Dpkg -i linux-image-2.6.27.18-mykernel_2.6.27.18-mykernel-10.00.Custom_i386.deb dpkg -i linux-headers-2.6.27.18-mykernel_2.6.27.18-mykernel-10.00.Custom_i386.deb

Запуск системы с новым ядром

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

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

Суть вкратце

Всё началось в 1991-м, когда финский студент Линус Торвальдс выложил в открытый доступ коды ядра новой операционной системы Linux. Почему в открытый? Потому что поддерживал . Но это, вы, пожалуй, и так знаете (или легко узнаете). Мы же обратим внимание на моменты, которые требуют чёткой классификации.

Linux

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

GNU

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

GNU/Linux - это уже ОС, а не просто ядро. Вместо GNU может быть что-то другое, например, Dalvik в Android .

Драйверы

Техника развивается, растёт количество компьютерных «железок», оборудование эволюционирует. И каждому изделию для работы нужен драйвер. Так вот, некоторые драйверы прикручиваются прямо к ядру. Если они свободные (Свободное ПО), как GNU и Linux, то и коды непременно открыты.

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

Приложения

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

Естественно, открыты коды всех вариантов - для всех поддерживаемых операционных систем. Та же самая ситуация - с различными утилитами.

Кто это изготавливает

Ядро Linux совершенствуется группой энтузиастов. Иногда сам Линус Торвальдс принимает участие. Код ядра, запакованный в архив, можно скачать с kernel.org с целью последующей самостоятельной компиляции.

Драйверы, если они свободные, тоже нередко изготавливаются сообществами. Для принтера, сканера, видеокарты, адаптера Wi-Fi... В общем, много для чего.

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

Иногда производители «железки» сами открывают код под какой-нибудь подходящей лицензией, той же GPL или BSD. Такие события обычно вызывают неописуемую радость сторонников Open Source.

Как вы уже догадываетесь, пользовательские приложения тоже создаются либо сообществами, либо энтузиастами-одиночками. Однако и коммерческие конторы любят рекламировать себя, давая народонаселению часть своей продукции в виде Свободного ПО. Яркий пример: офисный пакет OpenOffice.org долгое время выпускался компанией Oracle.

Более того, некоторые фирмы даже целые дистрибутивы делают. Red Hat, SuSE, Xandros берут деньги за бинарные сборки, готовые к употреблению, но коды прятать не имеют право. То есть, эти коды, как бы их ни переработали, должны оставаться открытыми. Таково требование лицензии GPL.

Кто этим пользуется

Смотрит программист на софт и думает: «Хорошая штука, но можно сделать лучше!» Качает с сайта разработчика архив с кодом - и совершенствует. К нему присоединяется группа специалистов, пожелавших участвовать, - и рождается новый проект.

Так появляются «форки» (от английского «fork», что в данном случае переводится как «ответвление»). Новые программы на кодовой базе уже существующих.

К примеру, из хорошего аудиоплеера Amarok сделан ещё лучший - Clementine. А из пакета офисных приложений OpenOffice.org - LibreOffice, бурно развивающийся и весьма перспективный.

Так вот, по такому принципу клонируются целые операционные системы. Из исходных кодов платной Red Hat Enterprise Linux компилируется бесплатная ОС CentOS . Конечно, боссы компании Red Hat наверняка кусают локти от досады, но сделать ничего не могут, поскольку исходный код им не принадлежит.

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

Заключение

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

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

Предыдущие публикации:

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

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

Apt-cache search linux-source

Команда выведет список доступных пакетов:


Как видите, у меня есть только пакет с текущей версией и пакет с версией 3.5 (на самом деле текущая версия ядра тоже 3.5). Расширить список ядер, доступных таким образом, стоит подключить дополнительные репозитории. Получить ядро мы можем командой: sudo apt-get install linux-source

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

Cd /usr/src sudo tar -xjvf linux-source-3.5.0.tar.bz2 sudo ln -s linux-source-3.5.0 linux

Если же вам нужна самая свежая версия ядра, то её всегда можно скачать с сайта kernel.org. Стоит заметить, что на сайте выкладываются как стабильные версии ядер так и версии предназначенные для тестирования и доработки(обычно в их названии есть содержится аббревиатура «RC» - Release candidate). Если вы не желаете лишних проблем с системой, советую скачивать стабильную версию:

Сохраним архив с исходниками в папку /usr/src. Чтобы распаковать полученный архив вам может понадобиться установить дополнительные утилиты:

Sudo apt-get install xz-utils

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

Cd /usr/src sudo tar -xpJf linux-3.8.5.tar.xz sudo ln -s linux-3.8.5.tar.xz linux

Конфигурация и компиляция.
Вот мы и подошли к самому интересному. Прежде чем начать, установим несколько дополнительных пакетов:

sudo apt-get install build-essential kernel-package libncurses-dev

Будем создавать новую конфигурацию, на основе используемого системой в данный момент ядра:

Cd /usr/src/linux sudo make oldconfig

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

Sudo make menuconfig

В терминале запустится программа конфигурирования:

Здесь параметры конфигурации разделены на разделы, чтобы в них было удобнее ориентироваться. Как я уже говорил выше, мне нужно включить в ядро поддержку cryptoloop. Для этого нужно перейти в раздел «Device Drivers», а из него в подраздел «Block Devices»:

Находим параметр «Cryptoloop Support», рядом с ним стоит буква «М» что означает что поддержка шифрующих устройств будет добавлена как модуль ядра, который можно будет включить командой modprobe. Нам же надо включить поддержку данной технологии непосредственно в ядро, чтобы она поддерживалась всегда. Переводим фокус на параметр «Cryptoloop Support» и нажимаем на пробел. Буква «М» должна смениться символом "*" это означает что поддержка данной технологии будет «вшита» в ядро. Осторожно, пробел означает что технология вообще поддерживаться не будет.

Нажимаем клавишу «Tab» и нажимаем на кнопку «Exit» до тех пор пока не появится запрос на сохранение изменений:

Отвечаем «Yes». Мы успешно закончили конфигурирование!
Приступим к компиляции. Сначала удаляем файлы оставшиеся от предыдущих сборок, если вы запускаете сборку впервые выполнять эту команду не обязательно: sudo make-kpkg clean

Запускаем компиляцию:

Sudo make-kpkg -j4 --initrd --append-to-version=-mykernel kernel_image kernel_headers

J4 - флаг, указывает какое количество потоков использовать для компиляции. Позволит сильно ускорить компиляцию на многоядерных процессорах. Цифра 4 тут указывает на 4 потока. Ставьте столько потоков сколько ядер вашего процессора «видит» система.
-mykernel - префикс указывающий что ядро было собрано вручную, можете его изменить, фактически ни на что не влияет.

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

Установка ядра в систему

После завершения компиляции, в директории /usr/src должны появится два файла с расширением «deb» они являются установочными пакетами нашего нового ядра и установить их можно с помощью утилиты dpkg:

sudo dpkg -i linux-image-3.8.5-mykernel_3.8.5-mykernel-10.00.Custom_i386.deb
sudo dpkg -i linux-headers-3.8.5-mykernel_3.8.5-mykernel-10.00.Custom_i386.deb

Поздравляю! Ядро установлено, теперь система будет загружаться с этим ядром по умолчанию, но если у вас возникнут проблемы с новым ядром вы всегда можете загрузится со старым выбрав его на экране загрузки - Grub. На этом я завершаю сегодняшнюю статью и желаю успехов, вам, уважаемые читатели!