• Собираем собственную ОС на базе Linux. Как создать свою собственную операционную систему с нуля

    Илья Александров

    Создаём собственную ОС на базе Linux

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

    За долгие годы работы с Linux мною было использовано огромное количество различных дистрибутивов: Mandriva, Fedora, SlackWare, Debian, Ubuntu и многие другие. Какой-то проект нравился больше, какой-то – меньше. Но во всех дистрибутивах неминуемо приходилось сталкиваться с серьезными недостатками, которые сильно затрудняли работу. Один слишком требователен к ресурсам, в другом нет поддержки всего нужного оборудования, в третьем не хватает различного ПО. Вот тогда я вспомнил известную восточную мудрость: если нужно что-то сделать хорошо, сделай это сам.

    Linux from Scratch

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

    Стремление талантливого программиста вылилось в проект Linux from Scratch (www.linuxfromscratch.org), сокращенно – LFS. Этот проект, позволяет сконструировать «с нуля», из исходных кодов, свою операционною систему на базе Linux. Компиляция LFS проходит на компьютере с уже установленной Linux-системой, впрочем, подойдет и «продвинутый» Live-CD, например, Knoppix .

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

    Как известно, Линус Торвальдс разрабатывал свою операционную систему под девизом «Just for fun!» – то есть только ради удовольствия. Нужно признать, что LFS действительно не часто можно встретить на серверах, используют эту систему, как правило, компьютерные энтузиасты. Установка и работа с Linux from Scratch поможет вам разобраться во взаимосвязи компонентов ОС, что пригодится при собственных разработках Linux-дистрибутива, причем не только на базе LFS. Поэтому LFS во многом рассчитан на тех людей, для которых процесс сборки собственного дистрибутива увлекателен и интересен – а таких людей, поверьте, немало.

    Итак, если вы готовы потратить на конструирование системы целый день (а то и больше), то рекомендую скачать с сайта (2) LFS-packages-6.0, LFS-book, и продолжить читать эту статью.

    Разбиение диска и создание дерева каталогов

    Для лучшего понимания материала опишем весь ход процесса в общих чертах (см. рис. 1).

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

    На протяжении всего процесса ваш главный помощник – документация из пакета LFS-book, русский перевод которой можно взять тут: http://multilinux.sakh.com/download/lfsbook.tar.bz2 . В книге подробно описан каждый шаг создания ОС, поэтому обязательно обращайтесь к этому руководству в случае возникновения проблем (данная статья не призвана заменить такую обширную документацию).

    Создаем новый раздел – в моем случае это /dev/hda5, так как раздел /dev/hda1 уже занят установленным на жесткий диск Linux Slackware. Рекомендуется предварительно сделать бэкап системы, дабы можно было ее восстановить в случае повреждения, хотя вероятность подобного близка к нулю. И тут, думаю, все понятно: выделяем нужное количество (достаточно 23 Гб) под корневой каталог, пространство, равное удвоенному объему ОЗУ – под swap-раздел, по желанию можно создать отдельные разделы для домашнего каталога (/home) и для /boot. Впрочем, излюбленный многими вариант разбиения – отвести под корневой каталог все доступное пространство минус swap, и последующее создание собственно swap – также вполне допустимо при сборке LFS. На компьютере автора и Linux Slackware, являющийся родительской ОС, и LFS, используют один жесткий диск, впрочем, установить LFS на другой винчестер тоже труда не составит.

    Файловую систему выбирайте на ваше усмотрение: и с Ext3, и с ReiserFS никаких проблем под LFS не было. А вот поклонников XFS придется огорчить – попытки заставить Linux From Scratch работать с этой ФС не увенчались успехом.

    Теперь монтируем раздел, отведенный под новую ОС:

    $ mount /dev/hda5 /mnt/mylin

    Для удобства определим переменную MYLIN:

    $ export MYLIN=/mnt/mylin

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

    $ useradd mylin

    $ chown –R mylin $MYLIN

    Нужно создать дерево каталогов в корне нового раздела:

    $ cd $MYLIN

    $ mkdir –p bin boot dev etc home lib mnt opt root sbin usr/{X11R6,local} var

    В каталогах usr, usr/X11R6, usr/local создаем необходимую структуру: подкаталоги bin, etc, include, lib, sbin, share, src.

    Затем то же самое проделаем для каталогов /var и /opt будущей системы:

    $ mkdir var/{cache,lib,local,lock,log,opt,run,spool}

    $ mkdir opt/{bin,doc,include,info,lib,man}

    Не будем забывать, что существуют более глубокие иерархии, например, /usr/share/man/man1. Но объем статьи не позволяет привести здесь всю информацию о структуре файлового дерева, поэтому нужно либо воспользоваться документом Filesystem Hierarhy Standart (можно найти по адресу: http://linux-ve.net/MyLDP/file-sys/fhs-2.2-rus), либо внимательно изучить структуру уже установленной у вас ОС семейства Linux. После подготовки жесткого диска приступаем к статической сборке.

    Статическая сборка

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

    Но когда мы посредством команды chroot установим корневой каталог для вновь собираемой системы, библиотеки «родительской», установленной системы, находящиеся в /lib, /usr/lib, и прочих, станут уже недоступны, поэтому динамически скомпилированные программы работать откажутся, вдобавок совместимость версий никем не гарантирована.

    Чтобы избежать этого, все необходимое программное обеспечение для нашей будущей системы мы для начала соберем статически. Начнем, пожалуй, с командного интерпретатора bash. (Поклонники ZSH или TCSH могут установить любимые интерпретаторы после установки системы, но на этапе сборки их использование не предусмотрено автором LFS). Следует проверить, есть ли у вас файл /usr/lib/libcurses.a и если его нет – установите пакет nсursesdev. Все пакеты надо собирать с флагами статической сборки: «--enable-static-link», «--disable-shared» или «--static». Какой именно подходит в каждом конкретном случае, можно узнать из документации к конкретному пакету или из вывода конфигурационного сценария, запущенного с параметром «--help».

    $ ./configure –-help

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

    $ mkdir $MYLIN/stat

    При сборке и установке пакетов не забываем добавлять параметр «--prefix=$MYLIN/stat» для перемещения файлов именно в этот каталог. И, наконец, ставим bash:

    $ ./configure –-enable-static-link --prefix=$MYLIN/stat

    $ make

    $ make install

    По такой же схеме собираем остальные необходимые пакеты: binutils, bzip2, textutils, texinfo, tar, sh-utils, gcc, grep, gzip, gawk, diffutils, fileutils, make, patch, sed, и, собственно, linux-kernel.

    Да, при компиляции ядра не забываем, что для старых версий ядер (2.2.x-2.4.x) нужно использовать gcc 2.95, а для текущей версии 2.6.x рекомендуется применить gcc 3.x, дабы не возникло проблем.

    Не забываем заглядывать в соответствующие разделы LFS-book, там сказано об этом и многих других нюансах. В целом же компиляция ядра в LFS не отличается от подобной процедуры, проводимой при использовании установленного на HDD дистрибутива. Разархивируем исходники ядра в $MYLIN/usr/src/linux-2.6.xx, после чего конфигурируем, запуская:

    $ make menuconfig

    Процесс настройки параметров ядра многократно описан в Интернете (6), вряд ли есть необходимость останавливаться на этом подробнее. Далее даем следующие команды в папке с исходными текстами Linux-kernel:

    $ make bzImage

    $ make modules

    Все, по адресу $MYLIN/usr/src/linux-2.6.xx/arch/i386/boot/bzImage находится новое ядро.

    Далее создаем файлы $MYLIN/etc/passwd и $MYLIN/etc/group. В первом прописываем пока единственного пользователя – root с любым паролем, а во втором группы пользователей (для начала одной группы root тоже будет достаточно).

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

    Динамическая сборка

    Теперь нам нужно сменить корневой каталог на /mnt/mylin, где мы будем пользоваться только статически собранными утилитами – к помощи инструментов из «родительской» ОС мы уже прибегать не сможем. Даем команду в консоли:

    $ chroot $MYLIN/usr/bin/env –i

    >HOME=/root TERM=$TERM PS1=’u:w$’

    >PATH=/bin: /usr/bin: /sbin: /usr/sbin: /stat/sbin

    >/stat/bin/bash --login

    Этой командой мы указали пути к исполняемым файлам, тип терминала, интерпретатор и вид приглашения командной строки.

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

    $ mount proc /proc -t proc

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

    При сборке мы указывали параметр «--prefix=$MYLIN/stat», поэтому при смене корня все статически собранные пакеты окажутся в каталоге /stat раздела новой ОС.

    Итак, распаковываем архив glibc-2.x.x.tar.gz (например, в директорию /usr/src/) и переходим в каталог glibclinuxthreads. Придется немного подправить исходный код ввиду того, что на данном этапе в системе невозможна идентификация пользователя по имени (как раз из-за отсутствия glibc и других библиотек), и того, что для установки glibc нужен интерпретатор Perl, которого у нас нет.

    Заменяем имя пользователя root в файле login/Makefile на его uid, то есть 0, а переменную $PERL в файле malloc/Makefile следует заменить на путь к интерпретатору – /usr/bin/perl – и при конфигурировании он просто будет проигнорирован.

    $ /usr/src/glibc-2.x.x/configure --prefix=/usr --enable-add-ons --libexecdir=/usr/bin &&

    & make

    & make install

    $ make localedata/install-locales

    $ /stat/bash --login

    Если вы все сделали правильно, glibc скомпилируется, в строке приглашения наконец-то появится «root», и можно будет динамически перекомпилировать все программы.

    Завершим установку ядра:

    $ make modules_install

    $ make install

    Чтобы переместить новое ядро в каталог /boot, выполняем еще одну команду:

    $ make unstall

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

    Таблица 1. Необходимый набор пакетов для сборки

    autoconf

    grep

    perl

    automake

    groff

    bash

    gzip

    procinfo

    bin86

    procps

    binutils

    less

    psmisc

    bzip2

    reiserfs-progs

    diffutils

    libtool

    e2fsprogs

    lilo

    sh-utils

    shadow

    file

    make

    sysklogd

    fileutils

    makedev

    sysvinit

    findutils

    man-pages

    flex

    modutils

    texinfo

    gawk

    ncurses

    textutils

    netkitbase

    util-linux

    bison

    net-tools

    gettext

    patch

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

    $ rm -rf /stat

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

    Начальное конфигурирование системы

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

    Для установки системного времени создадим файл /etc/sysconfig/clock, содержащий всего одну строку:

    UTC=0

    Теперь часы компьютера будут отображать время вашего часового пояса – при условии, что значение времени в BIOS установлено верно.

    Дадим компьютеру имя:

    echo "HOSTNAME=my_linux" > /etc/sysconfig/network

    Теперь разделы, которые система должна монтировать при загрузке, укажем в /etc/fstab:

    # filesystem mount-point fs-type options dump fsck-order

    /dev/hda5 / ext3 defaults 1 1

    /dev/hda3 swap swap pri=1 0 0

    proc /proc proc defaults 0 0

    Вместо /dev/hda3 и /dev/hda5 напишите ваши разделы (корневой и swap), дополните файл при необходимости точками монтирования других разделов жесткого диска и CD-ROM.

    Теперь сделаем нашу систему загружаемой.

    Если помимо lFS вы пользуетесь другими дистрибутивами Linux, то сейчас нужно войти в старую систему – для этого выполняем команду:

    $ exit

    Уже в родительской ОС в файл /etc/lilo.conf добавляем следующее:

    # LFS

    image=/boot/bzImage

    Label=lfs

    Root=

    Read-only

    Понятно, что «/boot/bzImage» – это путь к скомпилированному вами ядру системы, а «partition» – раздел диска, где находится корневой каталог.

    Если же вы не планируете пользоваться другими операционными системами и дистрибутивами Linux, то сразу переходите к настройке LILO в LFS.

    В этом случае lilo.conf будет выглядеть примерно так:

    boot=/dev/hda

    Delay=40

    Compact

    Vga=normal

    Root=/dev/hda1

    Read-only

    Image=/boot/zImage-2.6.12

    Label=Linux

    Сделайте необходимые изменения в зависимости от вашей конфигурации. Обновляем загрузчик командой:

    $ /sbin/lilo –v

    И, если все предыдущие этапы были выполнены правильно, мы окажемся в новой системе. Однако долгий этап «тонкой» настройки (отдельное внимание стоит уделить безопасности новой системы, ибо LFS по умолчанию выглядит довольно-таки незащищенным, как и всякая вновь установленная ОС) еще впереди. Зато собственноручно собранная версия Linux у вас уже есть.

    Постскриптум

    Герард Бикменс – не единственный, кому пришло в голову создать собственный Linux. Другой проект – BYOLinux, руководителем которого являлся Джонатан Торп (Jonatan Thorpe), на сегодняшний день свое развитие прекратил, хотя написанная имдокументация сохраняет актуальность и сейчас, но она не так детальна, как LFS-book и не переведена на русский. Главное отличие метода Джона в том, что библиотека glibc переносится из родительской системы в дочернюю без перекомпиляции, это не столь эффективно, но позволяет избежать многих проблем при сборке. Желание почувствовать себя конструктором ОС испытывают и некоторые пользователи FreeBSD.

    Теперь такое вполне возможно – по адресу http://ezine.daemonnews.org/200302/fbsdscratch.html находится статья о сборке FreeBSD из исходников целиком – от distributions до портов, причем методом не похожим на обычный «rebuild» системы, но схожим с методом Герарда Бикменса. Что ж, теперь и у вас есть личная, уникальная система, созданная на базе Linux. В случае возникновения проблем ищите их решение в LFS-book, там все подробно описано. Также рекомендую с портала http://www.tldp.org скачать руководство Linux Network Administrator’s Guide, оно хоть и не относится непосредственно к LFS, но пригодится на этапе настройки системы. Не стоит забывать, что с каждой программой поставляются также различные man и info pages, также призванные облегчить жизнь линуксоида.

    1. LFS-book на русском – http://multilinux.sakh.com/lfs .
    2. Официальный портал проекта LFS – http://www.linuxfromscratch.org .
    3. Портал ByoLinux – http://www.byolinux.org .
    4. Cтатья о FreeBSD from scratch – http://ezine.daemonnews.org/200302/fbsdscratch.html .
    5. Статья о компиляции ядра Linux – http://vikos.lrn.ru/MyLDP/kernel/kompil-2-6.html .
    6. Байрак А. Обзор Knoppix 3.7 Russian Edition. – Журнал «Системный администратор», №3, март 2005 г. – 4-6 с. ().

    Книга «Операционная система с 0 до 1» опубликована на GitHub и имеет более 2 000 звездочек и 100 форков. Как понятно из названия, прочитав её, вы сможете создать свою собственную операционную систему - и, пожалуй, мало что в мире программистов может быть круче.

    Благодаря этой книге вы научитесь следующему:

    • Узнаете, как создать операционную систему на основе технической документации железа. В реальном мире это так и работает, вы не сможете использовать Google для быстрых ответов.
    • Поймёте, как компьютерные компоненты взаимодействуют друг с другом, от софта к железу.
    • Научитесь писать код самостоятельно. Слепое копирование кода не есть обучение, вы действительно научитесь решать проблемы. Кстати, слепое копирование еще и опасно.
    • Освоите всем привычные инструменты для низкоуровневой разработки.
    • Познакомитесь с языком ассемблера.
    • Выясните, из чего состоят программы и как операционная система запускает их. Небольшой обзор этой темы для любознательных мы давали в .
    • Разберётесь, как проводить отладку программы прямо на железе с GDB и QEMU.
    • Язык программирования C. Быстро освоить его можно, следуя .
    • Базовые знания Linux. Достаточно изучить на нашем сайте.
    • Базовые знания в физике: атомы, электроны, протоны, нейтроны, напряжение.
    • Закон Ома о соотношении напряжения, силы тока и сопротивления.

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

    Оригинал: "Roll your own toy UNIX-clone OS"
    Автор: James Molloy
    Дата публикации: 2008
    Перевод: Н.Ромоданов
    Дата перевода: январь 2012 г.

    Этот набор руководств предназначен для того, чтобы подробно показать вам, как запрограммировать простую UNIX-подобную операционную систему для архитектуры x86. В этих руководствах в качестве языка программирования выбран язык C, который дополняется языком ассемблера там, где это требуется. Цель руководств - рассказать вам о разработке и реализации решений, используемых при создании операционной системы ОС, которую мы создаем, монолитную по своей структуре (драйверы загружаются в режиме модулей ядра, а не в пользовательском режиме так, как происходит с программами), поскольку такое решение более простое.

    Этот набор руководств очень практический по своей природе. В каждом разделе приводятся теоретические сведения, но большая часть руководства касается вопросов реализации на практике рассмотренных абстрактных идей и механизмов. Важно отметить, что ядро реализовано как учебное. Я знаю, что используемые алгоритмы не являются ни самыми эффективными по использованию пространства, ни оптимальными. Они, как правило, выбирались благодаря своей простоте и легкости понимания. Целью этого является дать вам правильный настрой и предоставить базис, на котором можно работать. Данное ядро является расширяемым и можно легко подключить лучшие алгоритмы. Если у вас возникнут проблемы, касающиеся теории, то есть много сайтов, на которых вам помогут с ней разобраться. Большинство вопросов, обсуждаемых на форуме OSDev, касаются реализации ("My gets function doesn"t work! help!" / "Моя функция не работает! Помогите!") и для многих вопрос по теории похож на глоток свежего воздуха. Ссылки можно найти в конце настоящего введения.

    Предварительная подготовка

    Чтобы скомпилировать и запустить код с примерами, как я предполагаю, потребуется только GCC, ld, NASM и GNU Make. NASM является ассемблером для x86 с открытым исходным кодом и многие разработчики ОС для платформы x86 выбирают именно его.

    Однако нет никакого смысла просто выполнять компиляцию и запускать примеры, если нет их понимания. Вы должны понять, что кодируется, и для этого вы должны очень хорошо знать язык C, особенно то, что касается указателей. Вы также должны немного понимать ассемблер (в этих руководствах используется синтаксис Intel), в том числе то, для чего используется регистр EBP.

    Ресурсы

    Есть много ресурсов, если вы знаете, как их искать . В частности, вам будут полезны следующие ссылки:

    • RTFM! Руководства от intel - это находка.
    • Wiki страницы и форум сайта osdev.org.
    • На сайте Osdever.net есть много хороших руководств и статей и, в частности, Bran"s kernel development tutorials (Руководство по разработке ядра), на более раннем коде которого основывается настоящее руководство. Я сам использовал эти руководства для того, чтобы начать работу, и код в них был настолько хорош, что я не менял его в течение ряда лет.
    • Если вы не новичок, то ответы на многие вопросы вы можете получить в группе

    Если подходить по существу...

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

    Ещё ОС, ежели имеется долговременная память, должна предоставлять доступ к ней: то есть предоставлять все функции для работы с файловой системой. Это минимум.

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

    Для РС надо на асме писать бутлоадер, который будет вызываться BIOS и кой должен, не превышая четырёх с копейками сотен байт, что-то сделать и запустить основную ОС - передать управление основному коду, который в ближайшей же перспективе можно писать уже и на С.

    Для ARM надо на асме делать таблицу прерываний (сброс, ошибки разные, прерывания IRQ, FIQ и пр.) и передачу управления в основной код. Хотя, во многих средах разработки такой код для почти любого контроллера имеется.

    То есть, необходимо для этого:

    1. Знать ассемблер целевой платформы.
    2. Знать архитектуру процессора и всякие служебные команды и регистры, чтобы настроить его для работы в нужном режиме. В РС это переход в защищённый режим, например, или в 64битный режим... В ARM - настройка тактирования ядра и периферии.
    3. Знать, как именно будет запускаться ОС, куда и как нужно пихать свой код.
    4. Знать язык С - большой код на асме написать затруднительно без опыта, поддерживать его будет ещё труднее. Посему надо ядро писать на С.
    5. Знать принципы работы ОС. Ну, книжек на русском языке по этой теме много всяких, правда, не знаю, все ли они хорошие.
    6. Иметь много-много терпения и усидчивости. Ошибки будут и их надо будет искать и исправлять. А ещё надо будет очень много читать.
    7. Иметь много-много времени.

    Далее. Допустим, вы что-то написали. Надо это дело тестировать. Либо надо устройство физическое, на коем будут идти эксперименты (отладочная плата, второй компьютер), либо эмулятор его. Второе обычно использовать и проще, и быстрее. Для PC, например, VMWare.

    Статей по этой теме в интернете тоже достаточно, если хорошо поискать. А также есть множество примеров готовых ОС с исходниками.

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

    Рано или поздно каждый пользователь Линукса задумывается над созданием собственного дистрибутива. Некоторые аргументируют это тем, что можно «все настроить под себя». Другие сетуют на то, что среди уже представленных дистрибутивов в Ветке нет идеального. А у них, якобы, есть суперконцептуальные идеи для собственной системы. Зачем я всю эту психологию затеял? Для того, чтобы сразу перекрыть кислород играющимся с Линуксом новичкам, которым делать нечего. Если уж задумались над созданием ОС, думайте до конца. Итак,

    Я хочу создать ОС на базе Linux.
    Сразу предупреждаю: был бы XVIII век, всех тех, кто для основы своей будущей системы выбирает другой развитый дистрибутив (и, не дай Бог, популярный...) ждала бы виселица. Пост именно про создание системы с нуля, а значит, всякие Slax и Linux Mint мы трогать не будем.

    Шаг 1. Выбор носителя
    Вариантов немного: либо ваша ОС запускается с LiveCD, либо с жесткого диска, либо с флеш-устройства. Сразу оговорюсь: не скажу в посте ни слова про жесткий диск, потому что гораздо удобнее создавать гибкий дистрибутив из серии «все свое ношу с собой», либо залоченный дистрибутив на оптическом диске. Если вы научитесь создавать LiveCD или LiveUSB систему, с установкой на жесткий диск проблем не будет.

    На всякий случай, приготовьте чистую флешку, CD-диск, и установите, наконец, Virtualbox.

    Шаг 2. Компиляция ядра
    По поводу выхода третьего ядра Linux, этот шаг воодушевляет на дальнейшие разработки… Итак, нам нужны исходники ядра. Каждый пользователь знает, что их можно достать на сайте kernel.org. Ни в коем случае, слышите?, никогда не прикручивайте к своей системе постороннее ядро, скомпилированное не вами!

    Поскольку лень моя зашкаливала, я создал папку /linuxkernel и распаковал туда архив с исходниками. Залогинившись под рутом, я сделал следующее:

    cd /linuxkernel
    make menuconfig

    В принципе, ядро можно конфигурировать тремя способами: make config (диалоговая конфигурация), make menuconfig (псевдографическая конфигурация через ncurses), а также make xconfig (графическая конфигурация). Суть в том, что make config испортит вам настроение надолго, т.к. он задаст все возможные вопросы по всем аспектам всех тем. Проблема с make xconfig встречается не у всех, но вот у меня встречалась и встречается. Если приспичило сделать через X, разбирайтесь сами. Оптимальный вариант - make menuconfig. Эта штука откроет вам псевдографический интерфейс, через который вы сможете настроить ядро на свой лад. Штука требует библиотеки ncurses, которая легко устанавливается.

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

    Однако, направить вас все же придется. Перейдите по адресу File Systems ---> и поставьте необходимые звездочки. Буква M означает, что поддержка того или иного драйвера осуществляется с помощью подключения к ядру внешнего модуля (ненавижу их!). Нам понадобится также поддержка isofs, для чтения дисков. File Systems ---> CD-ROM/DVD Filesystems ---> ISO 9660 CDROM file system support. Можно еще поддержать древнедосовские системы.

    Чмошные разработчики Mandriva забыли разрешить File systems ---> DOS/FAT/NT Filesystems ---> NTFS write support, и на одном из их дистрибутивов я мучился с доступом к древневиндовскому разделу.

    Посмотрите Processor type and features ---> Processor family, мне порекомендовали выбрать Pentium-MMX.

    Еще поройтесь в Device Drivers, полезно. Можете шутки ради понавыбирать там все и скомпилировать ядро весом > 50 Мб.

    Далее. Ядро после загрузки себя должно загружать, собственно, систему. Либо из скомпилированных в себе файлов (используются во встраиваемых системах), либо из CPIO архива, сжатого чем-нибудь, либо из Initrd. Здесь вам не DOS, здесь не получится сразу сослаться на какой-нибудь init"овый файл в корневом каталоге диска или флешки. На самом деле получится, не слушайте дядю Анникса! Неправильно это, хоть в Интернете по этому поводу уже нехилая полемика ведется. В своей системе мы будем использовать initrd, т.к. это удобно, и не вызовет нецензурных выражений от сторонних разработчиков, в отличие от CPIO архива.

    Ах, да, скомпилируйте ядро командой

    Если у вас x86, найдете его по адресу /linuxkernel/arch/x86/boot/bzImage.

    Для суровых челябинских программистов можно использовать Кросс-компайлинг…

    Создание Ramdisk.

    Теперь нам нужен initrd с установленной там простейшей оболочкой. Мы будем использовать busybox, потому что эта няша может все. Способ мы украдем у Роберто де Лео, создателя Movix (я бы даже уважать его начал, если бы не запредельная любовь к Perl):

    dd if=/dev/zero of=/dev/ram0 bs=1k count=5000 - Создаем Ramdisk в оперативной памяти нашего компьютера.
    mke2fs -m0 /dev/ram0 5000 - Форматируем Ramdisk в системе Ext2
    mkdir /distro - Создаем папку
    mount /dev/ram0 /distro - Монтируем в папку /distro

    Все, теперь у нас есть Ramdisk, емкостью в 5 Мб. Можно и больше, только не нужно. В отличие от Томаса Матеджисека, я не собираюсь пичкать initrd модулями в Squashfs, сжатыми LZMA. Все, что необходимо, будет скомпилировано вместе с ядром. Да, это не очень логично и правильно, но мороки в сто раз меньше. А специально для тех, кто осуждает такой подход, можно разрешить опцию модульности в ядре: Enable loadable module support.

    В нашем Ramdisk"е, смонтированном в /distro, есть такая папка, lost+found. Это потому, что мы отформатировали его в ext2. Ни в коем случае нельзя ее удалять, хоть она здесь вряд ли поможет, образ-то фиксированный. Нам бы busybox сначала поставить…

    Установка Busybox
    Вот почему у таких классных проектов такие отстойные сайты? Хотя… это уже не суть важно, если исходники скачаны и успешно распакованы в папку /busybox.

    Сконфигурировать busybox можно так же:

    cd /busybox
    make menuconfig

    Если вы еще не поняли, что это, объясню. Busybox заменяет тонны UNIX приложений, хранящихся в папках /bin, /sbin, /usr/bin, /usr/sbin. Вместо этого, создается только одно приложение: /bin/busybox, а на него создается куча ссылок в указанных выше папках. Установим busybox следующей командой:

    make CONFIG_PREFIX=/distro install

    Еще Busybox создаст файлы /sbin/init и зачем-то /linuxrc, чтобы ваша система корректно запустилась. Но не все необходимые папки были созданы. Так что завершаем все руками и создаем:

    /distro/etc
    /distro/lib
    /distro/dev
    /distro/mnt
    distro/proc
    /distro/root
    /distro/tmp
    /distro/root

    Если что забыл - вспомните, т.к. директории эти забыть сложно.

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

    ldd /distro/bin/busybox

    Программа покажет нам библиотеки, требуемые для нашей оболочки. Сразу говорю: linux gate создается ядром и скопирован быть не может.

    При копировании библиотек можно отсекать отладочную информацию (так Роберто советует):

    objcopy --strip-debug откуда куда

    Делаем из Линукса Линукс

    Надо создать несколько системных текстовых файлов:

    Нам нужен /etc/inittab. Удивлю вас: в начале жизни система даже не знает, что такое Root. У нас даже пользователь безымянный, но вот файл общесистемных низкоуровневых фич (ОНФ) должен присутствовать. Пилотное содержание файла следующее:

    # Самый первый запускаемый файл, /sbin/init потом.
    ::sysinit:/etc/rc.d/rc.S

    # Запустить оболочку в консоли.
    ::respawn:-/bin/sh

    # Команды, выполняемые перед выключением и перезагрузкой.
    ::shutdown:/sbin/swapoff -a >/dev/null 2>&1
    ::shutdown:/bin/umount -a -r >/dev/null 2>&1

    Следующий файл - /etc/fstab. Это таблица, в которой описано, что и куда монтировать при загрузке. Вещь бесполезная! Нам нужно обязательно смонтировать proc, иначе вообще ничего работать не будет, так что в файле пишем:

    none /proc proc defaults 0 0

    Для mount нужен также файл /etc/mtab. Создайте его и оставьте пустым.

    Но mount сделает все необходимое только тогда, когда мы явно его об этом попросим. А просить мы будем в том самом первозагрузочном файле /etc/rc.d/rc.S (rc.d - папка). Вежливо попросим:

    /bin/mount -av -t nonfs

    Еще нам необходим файл профиля (b)(a)sh, тут вообще раздолье для фантазии. Создаем файл /etc/profile и заполняем следующим:

    PATH="$PATH:/bin:/sbin:/usr/bin:/usr/sbin:"
    LESS=-MM
    TERM=linux
    HOME=/root
    PS1="> "
    PS2="> "
    ignoreeof=10
    export PATH DISPLAY LESS TERM PS1 PS2 HOME ignoreeof

    Понадобится также файл /etc/shell, в котором указано, что есть оболочка:

    /bin/sh
    /bin/ash
    /bin/bash

    Вот собственно и все. Можно записывать наш Ramdisk в файл.

    mkdir /os - папка для "готового".
    umount /dev/ram0 - размонтируем кусочек оперативной памяти.
    dd if=/dev/ram0 of=/os/initrd bs=1k count=5000 - создаем файл.
    gzip /os/initrd - сжимаем файл initrd

    Создание загрузочной флешки

    «Финишная прямая» нашей маленькой разработки. Берем флешку, вставляем, форматируем в vfat (можно и в ext, но не забывайте, что еще не все пользователи Windows застрелились).

    На флешке создаем папку boot, в ней папки initrd и kernel.

    Из папки /os копируем сжатый Ramdisk в папку boot/initrd на флешке, называем «main.gz». Из папки с исходниками ядра копируем bzImage в папку boot/kernel на флешке, называем «main.lk». Достаем файлы загрузчика Syslinux (в Интернете, либо из другого дистрибутива: тут не принципиально), а именно syslinux.bin, syslinux.boot, syslinux.cfg. Копируем их в корневой каталог нашей флешки. В файле syslinux.cfg пишем что-то подобное:

    default mm
    prompt 1
    timeout 100
    label mm
    kernel /boot/kernel/main.lk

    label mc
    kernel /boot/kernel/main.lk

    label cm
    kernel /boot/kernel/custom.lk
    append initrd=/boot/initrd/main.gz load_ramdisk=1 ramdisk_size=5000 rw root=/dev/ram0
    label cc
    kernel /boot/kernel/custom.lk
    append initrd=/boot/initrd/custom.gz load_ramdisk=1 ramdisk_size=5000 rw root=/dev/ram0
    label hd
    localboot 0x80

    Тем самым мы поддержали кастомные initrd и ядро, которые, эксперимента ради, можно подключить к нашему дистрибутиву.

    Узнаем, каким девайсом в системе является наша флешка (можно запустить mount без параметров и посмотреть). Это либо /dev/sdb1, либо /dev/sdc1, либо /dev/sdd1. Стоит отмонтировать флешку перед началом установки.

    Устанавливаем syslinux (если пакета в системе нет, apt-get install syslinux):

    syslinux -d путь_к_устройству

    В корневом каталоге флешки должен появиться файл ldlinux.sys. Если он есть, значит syslinux.bin, syslinux.boot больше не нужны.

    Как настроить BIOS на загрузку из флешки, я вам рассказывать не буду - это легко. Скажу только, что очень удобно создать папку /boot/initrd/init, в которую можно будет смонтировать /boot/initrd/main, для последующей работы с ним. Только не забудьте разжимать и сжимать его gzip"ом.

    Ну вот и все.

    Как-бы я только что рассказал вам, как создать с нуля систему на Linux. Легко, не правда ли? Далее вы можете редактировать скрипт /sbin/init, ведь у вас еще много работы! Вы должны будете написать скрипт для монтирования флешки, который делает chroot в корневой каталог. В противном случае, вы вынуждены будете работать с ReadOnly разделом, величиной в 5 Мб. Но это уже совсем другая история.