Введение

Я попытался повторить, насколько это возможно, действия Линуса Торвальдса по компиляции и запуску самой первой версии ядра Linux 0.01. Причины, побудившие Линуса начать разработка ядра, хорошо описаны в книге «Ради удовольствия: Рассказ нечаянного революционера» (далее J4F) и во множестве других источниках и мы не будем их касаться. А рассмотрим техническую сторону компиляции и запуску ядра Linux.

Непосредственно процесс сборки ядра по-unix'овски очень прост: достаточно выполнить команду make, и на выходе получаете готовый бинарный файл, который надо записать на дискету и загрузиться с неё. Но чтобы сборка прошла успешно, надо провести большую подготовку. Вот этим мы и займёмся. Я составил для вас очень подробное пошаговое руководство.

Сначала в эмуляторе 86Box создадим пустую виртуальную машину с характеристиками, близкими к компьютеру Линуса в то время, установим оригинальную версию операционной системы Minix 1.5.10, применим патчи «царя и бога Minix-386» (c) Брюса Эванса, поставим порт компилятора gcc версии 1.37.1 для Minix-386 от Алана Блэка (Alan W Black) и Ричарда Тобина (Richard Tobin), и в самом конце соберём и запустим ядро Linux с bash'ем внутри.

После каждого этапа я сохранял состояние виртуальной машины, жёсткого диска и образы дискет, которые подвергались изменению. Можете пройти все шаги самостоятельно или распаковать любой из архивов и продолжить выполнение инструкции с желаемого момента. Все дистрибутивы, скриншоты, конфигурации, это руководство, архивы с резервными копиями по каждому этапу и даже бинарный AppImage 86box (для Linux x86_64) можно найти в репозитории.

Приступим.


Оглавление


Предположительные характеристики PC Линуса Торвальдса

Прежде чем начать сборку и компиляцию Linux нужно определиться с условиями, в которых приходилось работать Линусу Торвальдсу. В первую очередь интересует, какой у него был персональный компьютер и его характеристики. Да, мы достоверно знаем, на каком процессоре он работал, и ещё некоторые параметры, но я нигде в интернете не встречал (или плохо искал?) полную спецификацию его ПК. Поэтому решил на основе различных открытых источников провести «исследование» по этому вопросу. Вот на каком «железе», по моему мнению, работал автор ядра Linux.

Аппаратное обеспечение

Производитель, модель

SVGA Монитор, 14 дюймов

GoldStar 1460 Plus12

Системный блок

Н/Д. «Простой серый системный блок»3

Материнская плата

Н/Д

CPU

Intel 386DX, 33 МГц4

FPU

Intel 3875

RAM

4 (или скорее всего 8) Мб6

Video

Производитель неизвестен, на основе ET4000 с 1 Мб памяти7

FDD A

Дисковод 3,5 дюйма, 1,44 Мб8

FDD B

Дисковод 5,25 дюйма, 1,2 Мб9

HDD C

Conner CP3044 IDE Type 1710

HDD D

Conner CP3044 IDE Type 17

Modem

Производитель неизвестен11

Клавиатура

Финская клавиатура, производитель неизвестен

Примечания по таблице:

  • [1] Размер дисплея был упомянут в J4F.

  • [5] Сопроцессор 387 появился в процессе разработки ядра.

  • [6] В J4F описывалось, что было 4 Мб (скорее всего, такой объём был изначально), но в книге Линус пишет: «Помню, мне пришлось выйти из дома, чтобы увеличить ОЗУ с 4 до 8 мегабайт», и непонятно, осталась эта дополнительная память в его ПК или он взял её у кого-то временно. Я думаю, что осталась, потому что в ядре 0.01 в нескольких местах указано, что уже 8 Мб.

  • [7] "Счастливый обладатель" ET4000 EVGA, а при покупке возможно, был видеоадаптер Trident TVGA 8800 (?).

  • [8] В Release note указано устройство /dev/PS0 ("cp Image /dev/PS0 is what I use with a 1.44Mb floppy").

  • [9] Предположительно, дисковод был, потому что, в то время было распространённой практикой иметь дисководы и 3,5, и 5,25 дюйма. Косвенное доказательно наличия дисковода на 5,25 заключается в том, что в J4F говорится, что во время установки Minix Линусу потребовалось вставить 16 дискет (скорее всего, на самом деле 15. Первые три дискеты являются загрузочными и он использовал одну из них). И несмотря на то, что Minix-1.5 от PH на дискетах 3,5 дюйма официально издавался, у меня есть сомнения, что PH оставили дистрибутив на 17 3,5-дюймовых дискетах. Японское издание книги уместились на 6.

  • [10] Два HDD c характеристиками H5 S17 C980 + CP3044. Факт наличия второго диска (см. с момента “At my system fdisk reports the following…”).

  • [11] Внешний HAYES-совместимый (?) модем на 2400 baud.

Если вы обнаружили в таблице ошибки, пожалуйста, сообщите мне об этом.

Давайте теперь приблизительно сконфигурируем виртуальный компьютер в эмуляторе 86Box.


Предварительные условия

Эта инструкция написана и тестировалась на HP ProBook 440 G6 с операционной системой Ubuntu 20.04.6 LTS и версией эмулятора 86Box-Linux-x86_64-b4724.AppImage (AppImage есть в директории bin репозитория).

В первую очередь необходимо клонировать репозиторий:

git clone git@github.com:olegslavkin/linux-0.01.git
cd linux-0.01

Далее необходимо распаковать архив с пустым и неразмеченным виртуальным жёстким диском на 68 Мб:

mkdir -p disks
xz -kdc backups/empty-hda.img.xz > disks/minix.img

