Лоуренс Кестелут. Перенос BSD Unix на новую платформу, 1995

1. Введение

Исходный код системы Berkeley Software Distribution (BSD) Unix доступен свободно. Здесь описывается руководство для тех, кто желает перенести систему на новую архитектуру. Перенос больше всего похож на написание драйверов устройств для нового компьютера, а если BSD Unix ещё не была перенесена на целевой процессор, то может потребовать и переписывания части операционной системы на язык ассемблера. В этом руководстве обсуждается как начать проект, какие файлы нужно модифицировать, какие драйверы нужно написать и что следует сделать после передачи переноса в общественное пользование.

Подразумевается, что читатель (и другие участники переноса) имеют глубокие знания языка C, хорошие навыки использования Unix и знакомы с базовым курсом по операционным системам.

1.1. Краткая история Unix и BSD

Unix была разработана в Лабораториях Белла - исследовательском подразделении Американской Телефонной и Телеграфной компании (Bell Labs AT&T) в начале 1970'х [1]. Несколько университетов приобрели её вместе с лицензией на исходный код, а Университет Калифорнии в Беркли переписал и усовершенствовал большую часть системы с 1979 по 1994 [3]. В конечном итоге была выпущена версия Unix под названием BSD, но часть исходных текстов имели отметку об авторских правах AT&T, из-за чего пользователям BSD было необходимо приобретать у AT&T дорогостоящую лицензию.

