Краткое содержание: разработка модуля совместимости с ОС Колибри внутри модуля совместимости с ОС Юникс внутри ОС Фантомь)
Внутри ОС Фантом есть маленький простенький Юникс. POSIX подсистема. В принципе необязательная для работы самого Фантома и довольно неполная — Unix Quake под ней собрать удалось, а, например, апач не соберётся почти наверняка. Тем не менее — она есть.
Чтобы продолжить, надо понимать, что такое ОС Колибри. Колибри — обрусевший западный проект микро-операционки на ассемблере. Собственно, это описание довольно полно. Над Колибри работают фанаты программирования на ассемблере x86, она, соответственно, непереносима и, к сожалению, очень плохо спроектирована. Очень — это катастрофически. Для понимания масштаба бедствия — нет никакого общего механизма определения успешности или ошибочности системного вызова. Для некоторых определить несупех просто невозможно, некоторые вызовы возвращают свой личный набор кодов ошибок, некоторые — какой-то другой.
Почему же, тем не менее, любопытно реализовать слой совместимости с этой ОС? Тому несколько причин:
- Она очень компактна. Забегая вперёд — первую программу для Колибри в Фантоме удалось запустить через четыре часа работы.
- Этот мини-проект стал драйвером развития некоторых нативных подсистем Фантома,
в частности — оконной. - Главное — всё состояние процесса Колибри, известное ядру, укладывается в небольшую структуру. Многие (почти все!) вызовы — stateless, то есть не опираются о какое-либо знание,
хранимое в ядре. Это идеальный кандидат на реализацию персистентных (переживающих перезапуск ОС) бинарных (не написанных на байткод-языке) процессов в Фантоме.
Собственно, разработка слоя совместимости делится на несколько очевидных частей:
- Загрузчик исполняемого образа
- Точка входа в системный вызов
- «Прокладки» для системных вызовов, конвертирующие их в семантику существующих компонент системы
- Разработка недостающей функциональности
Загрузчик образа Колибри тривиален, за исключением реализации запуска запакованных программ. К сожалению, реализация распаковки по имеющимся фрагментарным спекам к успеху не привела, и найти кого-то, кто разбирается, не удалось. Непакованные программы устроены очень просто, так что детектирование и загрузка образа дополнили существующий elf-овский загрузчик без проблем. Кстати, под Фантом программы для Колибри можно компилировать и обычным elf-овским тулчейном — вне зависимости от того, какой загрузчик загрузил программу, она может обращаться и к системным вызовам POSIX, и к Колибри. Можно вперемешку )
Точка входа тоже ничего неожиданного не представляет — вызовы делаются через программное прерывание, обычный IDT gate и небольшой ассемблерный трамплин решают задачу.
Основная работа, конечно, это реализация системных вызовов. Работа трудоёмкая по двум причинам — во-первых, вызовы документированы схематично, во-вторых, их создатели реально не утруждали себя какой-либо консистентностью. Для примера — вызов запроса информации о процессе в одном из полей возвращает… номер другого процесса, окно которого находится в заданной z-позиции на экране.
Реализация вызовов делалась по принципу «типа TDD»: вместо реализации системного вызова просто пишем в лог ошибку, запускаем прикладные программы, если вызван не реализованный системный вызов, реализуем то, что было вызвано. Так что если колл не сделан, значит я не дошёл до прикладной программы, которая в нём нуждается.
В целом вызовы делятся на несколько групп.
Информационные
С ними всё просто. Ещё и потому, что часть информации можно выдать в константном или фейковом виде. Хороший пример — st->eax = dummy++; // TODO n of context switches
— возрастает, и ладно. Где возможно, конечно, информация выдаётся реальная.
Low-level
Колибри — система почти без защиты, процесс может очень много, в том числе — модифицировать регистры процессора, обычно доступные только ядру. Большинство таких вызовов, конечно, просто не реализованы.
Файловые операции
Файловые операции Колибри более-менее консистентны (как минимум, коды ошибок одни и те же), но реализация их весьма дорогостояща — все они не хранят в ядре практически никакого состояния и, де факто, сводятся к группе open / do / close. То есть, чтение из файла на каждый вызов выполняет открытие и закрытие файла. В принципе, это можно попробовать оптимизировать через hash map имени файла и держать пул открытых дескрипторов, но в скоуп проекта выходного дня это уже не входит. Я не делал. В остальном реализация более-менее тривиальна.
Графика
Тут я ожидал проблем. Они и были, но, в основном не столь жуткие, как могло бы случиться. Впрочем, есть ощущение, что представления авторов графической подсистемы Колибри до конца я всё равно не постиг — некоторые программы работают нормально, некоторые — странно. Увы, без того, чтобы реально читать исходники оригинальной реализации, наверное, прогресс тут невозможен, а исходники, я напомню, на ассемблере. Я не нашёл в себе достаточно куража, и остановился на том, что какое-то подмножество программ работает нормально.
Главное отличие графики Колибри в том, что ядро реализует часть традиционно прикладных компонент окна — в частности, кнопки. Готовой ответной части в оконной системе Фантома не было, пришлось писать. Очевидно, прикладной код Колибри жёстко завязан на конкретные шрифты, применённые в ядре — шрифты пришлось извлечь и конвертировать в формат оконной подсистемы Фантома, плюс несколько доработать код визуализации шрифтов. Были и другие мелочи, в целом несущественные.
Реализовано, но не протестировано
Колибри поддерживает несложный механизм IPC — почтовые ящики. Он реализован схематически, но подробному тестированию не подвергался. Реализован также запуск дополнительных тредов процесса — тоже без серьёзного тестирования. Кстати, не вполне очевидно, какая часть состояния ядра должна относиться к процессу, а какая к треду.
Отсутствует
Полностью не реализованы функции управления отображением памяти — в настоящее время ядро Фантома работает только с одним адресным пространством (процессы Юникса и Колибри поддерживаются через механизм сегментной адресации x86), поэтому их не на что отображать. В силу этого же факта трудно (хотя и можно) реализовать изменение размера адресного пространства процесса. Не реализована поддержка DLL -сама Колибри ими пользуется очень неактивно, а план был в том, чтобы сделать минимум необходимого. Впрочем, это не представляется сложным.
Развитие проекта
Довольно очевидно, что для продолжения работ требуется:
- Набор регресс-тестов. Желательно в виде а) внутренних юнит-тестов для компонент;
б) специальных тестовых прикладных программ и в) прогона существующих программ с контролем их работоспособности. - Ревью кода опытным разработчиком ядра Колибри на предмет соответствия реализации оригиналу
- Ревью кода на предмет подробной верификации всех точек входа Колибри-Фантом на предмет допустимости и осмысленности параметров.
В общем, нужен герой из команды разработчиков ОС Колибри. I need a hero :)
Автор: dzavalishin