Внимательные читатели спросят, почему диск 1, а не 2, как в таблице выше? И почему он совершенно с другими характеристиками? Когда я начал писать это руководство, то ещё не знал о двух жёстких дисках и их характеристиках, и поэтому создал только один диск. Я попытался адаптировать руководство под два диска, но не справился с разметкой в Minix :( В будущих релизах, адаптирую под два и, возможно, не буду хранить вместе 16- и 32-битные утилиты Minix/Minix-386.

Теперь запустим эмулятор в режиме конфигурацию виртуального PC.

Если у вас до этого не был установлен 86box, то необходимо будет установить набор ROM-образов. Подробнее см. в документации.

$ ./86box -S

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

Конфигурация виртуального компьютера в 86box.

В качестве “Machine”, возможно, лучше было бы использовать “[SiS 310] ASUS ISA-386C”. Но, как писал выше, у меня нет информации об изначальной материнской плате.

86box-settings-machine
86box-settings-machine
86box-settings-display
86box-settings-display
86box-settings-input-devices
86box-settings-input-devices
86box-settings-sound
86box-settings-sound
86box-settings-network
86box-settings-network
86box-settings-ports-com-ltp-serial-port-1
86box-settings-ports-com-ltp-serial-port-1
86box-settings-storage-controllers
86box-settings-storage-controllers

Добавляем жёсткий диск disks/minix.img с указанными характеристиками:

86box-settings-hdd
86box-settings-hdd
86box-settings-floppy-cdroms
86box-settings-floppy-cdroms
86box-settings-other-removable-devices
86box-settings-other-removable-devices
86box-settings-other-peripherals
86box-settings-other-peripherals

Установка оригинальной 16-битной версии Minix 1.5.10

Установим оригинальную версию Minix 1.5.10 c оригинальных образов дискет. Я написал эту главу на основе второй главы оригинального MINIX 1.5 REFERENCE MANUAL.

Иногда в сети можно встретить название “Minix 1.5.10 PH”, ещё встречал “Minix PH”. PH — это аббревиатура от Prentice-Hall, названия издательства, которое и издавало книгу Andrew S. Tanenbaum “Operating Systems Design and Implementation-Prentice-Hall” (1987). Это те самые «719 страниц в мягком красном переплёте, можно сказать, поселились у меня в постели» (с) (J4F).

Загрузка Minix 1.5.10

Запускаем эмулятор:

$ ./86box

Первым делом заходим в настройки BIOS (нажимаем клавишу DEL). Задаём характеристики жёсткого диска (наиболее подходящий нам тип type 36) и дисководов. Важно, чтобы “Floppy drive A:” был “360KB 5.25”. Сохраняем настройки BIOS и выходим.

bios-floppyA-360k
bios-floppyA-360k

Проверяем, что в дисковод вставлена загрузочная дискета для PC (disk02), и после проверки BIOS и загрузки загрузочного сектора на экране эмулятора должно появится меню.

Загрузочное меню Minix
Загрузочное меню Minix

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

# _

…в меню эмулятора Media -> Floppy 1 -> Existing image... меняем на дискету с корневой файловой системой disk04. После этого в окне эмулятора вводим команду = для загрузки Minix в оперативную память (/dev/ram) с выбранной дискеты (/dev/fd0). После успешной загрузки в память, Minix предложит вставить дискету disk05, которая будет смонтирована в каталог /usr. Вставьте образ дискеты в меню эмулятора и нажмите Enter.

После монтирования дискеты система попросит ввести текущее время и день. Введите в формате MMDDYYhhmmss (см. скриншот ниже). И в конце загрузки Minix предложит авторизоваться в системе.

Как видите, Minix корректно работает, если ввести 2023 год. А вот недавно на linkmeup опубликовали забавный скриншот, на котором SunOS 4.1.4 писала предупреждение.

В Minix 1.5.10 есть, по меньшей мере, две учётные записи. Первая из них — это привилегированная rootовая с паролем Geheim, а вторая — учётная запись обычного пользователя ast с паролем Wachtwoord. Авторизуйтесь как root.

login
login
Настраиваем (опционально) getty

На этом этапе упростим дальнейшее взаимодействие с Minix. Вводить команды в окне эмулятора, с одной стороны, более «правильный» путь, но всё же это эмулятор, к тому же вводить команды таким способом получается очень медленно, да и copy-paste с этой инструкции будет невозможен :)

На наше счастье, Minix 1.5.10 поддерживает getty, а значит, благодаря возможности 86Box пробрасывать виртуальный COM-порт как устройство псевдотерминала на хостовую операционную систему, можно с помощью minicom, (c)kermit и других подобных утилит подключиться к Minix.

Поскольку при написании этого руководства проброс COM-порта ещё не был добавлен в релиз (это, предварительно, произойдёт в v4.0), в репозитории есть AppImage. Промежуточная сборка скачана с их Jenkins.

Однако на этапе установки из коробки нет возможности использовать getty, но очень легко это исправить. Для этого смонтируйте дискету disk04 в хостовой операционной системе (современный Linux всё ещё понимает старую файловую систему Minix) и добавьте одну строку в файл etc/ttys:

$ sudo dist/minix/disk04.img <path>
$ echo '2f1' >> <path>/etc/ttys

$ cat <path>/etc/ttys

100
0f1
2f1 <- Добавлена строка

Для этого руководства строка уже добавлена в disk04, но если хотите сделать это самостоятельно, то в репозитории есть оригинальная дискета disk04.img.orig.

И далее можно подключиться к Minix «удалённо». Псевдоустройство терминала /dev/pts/7, как в данном случае, будет отображено в stdout при запуске эмулятора 86box.

$ minicom -o -c off -t vt100 -p pts/7 -b 9600
minicom
minicom
Подключиться можно не только с хоста на Minix, но и в обратную сторону...

Для этого на хостовой ОС запустите agetty:

DEV='X'
sudo agetty -o '-p -- \\u' --keep-baud 9600 pts/${DEV} vt100

А в Minix запустите kermit и введите команды:

Устройство tty2 — это COM2. Чтобы не создавать петлю, включите проброс COM2 аналогично COM1.

set line /dev/tty2
set speed 9600
connect

Также при желании можно передавать и принимать файлы (правда, криво) с помощью протокола zmodem (через sz и rz). Но я считаю, что проще смонтировать на хосте дискету или раздел жёсткого диска и скопировать туда или оттуда нужные файлы.

Разметка жёсткого диска

Перед началом установки Minix необходимо разметить виртуальный жёсткий диск. Для этого введите команду:

fdisk -h8 -s17 /dev/hd0

Первая партиция диска hd1 размером в 5 Мб и с файловой системой DOS не будет использована в этом руководстве, но она специально оставлена как возможность установки MS-DOS, ведь даже у самого Линуса был раздел с MS-DOS где он играл в "Принца Персии".

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

c
1
0  (first cylinder)
75 (last cylinder)
y  (change partition to active)
a
1  (active )

Вторая партиция диска hd2, также размером в 5 Мб и с файловой системой Minix, будет использована как корневой раздел (/):

c
2
76  (first cylinder)
512 (last cylinder)
n

Третья партиция hd3 — как /usr:

c
3
513 (first cylinder)
588 (last cylinder)
n

Четвёртая партиция hd4 пока не будет использована, оставим её на будущее (для Linux):

c
4
589  (first cylinder)
1023 (last cylinder)
n

В результате получится такая таблица разделов:

                          ----first----  -----last----  --------sectors-------
Num Sorted Active Type     Cyl Head Sec   Cyl Head Sec    Base    Last    Size
 1     1     A    DOS-BIG    0   0   2     75   7   16       1   10334   10334
 2     2          MINIX     76   0   1    150   7   17   10336   20535   10200
 3     3          MINIX    151   0   1    905   7   17   20536  123215  102680
 4     4          MINIX    906   0   1   1023   7   17  123216  139263   16048

Для внесения изменений и выхода из fdisk нажмите w и выполните команду sync. Перезагрузите виртуальную машину и загрузитесь, как делали до этого. И потом вновь выполните fdisk и убедитесь, что всё успешно записалось. Для выхода из fdisk вводим q.

# fdisk -h8 -s17 /dev/hd0

                          ----first----  -----last----  --------sectors-------
Num Sorted Active Type     Cyl Head Sec   Cyl Head Sec    Base    Last    Size
 1     1     A    DOS-BIG    0   0   2     75   7   16       1   10334   10334
 2     2          MINIX     76   0   1    150   7   17   10336   20535   10200
 3     3          MINIX    151   0   1    905   7   17   20536  123215  102680
 4     4          MINIX    906   0   1   1023   7   17  123216  139263   16048

(Enter 'h' for help.  A null line will abort any operation)

Далее необходимо отформатировать средствами файловой системы все три Minix-партиции (раздела) жёсткого диска. Для каждой из них выполните команду mkfs /dev/hdX <РАЗМЕР В БЛОКАХ>, где X — это номер партиции, а РАЗМЕР В БЛОКАХ задаётся исходя из того, что блок занимает 1024 байта. Рассчитывается как количество секторов, разделённое на 2.

mkfs /dev/hd2 5100
mkfs /dev/hd3 51340
mkfs /dev/hd4 8024

Установка (копирование) Minix 1.5.10 на жёсткий диск

После подготовки жёстких дисков можно запустить shell-скрипт установки Minix 1.5.10. Для этого необходимо указать в качестве аргументов раздел корневого диска (в нашем случае это /dev/hd2), размер ram в Мб, а также размеры (в блоках) всех четырёх партиций.

/etc/setup_root /dev/hd2 4096 5139 5100 51340 8024