В 1991 году Исследовательская Группа Информационных Технологий Беркли (Berkeley's Computer Science Research Group - CSRG) удалила части BSD 4.3, написанные в AT&T, а всё остальное выпустила как Berkeley Networking Release 2 (Net/2). Билл и Линн Джолиц написали недостающие части Net/2 заново, завершили почти готовый перенос на i386 и выпустили 386BSD 0.0. Сразу за ней была выпущена чуть более стабильная 386BSD 0.1. Т.к. свободный от ошибок выпуск 0.2 был отложен на неопределённый срок, несколько групп были вынуждены начать выпускать собственные версии BSD. Группа FreeBSD взяла 386BSD, добавила собственные улучшения и стала регулярно выпускать BSD для линейки компьютеров IBM PC. Группа NetBSD приняла решение выпускать исследовательскую версию 386BSD, которая теперь перенесена на более чем полдюжины компьютеров. Система NetBSD лучше всего подходит для работы с различными архитектурами и рекомендуется, чтобы новые переносы основывались на дереве исходных текстов NetBSD. Автор этого документа и четверо других студентов (Брэд Грэнтем - Brad Grantham, Аллен Бриггс - Allen Briggs, Майк Финч - Mike Finch и Крис Капуто - Chris Caputo) перенесли NetBSD на Macintosh и теперь этот перенос является частью стандартного дистрибутива NetBSD.

1.2. План проекта

Перенос BSD происходит примерно в следующей последовательности. Нужно:

В конечном итоге вам может захотеться выпустить перенос в общественный доступ, для чего потребуется создать двоичный дистрибутив и набор инструментов для установки, а также обзавестись списком рассылки, подготовить FAQ (Frequently Asked Questions - часто задаваемые вопросы) и запастись терпением (раздел 5).

1.3. Термины

Определим несколько терминов, чтобы избежать дальнейшей путаницы. Ядро - это единая часть кода, которая всегда присутствует в оперативной памяти в процессе работы Unix и которая отвечает за взаимодействие с оборудованием и распределение ресурсов, таких как процессор, память и диски. Пользовательская программа (в кругах BSD часто называемая программой пространства пользователя) - это любая программа, отличная от ядра. В общем, это любая программа, которую может запустить пользователь. К ним относятся такие программы как ls и cc, а также демоны, такие как inetd и timed.

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

Модуль управления памятью (MMU - Memory Management Unit) является частью оборудования, которая преобразует виртуальные адреса в адреса физической памяти и отвечает за защиту адресных пространств процессов. Иногда MMU - это отдельная микросхема, находящаяся между центральным процессором и памятью, а иногда он бывает встроен прямо в центральный процессор. В памяти есть таблицы, которые MMU использует для преобразования адресов.

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

Любая исполнимая двоичная программа (ядро и программа пользователя) состоит из трёх сегментов: text, data и bss. text - это компьютерный код, который обычно отображается как доступный только для чтения, чтобы MMU перехватывал попытки записи по некорректным указателям. data - это инициализированные данные программы, которые хранятся вместе с сегментом text в исполнимом файле. bss (Block Started by Symbol - блок, начинающийся с символа) не сохраняется на диски и используется для хранения неинициализированных переменных программы. При загрузке программы в Unix для bss выделяется пространство, которое инициализируется нулями. Однако у программы нет гарантий, что bss (а следовательно и её неинициализированные данные) будут нулевыми. Вряд ли это поведение Unix когда-нибудь изменится, потому что из-за этого могли бы перестать работать многие пользовательские программы. Однако предупреждаем, что некоторые другие операционные системы (например, MS-DOS) не очищают bss и предположения о его содержимом сделают программу не переносимой.

1.4. Ресурсы

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

В настоящее время около дюжины людей активно участвуют в переносе NetBSD на различные компьютеры и важно пользоваться их помощью при затруднениях. Они могут ответить на вопрос или указать на неверно выбранный подход. Четверо ключевых членов NetBSD доступны по электронной почте core@netbsd.org. Члены команды, переносившей NetBSD на Macintosh, доступны по адресу alice@acm.vt.edu.

2. Раскрутка проекта2

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

2.1. Выбор начальной точки

Непрактично писать весь машинно-зависимый код с нуля. Стоит взять в качестве основы перенос NetBSD на компьютер, наиболее похожий на целевой. Идеально, если уже есть перенос на процессор целевого компьютера - это позволит избежать проблем с переписыванием всей ассемблерной архитектурно-зависимой части кода. Для переноса на серию процессоров Motorola 68000 проще всего выбрать процессор, начиная с 68020. Уже есть несколько переносов на этот микропроцессор (например, Macintosh, Sun 3, Amiga и HP 300), которые совместно используют большую часть кода. Другие поддерживаемые процессоры - это Intel i386, MIPS R3000 (перенос на который называется "PMAX") и Sun Sparc. Отправьте письмо на адрес core@netbsd.org для получения актуального списка уже готовых и находящихся в разработке переносов.

Придумайте для вашего переноса название, как можно точнее описывающее компьютер, на котором он будет работать. Например, наш перенос на Macintosh изначально назывался "Mac", но позже был переименован в "Mac68k", потому что не поддерживает микропроцессоры PowerPC. Сделайте копию поддерева /usr/src/sys/arch/ (имеющего имя переноса, выбранного в качестве основы) и переименуйте соответствующим образом подкаталоги и файлы. Теперь можно приступать к переносу.

2.2. Среда для кросс-разрабоки

Когда уже есть готовый перенос, то собрать ядро можно прямо из BSD. Но пока это не так, придётся настроить среду кросс-компиляции на другой платформе Unix. Лучше чтобы выбранный компьютер был похож на целевой компьютер, а операционной системой была BSD. Это позволит уменьшить проблемы с различным порядком байт в процессорах, с расхождениями в файлах (например, макросы в ctype.h часто реализуются по-разному) и с различиями в форматах объектных файлов.

Проект BSD использует улучшенную утилиту make, которая называется pmake. Кроме прочих возможностей она позволяет включать в makefile'ы другие makefile'ы, что часто используется во всей системе. Это единственная программа в системе, которую можно скомпилировать при помощи обычнй утилиты make, поэтому собрать её нужно в первую очередь. Затем нужно скомпилировать gcc, as, ld, ar, ranlib и size.

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

Поскольку в Unix, используемой для кросс-разработки, с высокой вероятностью уже есть утилиты с такими же именами, полезно написать сценарий, который позволит переключаться между системными исполняемыми файлами и исполняемыми файлами BSD. Этот сценарий также должен переключаться между системными заголовочными файлами и библиотеками и заголовочными файлами и библиотеками BSD. Как вариант, можно переименовать утилиты BSD и соответствующим образом обновить пути и makefile'ы BSD.

2.3. Автономное ядро

Операционные системы можно загрузить одним из двух способов. На некоторых архитектурах (например, на HP 300), загрузка компьютера состоит из этапов диагностики, производимой ПЗУ, чтения первого блока диска в оперативную память и его выполнения. Этот первый блок обычно читает следующие восемь блоков, содержащие автономное ядро, и запускает их. Автономное ядро, за редкими исключениями, может прочитать файл из основной файловой системы и, возможно, осуществить загрузку через сеть. Автономное ядро ищет в структуре каталогов на определённом (загрузочном) разделе файл с определённым именем, таким как unix, vmunix или netbsd, грузит его в память, очищает bss и запускает его. На компьютерах других архитектур (например, на Macintosh) ядро загружается прямо из приложения (загрузчика), работающего в исходной операционной системе (например, в MacOS). В таком случае автономное ядро не используется и его функции перемещаются в загрузчик (см. раздел 2.4).

В любом случае, автономное ядро - это отличное место для проверки драйверов устройств и другого экспериментального кода без необходимости разбираться с прерываниями, отображением памяти и остальной частью ядра. При переносе на Macintosh мы написали и протестировали драйверы дисплея, последовательного порта, клавиатуры, часов и жёсткого диска перед их компоновкой с кодом ядра. Мы также частично протестировали отображения MMU и прерывания. Другое преимущество автономного ядра заключается в том, что оно гораздо меньше ядра Unix и быстрее компилируется, что позволяет ускорить цикл разработки.

2.4. Загрузчик

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

  1. Найти ядро в корневом каталоге указанного раздела на диске;
  2. Загрузить ядро (сегменты text и data) в непрерывный фрагмент памяти;
  3. Поместить за ядром подпрограмму инициализации ядра и выполнить её.

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

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

3. Машинно-зависимый код

Код ядра делится на две главные части: машинно-независимую и машинно-зависимую. Первая обычно является общей для всех переносов, содержит алгоритмы и структуры данных, не зависящие от архитектуры, на которой будет работать ядро, и написана целиком на языке C. Вторая содержит подпрограммы и модули, которые называют машинно-зависимым кодом. Ассемблерная часть ядра хранится в одном файле - locore.s. Файл pmap.c содержит средства для управления отображениями памяти компьютера и взаимодействует с машинно-независимым кодом подсистемы виртуальной памяти ядра. Наконец, остальной машинно-зависимый код помещается в файл machdep.c.

3.1. locore.s

Файл locore.s содержит всю ассемблерную часть кода переноса. Она содержит обработчики прерываний и исключений, код начальной настройки, код переключения задач и любые другие подпрограммы, которые часто используются и достаточно малы, чтобы быть написанными на ассемблере (например, подпрограммы для копирования блоков памяти). На ассемблере должно быть написано как можно меньше, потому что он не переносим и не прост в сопровождении. У нескольких переносов часть файла locore.s отделена в Locore.c.

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

Загрузчик или автономное ядро передают управление коду по метке start. Обычно этот код отключает прерывания и кэши, настраивает таблицы MMU и включает его, включает прерывания и передаёт управление подпрограмме main(), написанной на C и отвечающей за инициализацию машинно-независимого кода.

На большинстве архитектур подпрограмму настройки MMU можно написать на C, а не на ассемблере. Однако на других архитектурах этот код должен быть написан на ассемблере из-за особенностей расположения памяти. Например, на компьютерах HP 300 оперативная память отображается в конец физического адресного пространства. Из-за этого последний адресуемый байт имеет адрес 232-1. Это означает, что при загрузке ядра в начало физической памяти младший адрес (и следовательно адрес всех переменных и подпрограмм ядра) зависит от объёма установленной в компьютер памяти. На этапе компоновки кода ядра этот адрес неизвестен, поэтому ядро должно использовать MMU, чтобы отобразить себя на виртуальный адрес 0. Настройка таблиц MMU происходит до включения MMU, поэтому все ссылки на переменные и подпрограммы нужно передать в область физического размещения ядра явным образом. Это не так легко сделать в C, поэтому код написан на ассемблере.

Ассемблерная часть кода переключения задач сохраняет и восстанавливает состояние компьютера (включая состояние MMU и модуля поддержки чисел с плавающей запятой). Остальной машинно-независимый код написан на C.

3.2. pmap.c

Файл pmap.c отвечает за машинно-зависимое взаимодействие с MMU. Машинно-независимый код подсистемы виртуальной памяти, который находится в каталоге /usr/src/vm, хранит записи о текущих отображениях каждого из процессов. При каждом изменении отображения код подсистемы виртуальной памяти вызывает подпрограмму в pmap, обновляющую состояние MMU, чтобы оно отражало изменения в структурах данных ядра. Самая частая операция в pmap - это добавление страницы к существующему отображению, но при вызовах fork() отображение бывает нужно скопировать, а при вызовах exec() - пересоздать. Большая часть pmap нового переноса может быть основана прямо на pmap из переносов на другие компьютеры со сходными процессорами и MMU.

3.3. machdep.c

Файл machdep.c содержит все остальные машинно-зависимые подпрограммы. Большинство из них инициализируют системную консоль, выделяют память для структур ядра, выполняют машинно-зависимую часть обработки сигналов, сохраняют образ памяти ядра на диск для отладки, обрабатывают аварийные ситуации в ядре, исключения, прерывания, таймеры, контроль чётности, учитывают разлчия между процессорами (например, тонкие отличия между Motorola 68020 и 68030), необычные отображения памяти и выполняют отладочный вывод.

3.4. Структура прерывания

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

Приоритеты прерываний имеют значение, потому что обычно для обеспечения взаимных исключений в ядре прерывания отключаются. Например, подпрограмма, изменяющая структуры терминала (которые обрабатывают ввод и вывод терминала) вызывает spltty() (что означает Set Processor Level TTY - установить уровень процессора для терминала) прямо перед критической секцией, а после неё восстанавливает прежний уровень, который был до вызова spltty(). На большинстве компьютеров этот вызов отключит все прерывания, которые могут вызвать функцию, работающую со структурой терминала, а также отключит все прерывания с прироритетами ниже, чем у терминала. Структура прерыванияй недостаточно подходящая для Unix может привести к тому, что относительно длинный код прерывания (например, для обработки доступа к диску или звуковому драйверу) может заблокировать более частые прерывания (например, от таймера, клавиатуры или последовательного порта). В переносе на Macintosh интенсивное использование диска может привести к тому, что системное время за день может отстать на несколько часов, а прокрутка экрана на терминале может стать причиной потери нажатий клавиш. На A/UX, System V Unix от Apple для Macintosh, писк динамика приводит к потере данных последовательного порта.

3.5. Фрагментированная системная память

По умолчанию ядро предполагает, что физическая память состоит из одного непрерывного блока. Однако некоторые архитектуры компьютеров обладают фрагментированной физической памятью и в ядре BSD есть код, который это учитывает. Например, IBM PC обладает оперативной памятью, начинающейся с физического адреса 0, но ПЗУ и BIOS находятся по адресу 640k. Следовательно, дополнительная память за ПЗУ должна начинаться с физического адреса 1024k.

В случае фрагментированной памяти нужно определить константу препроцессора MACHINE_NONCONTIG и добавить в модуль pmap.c три функции. Функция pmap_next_page() должна возвращать начальный физический адрес "следующей" страницы памяти. При первом вызове эта функция должна вернуть наименьший физический адрес памяти. При следующем вызове она должна вернуть начальный адрес следующей страницы (обычно на 4096 байт больше) и так далее, пропуская "дыры" в физической памяти. Функция pmap_page_index() должна возвращать количество страниц по указанному физическому адресу, а pmap_free_pages() должна возвращать количество оставшихся свободных страниц. Примеры реализации этих трёх функций можно увидеть в переносах на i386 и Macintosh.

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

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

В BSD нет строго определённой роли драйвера устройства, но обычно драйвер должен обеспечивать минимально необходимое взаимодействие с оборудованием. Проектировщик драйвера устройства (а в действительности - модуля ядра) должен спросить себя, какие функции драйвера должны находиться в ядре, а какие - в пользовательской прорамме. Хотя в случае некоторых программ это решение даётся просто (например, X Window или драйвер последовательного порта), в случае с некоторыми модулями ядра могут быть аргументы за оба места. Например, SL/IP (Serial Line Internet Protocol - IP через последовательную линию) реализован в ядре BSD, но кто-то может спросить, должен ли заботить всех пользователей вес модуля, которым пользуется всего несколько человек и который поэтому почти так же эффективно может быть реализован в виде демона. Подобным же образом в виде демонов на уровне пользователя, к которым обращается ядро, могут быть реализованы и редко используемые файловые системы.

На Macintosh видеодисплей реализован как растровое устройство и не имеет аппаратной поддержки шрифтов. Наш видеодрайвер (ITE) с поддержкой быстрой отрисовки шрифтов разного размера на разных видеокартах с разными размерами дисплеев, с эмуляцией VT220, поддержкой указателя мыши, копирования и вставки, виртуальных терминалов, обратной прокрутки и т.д. получился довольно большим. После долгого обсуждения члены команды решили, что этот драйвер стал напоминать оконную графическую программу и потому не должен находиться в ядре. Весь код (за исключением самой простой поддержки маленького шрифта и VT220) был перемещён в программу dt (сокращение от desktop), которую пользователь может запустить после входа. Она предоставляет пользователям все возможности, которые у них были бы, если бы код находился в ядре, но при необходимости её можно выгрузить, изменить настройки в процессе работы, что позволяет облегчить разработку и отладку, использовать больше памяти для буфера обратной прокрутки. Его вынос был верным решением, хотя это было не так очевидно, когда он поначалу был реализован в ядре. Любое дополнение к ядру должно быть тщательно изучено и обосновано во избежание разрастания ядра, потому что необходимость в скорости, которую даёт компоновка с ядром, возникает редко.

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

4.1. Последовательный порт

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

4.2. ITE

Большинство компьютеров подключаются к видеомонитору, который можно использовать в качестве системной консоли. Этот монитор может быть растровым или символьным, но в любом случае ядро отвечает за отображение символов и эмуляцию простого терминала, например VT220. Для этого обычно используют файл ite.c (internal terminal emulator - внутренний эмулятор терминала). Компьютеры с растровым экраном используют код из переноса на Amiga (если целевой компьютер имеет аппаратную поддержку графических операций) или из переноса на Macintosh (если нет). Если разрабатываемый перенос имеет символьный экран, тогда лучшим выбором для начальной основы будет перенос на i386. Код эмуляции VT220 можно скопировать из большинства любых переносов и довольно легко реализовать в виде конечного автомата.

4.3. Диск (SCSI)

У компьютеров с интерфейсом SCSI в ядре есть два уровня кода для работы с дисками. Файл scsi.c отвечает за низкоуровневые сообщения и команды SCSI, а файл sd.c (SCSI-диск) отвечает за разделы, блоки и порядок доступа к диску. Недавно в проекте NetBSD большая часть высокоуровневого кода для работы со SCSI-дисками была перемещена в машинно-независимый каталог, поэтому вероятнее всего для нового переноса потребуется написать только код для работы с адаптером.

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

4.4. Клавиатура

Написание драйвера клавиатуры имеет довольно низкий приоритет, потому что на начальном этапе переноса в качестве консоли можно использовать драйвер последовательного порта. Если интерфейс к оборудованию клавиатуры прост, то драйвер можно поместить прямо в ite.c, вместе с драйвером экрана. Обычно возвращаемые от оборудования данные - это коды клавиш, которые нужно преобразовать в ASCII, учитывая активны ли клавиши Shift, Control и Caps Lock. Иногда также может быть полезно реализовать поддержку недокументированных сочетаний клавиш для особых задач вроде перезагрузки компьютера или отображения системной таблицы процессов.

Если на клавиатуре есть клавиша Alt или Command, то можно обрабатывать её как клавишу Meta. Например, если пользователь нажал Alt-E, то драйвер клавиатуры должен симулировать нажатия клавиш <ESC><E>. Это полезно для программ вроде Emacs, которые используют клавишу Escape для симуляции клавиши Meta.

5. Подготовка продукта

Фредерик Брукс говорил, что создание системной программы в три раза сложнее, чем создание программы и что создание системного продукта в три раза сложнее, чем создание системной программы [2]. Так как выпущенная система BSD - это системный продукт, на неё должно потребоваться в девять раз больше работы, чем на обычную программу! Разработчики должны не только написать программу для установки и документацию, они также должны общаться с пользователями с несовместимым оборудованием или теми, кто не читает документацию и устанавливает программное обеспечение некорректно. В этом разделе представлен обзор нескольких инструментов, которые необходимы для выпуска переноса BSD.

5.1. Newfs

Сначала у пользователя есть компьютер, на котором предположительно уже есть операционная система. Ему нужно создать новый раздел на диске для BSD (от 40 до 50 мегабайт), один раздел для подкачки (по меньшей мере вдвое больше размера физической оперативной памяти) и отформатировать раздел BSD. Создавать разделы лучше инструментами, имеющимися в составе предустановленной операционной системы, но для форматирования скорее всего потребуется специальная программа. Исходный код программы newfs находится в дереве дистрибутива BSD, поэтому создание программы форматирования раздела сводится к переносу newfs на предустановленную операционную систему. При этом могут возникнуть проблемы, зависящие от того, насколько предустановленная операционная система похожа на BSD.

5.2. Программа установки

Двоичные файлы каждого из переносов могут распространяться по-своему, но проще всего воспользоваться сценариями, предоставленными группой NetBSD. Эти сценарии генерируют набор tar-файлов, которые можно скачать и установить поотдельности для получения рабочего дерева. Например, чтобы увидеть что система грузится, нужно установить только bin.tar, sbin.tar и ядро, т.к. init находится в /sbin, а оболочка находится в /bin. В частности, это может пригодиться пользователям, которые не уверены, что перенос работает на их конфигурации оборудования.

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

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

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

5.3. Сервер FTP

Нужно разместить файлы дистрибутива и документацию на сервере FTP, который допускает анонимный доступ и на котором есть место для сжатых tar-файлов (примерно 20 мегабайт). Убедитесь, что разместили на сервере файл с именем README, в котором чётко объясняется, где взять остальную документацию и к кому можно обратиться с вопросами.

В настоящее время запрещено экспортировать из США код BSD для шифрования паролей. Сценарий, генерирующий файлы дистрибутива, должен размещать весь код шифрования в отдельном tar-файле. Остальной код можно загружать кому угодно, но пользователи без tar-файла с поддержкой шифрования будут хранить свои пароли открытым текстом. Убедитесь, что чётко объяснили и на сервере FTP и в файле README, что скачивать tar-файл с поддержкой шифрования за пределы США запрещено законом. Вот пример уведомления, размещённого на домашнем сайте NetBSD sun-lamp.cs.berkeley.edu:

EXPORT CONTROL NOTE: ЗАМЕЧАНИЕ ОБ ОГРАНИЧЕНИИ ЭКСПОРТА:
Non-U.S. ftp users are required to follow U.S. export control restrictions, which means that if you see some DES or otherwise controlled software here, you SHOULD NOT copy it. Look at README.export-control (in / and most other directories) to learn more. (If the treaty between your country and the United States did not require you to respect U.S. export control restrictions, then you would not have Internet connectivity to this host. Check with your U.S. embassy if you want to verify this.) Пользователям сервера FTP за границей США требуется соблюдать экспортные ограничения США, которые подразумевают что если вы заметили здесь DES или другое программное обеспечение, на которое наложены ограничения, вы НЕ ДОЛЖНЫ копировать его. Обратитесь к файлу README.export-control (в каталоге / и других каталогах) чтобы узнать больше. (Если договорённости между вашей страной и США не требуют соблюдать экспортные ограничения США, то у вас не должно быть подключения к этому узлу сети Интернет. Для проверки информации свяжитесь с посольством США.)

5.4. Список рассылки

Как только пользователи начнут скачивать дистрибутив, они захотят оставаться в курсе изменений и обновлений. Группа NetBSD поддерживает списки рассылок и вы можете попросить их создать новый список рассылки для вашего переноса. Кто угодно сможет написать электронное письмо на адрес port-название@netbsd.org (где название - это название переноса), чтобы задать вопрос или помочь остальным.

5.5. FAQ

У большинства новых пользователей возникают одинаковые вопросы, поэтому полезно поддерживать на сервере FTP список часто задаваемых вопросов (Frequently Asked Questions - FAQ). При помощи программного обеспечения почтовой рассылки на netbsd.org можно отправлять короткое сообщение пользователям, присоединившимся к рассылке. Это сообщение может содержать ссылку на FAQ для уменьшения количества повторяющихся вопросов в списке рассылки. FAQ должен быть снабжён датой последнего обновления, списком вопросов и ответов и ссылкой на дистрибутив на сервере FTP для тех, кто получил FAQ из другого источника и хочет убедиться, что имеет дело с самой свежей версией.

Сообщество Linux недавно начало использовать для своей документации SGML (Standard Generalized Markup Language - стандартный обобщённый язык разметки). Документацию, написанную в SGML, можно автоматически преобразовать в обычный текст, в форматы troff, HTML, LaTeX и Texinfo. Программы для преобразования можно найти в каталоге /pub/Linux/docs на sunsite.unc.edu.

5.6. Интеграция и улучшения

Перенесённый код должен впоследствии попасть в официальное дерево NetBSD. Обратитесь в рассылку core@netbsd.org за инструкциями о том, как это сделать. Кроме того, полезно синхронизироваться с изменениями из других переносов, чтобы ваш перенос извлекал пользу из идей и исправлений ошибок в их машинно-зависимом коде. Подпишитесь на список рассылки source-changes, отправив сообщение "help" на majordomo@netbsd.org.

Ссылки

  1. Bach, Maurice J.

    The Design of the UNIX Operating System3

    Englewood Cliffs, New Jersey: Prentice Hall, 1986

  2. Фредерик Брукс

    Мифический человеко-месяц, или Как создаются программные системы4

    СПб: Символ-Плюс, 2000

  3. Leffler, Samuel J., M. Kirk McKusick, Michael J. Karels, and John S. Quarterman

    The Design and Implementation of the 4.3BSD UNIX Operating System5

    Reading, Massachusetts: Addison-Wesley Publishing Company, 1989

Примечания переводчика

  1. Слово "компернелфобия", предположительно, происходит от английского complexity kernel phobia - страх перед сложностью ядра.
  2. Этот абзац пришлось перефразировать, чтобы не тянуть в перевод кальку "бутстраппинг". Вместо неё использовано слово "раскрутка", относящееся к похожему процессу создания компилятора языка, умеющего компилировать самого себя. См. статью в Wikipedia: Раскрутка компилятора.
  3. В сети имеется широко растиражированный неофициальный перевод книги, выполненный кандидатом технических наук Кафедры Вычислительной техники Санкт-Петербургского Института Точной Механики и Оптики Крюковым А. В.: 1, 2, 3.
  4. Книга неоднократно переводилась и издавалась на русском языке. Первое издание: "Ф. П. Брукс мл. Как проектируются и создаются программные комплексы, М.: Наука, 1979". Самое свежее издание на момент подготовки этого документа: "Фредерик Брукс: Мифический человеко-месяц, или Как создаются программные системы, СПб: Питер, 2021".
  5. В последующем выходило обновлённое издание этой книги с описанием системы 4.4BSD: "Marshall Kirk McKusick, Keith Bostic, Michael J. Karels, John S. Quarterman, The Design and Implementation of the 4.4BSD Operating System, Addison-Wesley Longman, Inc, 1996". Потом авторы переключились на описание операционной системы FreeBSD, как наиболее популярной ветви развития BSD. На русском языке выходила книга "Маршалл Кирк МакКузик, Джордж В. Невилл-Нил. FreeBSD. Архитектура и реализация, М.: КУДИЦ-Образ, 2006" с описанием FreeBSD версии 5.2.

Автор перевода на русский язык: Владимир Ступин