/dev/hd2 mounted
/dev/hd2 unmounted

Теперь вновь «вставьте» образ загрузочной дискеты disk02 и перезагрузитесь. После отображения загрузочного меню необходимо изменить корневой раздел, с которого будет выполняться загрузка. Во всех предыдущих шагах мы загружались с дискеты (disk04), но в этот раз необходимо загрузиться с раздела жёсткого диска. Для изменения корневого раздела в меню введите r (select root device), далее h2, затем Enter и после введите =.

Как и при первом запуске операционная система попросит вставить дискету с /usr (это disk05), и затем необходимо будет вновь авторизоваться как root.

change-root
change-root

Если до этого вы подключались к Minix с помощью minicom, то после загрузки с дискеты можно вновь будет к ней подключиться. Если в эмуляторе 86Box перезагружаете виртуальный компьютер кнопкой Reset в меню эмулятора, то, как правило, устройство псевдотерминала остаётся тем же и в minicom ничего делать не надо, достаточно только ввести логин и пароль и далее следовать этому руководству.

Теперь необходимо инициализировать раздел /usr. Для этого в терминале запускаем другой shell-скрипт, указав в качестве аргумента партицию диска, которую планируется использовать как /usr. В этом руководстве это hd3.

/etc/setup_usr /dev/hd3

Начнётся инициализация раздела /usr. Скрипт попросит вставить по очереди дискеты с disk05 по disk17.

<Вырезано, оставлен вывод только последнего диска>

/dev/fd0 mounted
Copying commands
/dev/fd0 unmounted
Please insert disk 17, then hit the ENTER key

/dev/fd0 mounted
Copying LAST_DISK
Copying amoeba
/dev/fd0 unmounted
Loading finished. Please remove the last diskette from the drive.

После копирования данных с дискет автоматически запустится распаковка архивов.

Посмотреть вывод работы скрипта
The files will now be unpacked.
Unpacking /usr/lib
Unpacking /usr/include
Unpacking /usr/include/minix
Unpacking /usr/include/sys
Unpacking /usr/src/elle
Unpacking /usr/src/kernel
Unpacking /usr/src/fs
Unpacking /usr/src/mm
Unpacking /usr/src/tools
Unpacking /usr/src/test
Unpacking /usr/src/lib/ansi
Unpacking /usr/src/lib/posix
Unpacking /usr/src/lib/other
Unpacking /usr/src/lib/ibm
Unpacking /usr/src/lib/string
Unpacking /usr/src/commands
Unpacking /usr/src/commands/ibm
Unpacking /usr/src/commands/bawk
Unpacking /usr/src/commands/de
Unpacking /usr/src/commands/dis88
Unpacking /usr/src/commands/indent
Unpacking /usr/src/commands/ic
Unpacking /usr/src/commands/m4
Unpacking /usr/src/commands/make
Unpacking /usr/src/commands/mined
Unpacking /usr/src/commands/nroff
Unpacking /usr/src/commands/patch
Unpacking /usr/src/commands/sh
Unpacking /usr/src/commands/zmodem
Unpacking /usr/src/commands/kermit
Unpacking /usr/src/commands/elvis
Unpacking /usr/src/amoeba
Unpacking /usr/src/amoeba/kernel
Unpacking /usr/src/amoeba/fs
Unpacking /usr/src/amoeba/mm
Unpacking /usr/src/amoeba/examples
Unpacking /usr/src/amoeba/util
Installation completed.

Так как мы только что инициализировали раздел /usr, то нет больше необходимости вставлять дискету disk05 в начале загрузки операционной системы. Теперь можно автоматически монтировать партицию диска hd3 как /usr. Для этого надо немного исправить /etc/rc:

mined /etc/rc

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

Комментируем (или удаляем) строки монтирования дискеты (а также приглашение вставки дискеты) и добавляем запись монтирования раздела жёсткого диска.

#/bin/getlf "Please insert /usr diskette in drive 0.  Then hit ENTER."
#/etc/mount /dev/fd0 /usr           	# mount the floppy disk
/etc/mount /dev/hd3 /usr            	# mount the hard disk

Опционально, устанавливаем более высокую скорость serial-порта:

# Initialize the first RS232 line to 9600 baud.
/usr/bin/stty 9600 </dev/tty1

В редакторе mined сохраняем изменения комбинацией клавиш CTRL+W, а для выхода из редактора нажмите CTRL+X.

Кроме mined в оригинальном Minix 1.5.10 есть и клон vi, и клон emacs elle, но на протяжении всего руководства буду использовать mined.

Вводим команду sync, проверяем, что у нас вставлена загрузочная дискета disk02 и вновь перезагружаемся. После загрузки выбираем, как в прошлый раз, r -> h2 и нажимаем =. Такие действия необходимо выполнять при каждой загрузке операционной системы.

Тестирование работоспособности Minix

Чтобы убедится, что операционная система установлена корректно, разработчики подготовили тестовые программы (предварительно необходимо их скомпилировать) и shell-скрипты. Для тестирования необходимо перейти в каталог и откомпилировать *.c. Рекомендуется компилировать как root (на последнем этапе для файлов устанавливаются права на выполнение):

cd /usr/src/test
make all
Процесс компиляции тестовых программ
cc -F -D_MINIX -D_POSIX_SOURCE -o test0 test0.c;            	chmem =8192  test0
test0: Stack+malloc area changed from 56042 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test1 test1.c;            	chmem =8192  test1
test1: Stack+malloc area changed from 59024 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test2 test2.c;            	chmem =8192  test2
test2: Stack+malloc area changed from 58086 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test3 test3.c;            	chmem =8192  test3
test3: Stack+malloc area changed from 58816 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test4 test4.c;            	chmem =8192  test4
test4: Stack+malloc area changed from 58982 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test5 test5.c;            	chmem =8192  test5
test5: Stack+malloc area changed from 54974 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test6 test6.c;            	chmem =8192  test6
test6: Stack+malloc area changed from 59156 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test7 test7.c;            	chmem =8192  test7
test7: Stack+malloc area changed from 49378 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test8 test8.c;            	chmem =8192  test8
test8: Stack+malloc area changed from 58098 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test9 test9.c;            	chmem =8192  test9
test9: Stack+malloc area changed from 57486 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test10 test10.c;  	chmem =8192  test10
test10: Stack+malloc area changed from 57522 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test11 test11.c;  	chmem =8192  test11
test11: Stack+malloc area changed from 57490 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test12 test12.c;  	chmem =8192  test12
test12: Stack+malloc area changed from 60678 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test13 test13.c;  	chmem =8192  test13
test13: Stack+malloc area changed from 58574 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test14 test14.c;  	chmem =20000 test14
test14: Stack+malloc area changed from 59476 to 20000 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test15 test15.c;  	chmem =8192  test15
"test15.c", line 438: (warning) incompatible pointers in ==
"test15.c", line 439: (warning) incompatible pointers in ==
"test15.c", line 440: (warning) incompatible pointers in ==
"test15.c", line 441: (warning) incompatible pointers in ==
"test15.c", line 443: (warning) incompatible pointers in ==
"test15.c", line 445: (warning) incompatible pointers in ==
"test15.c", line 447: (warning) incompatible pointers in ==
"test15.c", line 453: (warning) incompatible pointers in ==
"test15.c", line 506: (warning) incompatible pointers in ==
"test15.c", line 512: (warning) incompatible pointers in ==
"test15.c", line 514: (warning) incompatible pointers in ==
"test15.c", line 517: (warning) incompatible pointers in ==
"test15.c", line 523: (warning) incompatible pointers in ==
test15: Stack+malloc area changed from 49120 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test16 test16.c;  	chmem =8192  test16
test16: Stack+malloc area changed from 54988 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test17 test17.c;  	chmem =8192  test17
test17: Stack+malloc area changed from 43274 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test18 test18.c;  	chmem =8192  test18
test18: Stack+malloc area changed from 46508 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test19 test19.c;  	chmem =8192  test19
test19: Stack+malloc area changed from 54990 to 8192 bytes.
cc -F -D_MINIX -D_POSIX_SOURCE -o test20 test20.c;  	chmem =65000 test20

А для запуска самих тестов рекомендуется авторизоваться как обычный пользователь, а не root. Авторизуйтесь как ast с паролем Wachtwoord.

cd /usr/src/test
run

Если все тесты были успешно пройдены, то дополнительно запустите два тестовых shell-скрипта sh1 и sh2.

$ run
Test  0 ok
Test  1 ok
Test  2 ok
Test  3 ok
Test  4 ok
Test  5 ok
Test  6 ok
Test  7 ok
Test  8 ok
Test  9 ok
Test 10 ok
Test 11 ok
Test 12 ok
Test 13 ok
Test 14 ok
Test 15 ok
Test 16 ok
Test 17 ok
Test 18 ok
Test 19 ok
Test 20 ok
Test 21 ok
All system call tests completed.
Try running sh1 and sh2.

$ sh1
Shell test  1 ok

$ sh2
Shell test  2 ok

При запуске в minicom могут появиться фантомные ошибки, но после повторного запуска они обычно исчезают.

Резервное копирование промежуточной точки

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

tar cvfJ backups/minix-1.5.10-install-hda.tar.xz disks/minix.img nvr/acc386.nvr 86box.cfg

Установка патчей от Брюса Эванса (Bruce Evans' 386 patches) ака Minix-386

В предыдущей главе мы установили классическую 16-битную версию Minix 1.5.10, в том виде, в каком она изначально задумывалась автором. Но цель этого руководства — пройти шаги, сделанные Линусом Торвальдсом при написании Linux (ну ладно, ладно, не все шаги, сам Linux писать не будем :)). Как упоминалось выше, Линус работал не в оригинальной, а в пропатченной версии Minix 1.5.10, также известной как Minix-386. Патчи были подготовлены Брюсом Эвансом, а Джон Налл (John Nall) написал прекрасное руководство по их применению.

Но прежде, чем мы начнём преображение, необходимо немного «проапгрейдить» наш виртуальный PC. При установке классического Minix был задействован дисковод 5,25 дюйма на 360 Кб. Только указав такой тип виртуального дисковода в настройках эмулятора и BIOS, мне удалось выполнить установку и написать это руководство. Но для загрузки 32-битной версии Minix (а позже и для Linux) понадобятся уже дискеты 5,25 дюйма на 1,2 Мб. Поэтому необходимо, убедиться, что в настройках эмулятора и в BIOS указан соответствующий тип дисковода.

86box_floppy
86box_floppy
1_2M_FDD
1_2M_FDD

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

Загружаемся как обычно с загрузочной дискеты disk02, не забываем при этом указать в качестве корневого раздела партицию h2 при загрузке. Авторизуемся как root. Далее вместо загрузочной дискеты, в эмуляторе, вставляем дискету с патчами от Брюса Эванса minix-386, создаем каталог /usr/oz, монтируем дискету и копируем все файлы.

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

mkdir /usr/oz
cd /usr/oz
/etc/mount /dev/at0 /user
cp /user/* /usr/oz
/etc/umount /dev/at0
sync

Подготавливаем загрузочную дискету. Вставляем дискету shoelace и форматируем её:

mkfs /dev/at0 1200

Переходим в каталог с архивами и распаковываем их:

cd /usr/oz
compress -d mx386_1.1.t.Z
compress -d mx386_1.1.01.Z
compress -d bcc.tar.Z
compress -d bccbin16.tar.Z
compress -d bccbin32.tar.Z
compress -d bcclib.tar.Z

rm mx386_1.1.t.Z
rm mx386_1.1.01.Z

Далее создаём папку для загрузчика и распаковываем его:

mkdir /usr/oz/shoelace
mv shl-1.0a.t.Z shoelace
cd shoelace
compress -d shl-1.0a.t.Z
tar xvf shl-1.0a.t
rm shl-1.0a.t shl-1.0a.t.Z

Создаём папку для компилятора bcc, распаковываем архивы с 16- и 32-битной версией и исходными кодами стандартной библиотеки Си:

cd /usr/oz
mkdir bcc
mv bcc*.tar bcc

cd /usr/oz/bcc
tar xvf bcc.tar
tar xvf bccbin16.tar
tar xvf bccbin32.tar
tar xvf bcclib.tar
rm bcc*.tar

Распаковываем архив с патчами minix-386, а также для удобства работы переименовываем директорию в mx386:

cd /usr/oz
tar xvf mx386_1.1.t
mv mx386_1.1 mx386
rm mx386_1.1.t

Распаковываем небольшой патч на патч minix-386:

cd /usr/oz
unshar < mx386_1.1.01
rm mx386_1.1.01
mv klib386.x* /usr/oz/mx386/kernel

Переходим в папку с патчами ядра и применяем:

cd /usr/oz/mx386/kernel
patch klib386.x klib386.x.cdif

Монтируем загрузочную дискету (в дисковод всё ещё должна быть вставлена дискета shoelace), создаём необходимые директории и копируем директории dev и etc:

/etc/mount /dev/at0 /user
cd /user
mkdir usr
mkdir user
cd /
cpdir -s dev /user/dev
cpdir -ms etc /user/etc

Удаляем три 16-битные версии программ:

cd /user/etc
rm mount umount update

Комментируем строку с монтированием диска как /usr:

mined /user/etc/rc
# comment
# /etc/mount /dev/hd3 /usr

В корне создаём папку /local и копируем в неё 16- и 32-битную версию компилятора.

Использование пути /local обязательно. Если он вдруг не подходит, то необходимо будет его изменить в bcc.c и перекомпилировать компилятор.

cd /
mkdir local

cd /usr/oz/bcc
cpdir -ms bccbin16 /local/bin
cpdir -ms bccbin32 /local/bin3

cd /usr/oz/mx386
cpdir -ms bin0 /local/bin  # 16-bit compiler stuff
cpdir -ms bin3 /local/bin3 # 32-bit compiler stuff

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

cpdir -ms fs /usr/src/fs         # mods for fs
cpdir -ms kernel /usr/src/kernel # mods for kernel
cpdir -ms mm /usr/src/mm     	 # mods for mm
cpdir -ms tools /usr/src/tools   # mods for tools

cd /usr/oz/bcc/lib/fix1.5.10 	# move Bruce's changes
cp include.cdif /usr/include 	# to include

cp ansi.cdif /usr/src/lib/ansi   # to ansi
cp other.cdif /usr/src/lib/other # to other
cp posix.cdif /usr/src/lib/posix # and to posix

Применяем патчи заголовочных файлов:

cd /usr/include
patch < include.cdif

cd /usr/src/lib/ansi
patch < ansi.cdif

cd /usr/src/lib/other
patch < other.cdif

cd /usr/src/lib/posix
patch < posix.cdif

cd /usr/src/tools
patch < tools.cdif

cd /usr/oz/bcc/lib
cpdir -ms bcc /usr/src/lib/bcc

Сохраняем (не удаляем, он ещё будет нужен) оригинальный бинарный make и компилируем без флага -DMINIXPC:

cd /usr/bin
mv make make_s
cd /usr/src/commands/make
mined Makefile # Оставить только "CFLAGS = -Dunix"
make_s
mv make /usr/bin

Добавляем в PATH путь до компиляторов bcc, а также переименовываем оригинальный компилятор Си (сс) и делаем симлинк:

PATH=/local/bin:$PATH
export PATH
cd /usr/bin
mv cc cc_old
cd /local/bin
ln bcc cc

Компилируем 16-битную версию библиотеки libc.a и longlib.a:

cd /usr/src/lib/ansi
rm -f *.s
cd ../posix
rm -f *.s
cd ../ibm
rm -f *.s
cd ../other
rm -f *.s
cd ../string
rm -f *.s

cd /usr/src/lib/bcc
sh makelib 86 | tee problems.out 2>&1

cd /usr
mkdir local
cd local
mkdir lib
cd lib
mkdir i86
cd /usr/src/lib/bcc/i86
cp * /usr/local/lib/i86

cd /usr/src/lib/bcc/86
ar r /usr/src/kernel/longlib.a laddl.o lcmpl.o ldecl.o lorl.o \
    	lsll.o lsrul.o lsrl.o
cd /usr/src/kernel
ar t longlib.a  # check to be sure they are there...

Компилируем 32-битную версию библиотеки:

cd /usr/src/lib/bcc
sh makelib 86 clean

sh makelib 386 | tee problems.out 2>&1

cd /usr/src/lib/bcc/i386
mkdir /usr/local/lib/i386
cp * /usr/local/lib/i386
cd ..
sh makelib 386 clean

Создаём директорию для компонентов ядра Minix:

cd /etc
mkdir system

Компилируем компоненты ядра Minix. Обратите внимание, что при редактировании makefile.cpp необходимо, чтобы все строки препроцессора cpp начинались с начала строки.
В процессе линковки могут появляться предупреждения warning: _exit (или _unlock или _lock) redefined. Не обращаем на них внимание ни сейчас, ни позже.

cd /usr/src/mm
rm -f *.s *.o
mined makefile.cpp   # be sure all "#" commands start in column 1
/usr/lib/cpp -P -DINTEL_32BITS makefile.cpp > makefile
make             	# generate /etc/system/mm

cd /usr/src/fs
rm -f *.s *.o
mined makefile.cpp   # again, be sure all "#" commands start in col 1
/usr/lib/cpp -P -DINTEL_32BITS makefile.cpp > makefile
make             	# generate /etc/system/fs

При редактировании xx удалите все комментарии, которые не относятся к синтаксису препроцессора cpp, а также лишние символы табуляции в таких выражениях как #define O s, #if INTEL_32BITS, #else, #endif.

cd /usr/src/kernel
cp makefile.cpp xx
mined xx          	# remove all of the comment lines
rm -f *.s *.o
sh config 386     	# set up proper files.
/usr/lib/cpp -P -DINTEL_32BITS xx > makefile
make              	# generate  /etc/system/kernel

Компилируем init. В процессе линковки также могут появиться предупреждения warning: _exit (или _sbrk) redefined, которые тоже игнорируем.

cd /usr/src/tools
cc -3 -c -D_POSIX_SOURCE -D_MINIX init.c
ld -3 -o /etc/system/init /usr/local/lib/i386/head.o \
   init.o /usr/local/lib/i386/libc.a

Компилируем загрузчик shoelace, но для этого временно возвращаем оригинальные make и cc.

cd /usr/bin
mv cc_old cc
mv make make_o
mv make_s make
PATH=/usr/bin:/bin
export PATH
cd /usr/oz/shoelace
mined shoe.c      	# Заменить <varargs.h> на "varargs.h"
make -f makefile.min

Создаём загрузочный сектор на дискете и копируем бинарные файлы загрузчика, его конфигурационные файлы и компоненты ядра Minix.

cd /usr/oz/shoelace
./laceup /dev/at0 5.25dshd
cd /etc/system
mkdir /user/etc/system
cp * /user/etc/system   	# copy kernel, fs, mm, init
cp /usr/oz/shoelace/config /user/etc/config
cp /usr/oz/shoelace/shoelace /user/shoelace
cp /usr/oz/shoelace/bootlace /user/etc/bootlace
cp /usr/oz/shoelace/disktab /user/etc/disktab
cp /usr/oz/shoelace/laceup /user/etc/laceup

mined /user/etc/config
# Закомментировать run    /etc/system/db
# Заменить на дискету
setdev rootdev /dev/at0

Возвращаем make и сс, а также переменную PATH в прежнее состояние.

cd /usr/bin
mv cc cc_old
mv make make_s
mv make_o make
PATH=/local/bin:$PATH
export PATH

Компилируем 32-битный sh:

cd /user
mkdir bin
cd /usr/src/commands/sh

rm -f *.s *.o
cc -3 -D_POSIX_SOURCE -o /user/bin/sh *.c

Компилируем другие, минимально необходимые программы:

cd /usr/src/commands
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/bin/login login.c
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/etc/update update.c
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/etc/mount mount.c
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/etc/umount umount.c
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/bin/cat cat.c
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/bin/ls ls.c
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/bin/cp cp.c
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/bin/mv mv.c

cd /usr/src/commands/ibm
cc -3 -D_POSIX_SOURCE -D_MINIX -o /user/bin/readclock readclock.c

Убеждаемся, что в дисковод по прежнему вставлена дискета с shoelace, и перезагружаем компьютер.

Добро пожаловать в Minix-386!

minix-386
minix-386

Не обращайте внимание, что часть программ readclock, date, wtmp, printroot и stty, задействованные иницилизирующем скриптом /etc/rc, не смогли запуститься, они всё ещё 16-битные. В следующей главе исправим это.

minix-386-not-found
minix-386-not-found
Резервное копирование промежуточной точки

Ставим эмулятор на паузу и сохраняемся:

tar cvfJ backups/minix-386-1.5.10-stage1.tar.xz disks/minix.img dist/minix-386/shoelace.img nvr/acc386.nvr 86box.cfg

Компиляция стандартных утилит 1.5.10 под архитектуру i386

После проверки, что мы успешно загрузились с новым ядром с дискеты, необходимо перекомпилировать утилиты. Для этого загружаем 16-битный Minix (используем дискету disk02 и раздел жёсткого диска h2) и выполняем кросс-компиляцию 80386-версий бинарных утилит.

Чтобы упростить процесс я подготовил Makefile и вспомогательный sh-скрипт. Распаковываем архив с Makefile его и запускаем компиляцию:

cd /usr/oz
compress -d bin32.tar.Z
tar xvf bin32.tar && rm bin32.tar
/tmp/bin32.sh | tee problems.out 2>&1

Создаём директорию для 32-битной версии ядра и переносим туда скомпилированные на предыдущем этапе компоненты:

mkdir /etc/system3
cd /etc/system/
mv kernel fs mm init /etc/system3

Переносим бинарные файлы в /bin:

cd /etc
mv mount umount update /bin

Да, с точки зрения Minix это, возможно не канон, но так можно одновременно иметь как 16-, так и 32-битные версии программ. Также это упростит переключение между 16- и 32-битным режимом. Да и я уже просто привык, что mount/umount находится в PATH.

Размонтируем дискету, если в дисководе вставлено что-то отличное от shoelace, поменяем на неё и примонтируйем. Меняем в конфигурационном файле загрузчика значение rootdev с дискеты (at0) на диск (hd2) и меняем пути для mount и update:

umount /dev/at0
mount /dev/at0 /user

mined /user/etc/config
# setdev rootdev /dev/hd2	<- заменить на раздел HDD

mined /etc/rc
# /bin/mount /dev/hd3 /usr	<- заменить на /bin/
# /bin/update  &          	<- заменить на /bin/

sync

Переименуем директории. Не спешите перезагружаться!

/local/bin/bin3

Скрипт, который мы только что выполнили, не переименовывает директорию /usr/binX. Сделайте это вручную:

/bin0/mv /usr/bin /usr/bin0
/bin0/mv /usr/bin3 /usr/bin

Вот теперь можно перезагрузиться, и добро пожаловать в Minix-386 (снова)!

minix-386-again
minix-386-again
Резервное копирование промежуточной точки

Ставим эмулятор на паузу и сохраняемся:

tar cvfJ backups/minix-386-1.5.10-stage2.tar.xz disks/minix.img dist/minix-386/shoelace.img nvr/acc386.nvr 86box.cfg
Возврат на 16-битную версию

Если необходимо возвратиться на 16-ти битную версию, то нужно просто переименовывать пути до бинарных файлов, вставить дискету disk02 и использовать раздел жёсткого диска h2 как корневой.

/local/bin/bin0
/bin3/mv /usr/bin /usr/bin3
/bin3/mv /usr/bin0 /usr/bin
/bin3/sync
Утилиты, которых нет в версии 80386

Части утилит нет в 32-битной версий Minix. Нет клона emacs elle (это файлы файлы elle, ellec), потому что в оригинальных дискетах нет их исходных кодов.

В bcc не компилируются cpdir и ttt, это известная проблема. Для cpdir есть исправление, а для ttt — неизвестно. Но ttt — это игра “Tic Tac Toe”, или «Крестики-Нолики», мне она была ни к чему.

Нет необходимости в утилитах ast и cc, потому что мы используем компилятор bcc. Нет исходных файлов для pc— The Minix Pascal Compiler, но, возможно, это просто симлинк на cc.

Также у меня не работает compress (и его симлинки uncompress и zcat), но позже с установкой gcc поставим работающий compress.


Установка патча для сопроцессора 387

Вставляем дискету с shoelace и для компиляции ядра временно мигрируем на 16-битную версию.

/local/bin/bin0
/bin3/mv /usr/bin /usr/bin3
/bin3/mv /usr/bin0 /usr/bin
/bin3/sync

Вставляем дискету disk02 и перезагружаемся. После перегрузки вставляем дискету с gcc-1.37.1. Копируем патч ядра, имитирующий наличие сопроцессора 387. Он является частью gcc-1.37.1 и, как я понял, переназначает второй бит регистра CR0, «говорящий» компилятору, что у нас нет сопроцессора 387. Этот патч обязателен, в противном случае в будущем не получится собрать ядро Linux, мы получим ошибку компиляции fp stack overflow. После применения патча необходимо пересобрать ядро (достаточно только kernel) minix-386:

/bin/mount /dev/at0 /user
cp /user/klib386.cdiff /usr/src/kernel
cd /usr/src/kernel
PATH=/local/bin:/usr/bin:bin
export PATH
patch < klib386.cdiff
rm -f *.s *.o
make

Копируем ядро на загрузочную дискету. Размонтируем вставленную дискету, вставляем shoelace, монтируем её и копируем ядро:

/bin/umount /dev/at0
/bin/mount /dev/at0 /user
mv /etc/system/kernel /etc/system3
cp /etc/system3/kernel /user/etc/system
sync

Мигрируем обратно на minix-386:

/local/bin/bin3
/bin0/mv /usr/bin /usr/bin0
/bin0/mv /usr/bin3 /usr/bin
/bin0/sync
Резервное копирование промежуточной точки

Ставим эмулятор на паузу и сохраняем текущее состояние.

tar cvfJ backups/minix-386-1.5.10-stage3.tar.xz disks/minix.img dist/minix-386/shoelace.img nvr/acc386.nvr 86box.cfg

Установка компилятора GCC-1.37.1 от Alan W Black и Richard Tobin

Как известно, ядро Linux было скомпилировано с помощью gcc. И в оригинале это была собственная пропатченная версия gcc 1.40 от Линуса с поддержкой опции -mstring-insns (может, чего-то ещё). Где сейчас можно найти именно эту версию компилятора, мне не известно. Возможно, это та самая версия. В архиве файлы датированы 22 сентября 1991, очень-очень близко к тому времени. С другой стороны, на эти даты нельзя ориентироваться. Возможно, это gcc для сборки в самом Linux, а не в Minix.

Я пойду немного другим путём и буду использовать версию gcc-1.37.1 от Alan W Black и Richard Tobin, также известную как “awb-gcc from plains». Иногда в сети её называют просто “gcc from plains”. В природе существует и gcc-1.40 для Minix-386, но его использовать не буду, потому что: а) патч не от Линуса Торвальдса, а от Энди Майкла (Andy Michael); б) есть только diff, надо его ещё и скомпилировать :)

Загружаемся с дискеты shoelace, затем меняем её на дискету c gcc-1.37.1, монтируем её и копируем 16-битную версию утилиты compress (в Minix использовалась 13-битная компресия):

mount /dev/at0 /user
cp /user/16bcompress /usr/bin
chmod 755 /usr/bin/16bcompress

Копируем бинарные файлы gcc во временную папку, распаковываем и устанавливаем их:

cd /usr/tmp
cp /user/gcc*.tar.Z /usr/tmp
16bcompress -d gcc*.tar.Z

tar xvf gccbin.tar
cd gccbin
mkdir /usr/local/bin
mkdir /usr/local/lib/gcc
mv ar gcc gcc2minix make nm size /usr/local/bin
mv gcc-ld gcc-cc1 gcc-cpp gcc-as /usr/local/lib/gcc
ln /usr/local/lib/gcc/gcc-as /usr/local/bin/gas
ln /usr/local/lib/gcc/gcc-ld /usr/local/bin/gld
ln /usr/local/bin/ar /usr/local/bin/gar
cd /usr/tmp
rm -fr gccbin*

Устанавливаем заголовочные файлы:

cd /usr/tmp
tar xvf gccinc.tar
cd gccinc
mkdir /usr/local/lib/gcc/gcc-include
mv * /usr/local/lib/gcc/gcc-include
cd /usr/tmp
rm -fr gccinc*

Устанавливаем библиотеки Си:

cd /usr/tmp
tar xvf gcclib.tar
cd gcclib
cp /usr/lib/libc.a /usr/lib/libc.a.orig # вдруг будет необходима
cp libc.a /usr/lib/libc.a
cp libm.a /usr/lib/libm.a
cp gnulib /usr/local/lib/gcc/gnulib
cp crt0.o /usr/local/lib/gcc/crt0.o
cd /usr/tmp
rm -rf gcclib*

Тестируем компилятор, пишем традиционный “Hello World”:

cd /usr/tmp
PATH=/usr/local/bin/:$PATH
export PATH

cat <<EOF > gcc_test.c
#include <stdio.h>
main()
{
  printf("Hello World\\n");
}
EOF

gcc gcc_test.c

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

a.out
: not found

Всё дело в том, что gcc генерирует бинарный файл напрямую несовместимый с Minix. Есть два пути решения. Первый (популярный): сконвертировать в совместимый формат с помощью gcc2minix, который входил в комплект gccbin.

gcc2minix < a.out > test
chmod +x test
./test
Hello World

Второй вариант: использовать патч gnutoo. У меня он не сработал, но, возможно, я что-то сделал неправильно.

Резервное копирование промежуточной точки

Ставим эмулятор на паузу и сохраняем текущее состояние.

tar cvfJ backups/minix-386-1.5.10-gcc1.37.1.tar.xz disks/minix.img dist/minix-386/shoelace.img nvr/acc386.nvr 86box.cfg

Компилируем и запускаем ядра Linux 0.01

И вот, наконец-то, после всех этапов подготовки можно приступить к компиляции ядра Linux. Но для этого нужно ещё чуть-чуть подготовиться :). Помните, в самом начале, когда разбивали жесткий диск на разделы, у нас остался неиспользованный раздел h4? Его оставили как раз для Linux. Отформатируем раздел, а также подключим его в автомонтирование при запуске Minix-386:

mkdir /linux
mkfs /dev/hd4 8024
mined /etc/rc
# добавить можно сразу после строки монтирования /dev/hd3
# /bin/mount /dev/hd4 /linux          	# linux
/bin/mount /dev/hd4 /linux

Создадим необходимые каталоги:

cd /linux
mkdir usr
mkdir tmp
cd usr
mkdir src

Вставляем дискету с исходными кодами Linux linux-src-0.01 и монтируем дискету. Сам архив c исходными кодами linux-0.01.tar.Z взят с сайта oldlinux.org. Примечательно, что на официальном сайте ядра Linux имеется tar.gz версия от октября 1993 (ядро 0.01, я напомню, «родилось» 17.09.1991). Это, скорее всего переупаковка в формат архива, поддерживаемого GNU-утилитами того времени.

/bin/mount /dev/at0 /user
cp /user/linux.tar.Z /linux/tmp
16bcompress -d /linux/tmp/linux.tar.Z
cd /linux/usr/src
tar xvf /linux/tmp/linux.tar
rm /linux/tmp/linux.tar
cd linux

Адаптация ядра под gcc-1.37.1:

mined Makefile

# Добавляем путь до gnulib:
LIBS	=lib/lib.a /usr/local/lib/gcc/gnulib

# У Линуса был патч gnutoo (или ему подобный), поэтому конвертации не было.
# Приводим к следующему виду.
# Не забывайте, что в Makefile отступ от начала строки отделяет символ табуляции!
tools/build: tools/build.c
	$(CC) $(CFLAGS) \
	-o tools/a.out tools/build.c
	gcc2minix < tools/a.out > tools/build
	chmod +x tools/build
	chmem +65000 tools/build

# Удаляем `-mstring-insns` из CFLAGS
mined fs/Makefile
mined kernel/Makefile
mined lib/Makefile

Адаптируем под наше «железо»: используем 5,25-дюймовые дискеты на 1,2 Мб вместо 3,5-дюймовых, задаём верхнюю границу оперативной памяти, а также указываем, что будем использовать раздел h4 жёсткого диска, и его характеристики.

Сейчас и чуть позже вы увидите, почему я сомневаюсь, что у Линуса был компьютер с 4 Мб оперативной памяти, скорее всего у него было 8Мб. Возможно, при покупке было действительно 4, но потом увеличил до 8. Как, возможно, и добавил второй жёсткий диск.

# Указываем, что будем использовать 1,2 Мб
mined boot/boot.s
| sectors = 18
sectors = 15

mined include/linux/config.h
/* #define LASU_HD */
/* #define LINUS_HD */
#define E86BOX_HD
...
#if 	defined(LINUS_HD)
#define HIGH_MEMORY (0x800000)
#elif   defined(LASU_HD)
#define HIGH_MEMORY (0x400000)
#elif   defined(E86BOX_HD)
#define HIGH_MEMORY (0x400000)
#else
#error "must define hd"
#endif
...
/* Root device at bootup. */
#if 	defined(LINUS_HD)
#define ROOT_DEV 0x306
#elif   defined(LASU_HD)
#define ROOT_DEV 0x302
#elif   defined(E86BOX_HD)
#define ROOT_DEV  0x304
#else
#error "must define HD"
#endif

#if 	defined(LASU_HD)
#define HD_TYPE { 7,35,915,65536,920,0 }
#elif   defined(LINUS_HD)
#define HD_TYPE { 5,17,980,300,980,0 },{ 5,17,980,300,980,0 }
#elif   defined(E86BOX_HD)
#define HD_TYPE { 8,17,1024,65536,1024,0 }
#else
#error "must define a hard-disk type"
#endif

Добавляем в PATH пути до компиляторов и ассемблера, и наконец компилируем:

PATH=/usr/local/bin:/local/bin:/bin:/usr/bin
export PATH
make

Если компиляция пройдёт успешно, то в папке с ядром появится файл Image. Это и есть наше ядро Linux.

...
gld -s -x -M boot/head.o init/main.o \
kernel/kernel.o mm/mm.o fs/fs.o \
lib/lib.a /usr/local/lib/gcc/gnulib \
-o tools/system > System.map
(echo -n "SYSSIZE = (";ls -l tools/system | grep system \
    	| cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s
cat boot/boot.s >> tmp.s
as -0 -a -o boot/boot.o tmp.s
rm -f tmp.s
ld -0 -s -o boot/boot boot/boot.o
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \
-o tools/a.out tools/build.c
gcc2minix < tools/a.out > tools/build
chmod +x tools/build
chmem +65000 tools/build
tools/build: Stack+malloc area changed from 65536 to 130536 bytes.
tools/build boot/boot tools/system > Image <---- это Linux!!!
Boot sector 452 bytes.
System 93184 bytes.
sync
Но, возможно, у вас, как и у меня, компиляция может упасть с ошибкой
gcc: installation problem, cannot exec /usr/local/lib/gcc/gcc-cc1: No more processes

Это происходит, как я понял, из-за малого размера оперативной памяти (напомню, мы используем 4 Мб). И тут есть два решения: а) в настройках эмулятора временно увеличить до 8 Мб и всё заработает как надо; или б) выполнить сборку в несколько этапов.

cd kernel && make
cd ../mm  && make
cd ../fs  && make
cd ../lib && make
cd .. 	&& make

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

cd /linux
mkdir dev
mkdir bin

cd dev
mknod tty c 5 0
mknod tty0 c 4 0
mknod tty1 c 4 1
mknod tty2 c 4 2
mknod hd0 b 3 0 0
mknod hd1 b 3 1 5139
mknod hd2 b 3 2 5100
mknod hd3 b 3 3 51340
mknod hd4 b 3 4 8024

Вставляем дискету bin c готовыми бинарным bash и update.

bash не оригинальный, скомпилирован в 2004 году, скорее всего Jiong Zhao (автором сайта oldlinux.org). В оригинале должен использоваться bash-1.08, но мне не удалось найти ни бинарный, ни исходный код этой версии.

/bin/mount /dev/at0 /user
cp /user/bash /linux/bin/sh
cp /user/update /linux/bin/update

Вставляем чистую дискету boot и записываем на неё ядро.

/bin/umount /dev/at0
cd /linux/usr/src/linux

dd if=Image of=/dev/at0
183+0 records in
183+0 records out

Перезагружаем компьютер. И поздравляю, вы в Linux-0.01 с захардкоженной финской раскладкой.

linux-0.01
linux-0.01

Но, как и писал Линус, делать в этой версии ядра совершенно нечего, только любоваться. Голая оболочка bash, в которой нет ничего, кроме встроенных команд. Даже ls нельзя выполнить, но можно попробовать её имитировать с помощью alias ls='echo *'.

Резервное копирование промежуточной точки

Ставим эмулятор на паузу и сохраняем текущее состояние.

tar cvfJ backups/minix-386-1.5.10-linux-0.01.tar.xz disks/minix.img dist/minix-386/shoelace.img dist/linux/boot.img nvr/acc386.nvr 86box.cfg

Заключение

Кроме Linux 0.01 мы сделали три различные среды, в которых можно долго и увлекательно проводить время.

Во-первых, это оригинальная Minix 1.5.10, в которой можно изучить микроядро Minix, а книга Эндрю поможет в этом. За прошедшие годы сообщество создало и портировало немало интересных программ. Часть их них до сих пор можно найти в интернете. Часть сохранена на легендарном nic.funet.fi.

Во-вторых, это Minix-386, для которой тоже сделали немало интересного. Например, была реализация GUI Mini-X (не X11 совместимая), виртуальные консоли (прямо как современный screen), реализация IP-стека, которого не было в Minix, но очень многие его просили, и многое другое.

И в-третьих, мы сделали среду с gcc и Linux, где можно самостоятельно скомпилировать и запустить другие версии ядра или попробовать портировать GNU-утилиты. К сожалению, последующие версии ядра 0.02 и 0.03 не сохранились до наших дней, а из 0.10 сохранилась только версия Theodore Ts'o. Зато на версиях 0.11 и 0.12 можно изучать внутренне строение ядра Linux.

А ещё, всё тот же автор oldlinux.org Jiong Zhao написал фейковую версию 0.00. Как писал Линус: "Моя первая тестовая программа использовала один процесс для выдачи на экран буквы А, а другой – для выдачи буквы В. (Звучит тоскливо – я знаю.) Я запрограммировал это так, чтобы каждую секунду писалось несколько букв. С помощью прерывания по таймеру я сделал так, что сначала экран заполнялся ААААААА. Потом неожиданно буквы сменялись на ВВВВВВВВВ.". Однако у меня в 86Box она не заработала :(.


P.S.

Если у кого-нибудь будет желание запустить всё на настоящем, а не виртуальном «железе», и у вас появятся вопросы, то мои контакты можно найти в профиле Хабра или на github.com.

Комментарии (15)


  1. alan008
    16.08.2023 05:30
    +4

    Титанический труд. И сразу представляешь, насколько тяжело жилось пользователям ПК в те годы. Чего только стоит постоянная подмена дискет и "вставьте дискеты с 5 по 17-ю", а уж если какая-то дискета не прочитается, то вообще голяк. И тонны команд в консоли, которые выглядят как минное поле - если пропустить что-то или опечататься, весь процесс мог пойти на смарку. И всё это на реальном железе. Эхехех.

    Здесь может начаться холивар, но всё-таки доступность ПК для всех людей пришла с миром Windows (ну и более лучшим железом, конечно же, т.к. даже устанавливать ОС с компакт диска в разы удобнее, чем с дискет).


    1. guryanov
      16.08.2023 05:30
      +3

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


    1. Stanislavvv
      16.08.2023 05:30

      С учётом того, что и win 3.1 всё ещё ставилась с дискет — это было нормально. И, кстати, привычно — тогда начинали с MSDOS, а не чего-то гуёвого.

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


      1. Xeldos
        16.08.2023 05:30

        Просто поставить с дискет - было нормально. Это занимало часы, но было привычно. Но вот это жонглирование дискетами туда-сюда-обратно... А это ещё есть два физических дисковода и HDD!


    1. saipr
      16.08.2023 05:30

      а уж если какая-то дискета не прочитается, то вообще голяк

      Как мы боролись с этим? Мы запускали Minix и пытались хоть часть информации с дискеты восстановить утилитой dd!!! Вёсёлое было время.


      1. romanuld
        16.08.2023 05:30

        если это были дискеты с ОС (или wolf 3d), то это не помогало. приходилось куда-то бежать за новой копией дискеты


        1. saipr
          16.08.2023 05:30

          Речь идет, конечно, только о текстовой информации. Мы этот приём использовали при подготовке списков для получения приватизационных чеков в 1992 году.


  1. alan008
    16.08.2023 05:30

    Посмотрел профиль автора. Начальство такое: девопс ты или не девопс, если не можешь развернуть Linux 0.01 в виртуалке :-) Автор: Challenge accepted and passed


    1. OlegSL Автор
      16.08.2023 05:30
      +2

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

      Если кому интересно по времени, то у меня на это руководство ушёл почти год, конечно с перерывами. Где в конце августа 2022 года я начал попытку поставить Minix в виртуальную машину (до сих пор сохранились скриншоты) и худо-бедно у меня заработала в конце сентября того же года, с чем я радостно поделился с читателями ЛОРа. И в том посту на ЛОРе, я даже попытался рассказать что надо сделать, чтобы добиться тоже результата и потом дал себе слово, что сделаю нормальную документацию. Но глядя на множество скриншотов, разрозненных заметок понял, что это работы еще на месяц, отложил это дело. Вернулся к инструкции только во второй половине лета этого 2023 года, и да, где-то месяц-полтора ушло на написание и редактирование материалов.

      Кроме Linux, мне нравится запускать и другие разные утилиты. Вот Midnight Commander (ранее MouseLess Commander), а вот, возможно наиболее полная коллекция в мире DE Xfce (версии 1.04 - 3.8.18). Но этот проект у меня ещё не завершён. Однажды, я спросил по email основателя Оливье Фордана (Olivier Fourdan), а может сохранились у него какие-то другие версии, на что он мне ответил, цитирую: "I reckon you already have more versions than I could find myself! I used to have older, preliminary versions of xfce on backups but I lost these after several house moves a long time ago.". Увы и ах...


      1. alan008
        16.08.2023 05:30

        Склоняю шляпу.


        я раза 4 или 5 переписывал всё с нуля и с десяток раз корректировал последовательность выполнения команд

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


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


        1. Johan_Palych
          16.08.2023 05:30

          Самый главный вопрос — какая, на ваш взгляд, может быть польза от запуска этих старинных программ / операционных систем в настоящее время?

          Человек может в разработку. У него прошаренные компетенции. Без прошлого не бывает будущего(Кэп - самого чуть не стошнило)
          Книжка актуальна и в настоящее время
          http://old-os.ucoz.com/publ/knigi/1001_sekret_reestra_windows_nt_4/7-1-0-33


        1. romanuld
          16.08.2023 05:30

          тренировка нейросвязей в мозге еще никому не помешала )


  1. saipr
    16.08.2023 05:30

    Итак, 30 лет назад, теперь уже в далеком 1987 году, Эндрю Таненбаум в качестве учебного пособия для своей книги «Operating Systems: Design and Implementation» (1987, ISBN 0-13-637406-9) написал Unix-совместимую операционную систему Minix. Сокращённые 12000 строк исходного кода, написанного преимущественно на языке программирования C, ядра, подсистемы управления памятью и файловой системы Minix были напечатаны в книге. Эндрю Таненбаум разработал ОС Minix для компьютеров IBM PC и IBM PC/AT, доступных в то время. К этому времени и у нас в стране стали появляться совместимые с IBM PC персональные компьютеры ЕС-1840/41/42 и даже ЕС-1845, на которых, как оказалось в последствии, успешно работала ОС Minix.

    Это было напечатано в 2017 году на просторах Хабр-а: 30-летие учебного пособия ОС Minix.


    Именно Minix стал отправной точкой для появления Linux.


    1. Johan_Palych
      16.08.2023 05:30

      Информативнее читать англоязычный вариант.
      https://en.wikipedia.org/wiki/Minix
      https://oldlinux.superglobalmegacorp.com/Linux.old/Minix/old/1.1/Floppies/Readme

      MINIX 1 был совместим по системным вызовам с Seventh Edition Unix:
      https://en.wikipedia.org/wiki/Version_7_Unix

      Если интересно:
      Эмулятор PDP -11 simh есть под основные дистрибы
      https://pkgs.org/download/simh
      Образы:
      http://ftp.fibranet.cat/UnixArchive/Distributions/Boot_Images/


  1. HabraHabrAbraKadabr
    16.08.2023 05:30

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