Это такое 32-битное нечто, которое формально можно назвать небольшой
OS (для которой можно писать приложения) и которое (попутно) является
загрузчиком ядра OS/2. А "Тетрис" потому, что самым первым приложением и был тетрис. |
И как вообще до этого дошло? ;)
Всё началось с частичного участия в проекте реверса осевого ядра - под названием OS/4 ;) В его рамках есть свой штатный загрузчик ядра, внешне похожий на исходный от IBM. Основная проблема в том, что это практически COM файл - т.е. файл размером < 64k, со сложной внутренней структурой, который обязан делать кучу дел, но умещаться, при этом, в один 16-битный сегмент. После долгих войн за каждый байт (когда я ещё принимал участие в этом), пришла в голову мысль написать нечто более удобное для практических задач. А таких задач на загрузке может быть масса:
Промежуточным итогом аж 13 (к июню 23-го) лет творчества является QSINIT в нынешнем его виде :) Бинарно - это два файла: OS2LDR и QSINIT.LDI, которые надо положить в корень загрузочного диска - всё. |
Стартовать можно:
Загрузка поддерживается и на MBR и на GPT дисках, на последних FAT/FAT32 раздел должен начинаться ниже границы в 2Tb (32-битный стартовый сектор раздела). В EFI версии и при старте с FAT32/exFAT - загрузка ядер OS/2 не поддерживается, но сам QSINIT вполне применим для разных тестовых/сервисных задач (в т.ч. с написанием нативных приложений под него). Это же касается CD/DVD - прямая загрузка OS/2 невозможна, но возможна косвенная, через ramdisk (см. ниже). Минимальные требования к железу для BIOS версии - 486dx и 24Mb (16 сходу резервируются для раскладывания осевого ядра, поэтому так много). |
Что внутри?
Небольшая 32-битная "система". Формат модулей - LX, компилятор - ватком.
Приложения хранятся во втором файле - QSINIT.LDI, это обычный zip.При загрузке в памяти создаётся виртуальный диск с его содержимым, затем запускается либо загрузка ядра OS/2, либо один из вариантов меню:
|
Меню выбора ядра
Слегка пугающий пример из подопытной виртуальной машины, в нормальных случаях такого меню не требуется ;) ![]() Стрелка вправо вызывает диалог настроек ядра, там можно изменить много всякого, включая название самого файла ядра. ![]() Для особых ценителей - запустить загрузку можно и из шелла, командой BOOTOS2 :) ![]() |
Меню приложений
В отдельной установке (без OS/2) оно показывается сразу после загрузки. Все пункты меню просто вызывают команды шелла или отдельные приложения, его содержание целиком настраиваемо. ![]() Вместо Enter можно нажать Ctrl-Enter и команда меню скопируется в строку редактирования новой копии шелла, чтобы что-нибудь в ней изменить ;) В одном из подменю прячется тетрис: ![]() в другом - просмотр простого и детального списка PCI девайсов, всяческих таблиц BIOS, списка доступных в VESA (или EFI) графических режимов, таблицы памяти PC и тому подобного ... ![]() в третьем монтирование и размонтирование разделов для самого QSINIT и старт шелла в отдельной сессии. ![]() Disk management тут - вызов диалога работы с дисками, о нём ниже. В подменю "Reboot" прячется несколько способов загрузить что-нибудь ещё: ![]() Boot Manager - это не прямой его вызов, а своя обработка данных LVM. Самого BM уже может не быть, но если в LVM данных указано, что раздел включён в меню - он попадёт в список. Наличие этого пункта - исключительно дань истории. Пункт "Boot iPXE" появляется только если вы допакуете в QSINIT.LDI файл IPXE.PXE от iPXE. Точно также можно грузить какой-ньть GRLDR из GRUB4DOS (только меню придётся менять самостоятельно). Reboot / Power off - перезагрузка или выключение PC. Выключение на BIOS хосте работает только через APM, которого давно нет на ноутбуках и в EFI биосах. В команде POWER шелла есть возможность и suspend, но работающий APM suspend - это зверь из красной книги ;) Хотя есть редкие биосы, где он функционирует (на асусах, по крайней мере). В EFI версии вызывается EFI фирмварь (тоже проблемная вещь - если ребут работает всегда, то выключение - далеко не факт). |
Меню загрузки разделов (BIOS версия)
В файле QSINIT.INI можно описать список загрузочных разделов - чтобы получилось вот такое меню (ядовитые цвета вполне настраиваемы ;) ![]() Это меню можно сделать стартовым - и вместо загрузчика OS/2 QSINIT становится загрузчиком разделов ;) Ось, XP, Win7, Linux у которого GRUB в бутсекторе раздела - работают без возражений. Дополнительно можно указать файл бутсектора (например от DOS из XPшного NTLDR или самого NTLDR) и включить clock modulation (снижение частоты на Интеле). В качестве основного загрузчика может и не так удобно - но запасного - вполне ;) У загрузки есть небольшая проблема - A20 открыта - но с воплями умирают от этого только древние версии HIMEM.SYS под досом. Чуть менее древние (и сам дос) - грузятся. Ну и, в любом случае, для аварийной загрузки есть F2 -> Power off / reboot -> Boot any partition (см картинку выше) - альтернативный способ стартануть всё, что умеет грузиться из бутсектора раздела. |
Меню загрузки EFI модулей (EFI версия)
Аналогично меню разделов можно использовать QSINIT как простой EFI менеджер загрузки. Список для меню точно так же описывается в QSINIT.INI и ядовитые цвета можно изменить в menu.ini внутри архива QSINIT.LDI ![]() Это меню будет стартовым по умолчанию в EFI версии, если в QSINIT.INI присутствует его описание. |
Из любого меню доступны:
|
SysView
Это такое "сборное" приложение, написаное на старом добром Turbo Vision, куда добавляется всё, что требует "обширного интерфейса" ;) Мыши нет, но диалоги не так уж велики и проходятся кнопкой Tab. Тут собрана работа с дисками (см. ниже), штатный текстовый редактор (оригинальный из Turbo Vision), простой бинарный редактор, разные меню загрузки, поиска, копирования секторов, калькулятор, просмотр лога, CPU/BIOS info и просмотр/редактирование физ.памяти: ![]() Диалог CPU info делался из тестовых соображений (хоть кто-то помнит в деталях все фичи всех новых моделей процессоров? ;) Ниже в нём же - немного информации о биосе из DMI. ![]() |
Работа с дисками
Полный список разделов на всех дисках можно вызвать прямо из меню приложений - кнопкой F7. В более удобном виде оно присутствует в диалоге Disk Management в SysView. И есть команды шелла, которые делают то же самое. Что вообще можно делать:
Образцом производительности кэш не является, но с ним копирование с диска на диск (с помощью BIOS!) быстрее удивительного осевого драйвера FAT32, работающего через SATA/AHCI :) По умолчанию, доступ к FAT не поддерживает имена в национальных кодировках, но с помощью команды CHCP можно выбрать кодовую страницу (из небольшого числа имеющихся). Пример реакции на CHCP. Русские буквы на скриншоте - результат загруженного шрифта (см. ниже), в BIOS, понятное дело, их нет :) ![]() С exFAT всё ещё хуже - коротких имён там нет и при выключенной или несовпадающей кодовой странице имена в национальных кодировках просто неизвестны: ![]() Помимо этого, есть команда VHDD, которая работает с "файлдиском" своего формата. Предназначена, в основном, для тестирования - но варианты полезного использования тоже есть. |
500Gb и OS/2
Виноват в проблеме, как всегда, МежДелМаш aka IBM :) В IOCTL доступа к дискам чтение происходит не по LBA номеру сектора, а по дремучим значениям CHS, которые, к тому же 16-битные. В итоге, физический диск в OS/2 ограничен 65536 x 254 x 63 - примерно 512 гигабайтами пространства. Хитроумная фрау Даниэлла придумала решение - её DANIS стал отдавать CHS геометрию с числом секторов 127 и 255, вместо максимальных 63. Этого достаточно для дисков до 2Tb, но - таблица разделов, которую создаёт при этом LVM - некорректна по "классическим" канонам. Значения CHS там просто битые и некоторые бутменеджеры ругаются на неправильную разбивку диска. Однако, будучи вторым диском в системе - такой диск мирно уживается со всеми, поскольку LBA значения в таблице разделов вполне корректные. Пример этой разбивки (для диска размером 1 Tb - 60321 цилиндр и 127 секторов на трек). Видно, что первый раздел начинается на 127м секторе: ![]() Disk Management (описанный выше) при инициализации нового диска в MBR спросит о необходимости его работы с LVM и, при согласии, для больших дисков будет выбрана эта странная геометрия (127/255). Уже размеченные диски с нормальной геометрией превратить в такие не получится. Использовать диск больше 500Gb в качестве первого всё-таки можно, но с некоторыми предосторожностями:
|
2Tb и OS/2
Эта проблема куда глобальней, ибо 2Tb - это предел для 32-битного номера сектора. Чтобы его преодолеть - надо внедрять 64-битный номера сектора везде - начиная от драйверов устройств и кончая ядром. В ArcaOS оно решилось созданием GPT.FLT, который представляет каждый GPT раздел как отдельный диск и поддерживает API для их создания, удаления и монтирования. Единственное, что может сделать здесь загрузчик - уметь GPT саму по себе и грузиться с неё. Для загрузки с GPT потребуется заменить код MBR сектора на диске (в диалоге Disk Management) и установить загружаемому разделу флаг активного там же. После этого можно выбирать его загрузочным в BIOS. Единственное ограничение - раздел должен находиться ниже 2Tb - причина этому всё тот же 32-битный номер сектора, который используется для хранения стартовой позиции раздела в бутсекторе. В exFAT это поле 64-битное, поэтому можно загрузиться с GPT, из обычного BIOS - даже выше этого предела Пример загрузки с exFAT раздела с 256k кластером, расположенного в конце 3Tb диска (OS/2 в BIOS режиме так, к сожалению, не загрузишь). ![]() Но EFI загрузка в ArcaOS работает, поскольку дисковый вывод между загрузчиком и стартом GPT.FLT не используется, а затем загрузочный раздел становится обычным "32-битным" диском. Т.е. ваш любимый HPFS раздел с осью вполне может находиться в каком-нибудь 10м терабайте ;) |
Работа с разделами дисков
Эта функциональность, в принципе, рекомендуется к использованию только на чистых дисках ;) Т.е. она оттестирована за прошедшие годы и сам я пользуюсь только тетрисом при всех операциях разметки дисков, но кто знает - какие варианты глюков припасли многочисленные менеджеры дисков, которые лично мне не попадались :). Разделы создаются по "классическим" канонам - т.е. начало и конец выравнены на цилиндр. На MBR дисках, при создании раздела в конце свободного места можно добавить опцию AF выравнивания, в этом случае оно честно будет пытаться выравнять и на границу цилиндра и на 4k. На GPT выравнивание на 4k по умолчанию форсируется, поскольку там нет излишних плясок с CHS геометрией (создать невыравненный раздел тоже можно). Стоит отметить, что для FAT/FAT32/exFAT разделов это не нужно (если форматировать их в тетрисе). Формат сам выравняет обе копии FAT и начало кластеров данных на 4k. Создание primary чаще всего почти безопасно, logical - теоретически может убить все logical разделы на изменяемом диске - в силу специфики формата extended partition, но практически - этого не делает :) Да, и всегда есть LVM, miniLVM, dfsee и тьма партишнмагиков / fdisk-ов под другие платформы. Но как же не написать свой? ;) Так выглядит диалог Disk Management - тут доступна почти вся наличная функциональность ![]() Пример: много свободного места, надо его как-то применить ![]() Создаём небольшой (100 Gb) раздел в конце: ![]() остальное честно делим пополам: ![]() ![]() Форматируем наш небольшой (100 Gb) раздел в FAT32, но по глупости выбираем Long format. Quick здесь - быстрый формат, без чтения поверхности, Long - чтение (поиск бэдов), Wipe - запись старого доброго байта F6 на весь диск. ![]() ждём... ждем... ну его нафиг, долго: ![]() ![]() Выбираем Quick, готово: ![]() Метка диска сейчас спрашивается тут же, но эти скриншоты сделаны когда этого ещё не было (этим же объясняются различия в строке меню ;)) |
Посекторный редактор диска
Ближайший аналог этого редактора - diskedit из NU (опять же, кто-то помнит? :)) Функциональность сравнительно небольшая - редактирование, копирование/заполнение секторов, запись в файл и из файла, поиск по диску и возможность посмотреть сектор в виде MBR / бутсектора: ![]() При боязни пробовать редактор на реальном диске - объектом издевательств может служить (PAE) рамдиск. Образ диска из команды VHDD тоже подходит. На скриншоте в списке доступных для редактирования - загрузочный раздел и два физических диска, в фоне - MBR сектор (строчка %QS% в начале сектора - это исполняемый код, несущий функциональную нагрузку - если что ;) ![]() Ищем строчку на диске, в данном случае описание точки монтирования в регистри Windows XP: ![]() ![]() Все найденные позиции заносятся в историю поиска и по ней можно откатиться назад. |
Графика
Все полуосевики знают "панораму" - драйвер VESA, умеющий ставить Write Combine и показывать нормальный fps. Делал он это не всегда - долгие годы в коде жила ошибка, благодая которой Write Combine почти никогда не ставился на PC с размером памяти от 4Gb и выше. Проблема давно исправлена, но новые версии панорамы привязаны к новым версиям ACPI. У OS/4 ядрописаталей тоже какой-то свой, традиционно ни с кем не совместимый метод. Но никто не мешает нам поставить Write Combine самостоятельно, изменив MTRR регистры до старта ядра. Поскольку часть загрузчика остаётся резидентной - эти значения копируются и остальным ядрам после их старта. Для работы с MTRR в шелле есть одноименная команда, умеющая менять всё, что вообще возможно. Помимо установки Write Combine с её помощью можно, например, превратить PC в 386 - просто выключив кэш :) Наберите MTRR OFF. Или выставить WC памяти текстового режима (довольно стрёмная операция на многих типах карт, видеоэффекты непредсказуемы). Установка Write Combine автоматизирована - желающих посчитать его вручную, думаю, найти непросто ;). Записываем в файл qssetup.cmd (аналог autoexec/startup.cmd) в корне загрузочного диска строчку vmtrr и этот VMTRR прочитает из VESA (или EFI фирмвари) адрес видеопамяти, найдёт на PCI устройство, к которому она относится и поставит Write Combine на его полный диапазон адресов (видеокарты, очевидно). Из плюсов такого метода - сохранение установок для любой последующей загруженной не-SMP системы, не умеющей MTRR. Это особенно актуально для интелов начиная с 1156 сокета - где UC режим, стоящий на видеопамяти по умолчанию, стал особенно тормозным. Борцы с MTRR могут изучить регистры до и после установки: ![]() ![]() С учётом того, что поддержка VESA в QSINIT есть - есть и графические режимы. А раз так - почему бы не быть и графической консоли? ;) Был же заметен разный размер скриншотов выше? Здесь, например 128x51 (едва заметная зелёная стрелочка на него указывает): ![]() Возможна загрузка файла с битовым шрифтом (тех, что были в русификаторах доса когда-то). При добавлении такого шрифта все возможные режимы с ним автоматически добавляются в список (отсюда его длина ;). Любой из этих режимов может быть выбран в шелле при помощи "mode x,y" или "mode con id=..." (по его id). Есть и более гуманный вариант - через диалог: ![]() На древних VESA картах, где есть нативные текстовые режимы с шириной 132 символа - они тоже должны работать. Диапазон поддерживаемых видеокарт, по идее, должен начинаться с VESA 1.0, но мне реально лень искать в шкафу S3 864 и проверять ;) |
Процессы и треды
В какой-то момент показалось естественным добавить функциональность "нормальной системы", а именно сессии, процессы, треды и прочая. По умолчанию этот режим выключен - и включается только с "толкача" (команды start, stop, первый вызов тасклиста (Ctrl-Esc), итд). Мультизадачность в тетрисе довольно таки суровая, возможны длительные блокировки хотя бы на моментах обращения к диску, которые выполняются через BIOS или EFI. Однако, на практике можно спокойно Системное API умеет треды, фиберы (почти аналогичные виндовым), мутексы, эвенты, TLS, сигналы, итд, итп Тасклист в двух переключаемых формах - список процессов и список сессий: ![]() ![]() Такое странное деление объясняется тем, что экранная сессия это свойство треда, а не процесса. Т.е. тред может создать сессию и переключиться в неё или вообще её не иметь. Пример команды PS при двух активных сессиях. Видны системные треды в PID 1 (в т.ч. "system idle", который честно зовёт hlt, когда делать нечего). ![]() Команды шелла в этом режиме можно прервать нажатием Ctrl-C. Отдельный вопрос, пересекающийся с этим - экранные сессии и "девайсы". Под экранными девайсами понимается устройство для отображения, на данный момент всего два типа таковых - видеокарта и VT100 терминал через компорт. Можно создать несколько VT100 терминалов через разные компорты и каждый будет отдельным устройством вывода. Экранные сессии в свою очередь могут выводиться на одно или несколько устройств. Т.е, проще говоря - кто-то может играть в тетрис по COM-портовому соединению на вашем PC, а вы этого даже не заметите поскольку эта сессия видна только в терминальной консоли :) Вызов тасклиста индивидуален для устройства вывода, т.е. юзер в терминалке может переключать видимые ему сессии, пока вы переключаете свои. Если на экране режим 80x25, то нажатие Ctrl-Alt-F1 переключает дебужный компорт в устройство вывода (и назад). Пример с девайсом на COM2. Во время первой команды "sm list" на обоих "экранах" одна и та же сессия, во второй - разные. Вторая сессия в терминальной консоли не видна. ![]() Зачем такая сложная схема? Процессы требуют наличия сессий, а сессии, в свою очередь, некоей универсальной системы вывода. Экран, буфер для фоновых процессов и потенциально иные девайсы (VT100, как пример) - просто напрашиваются на свой уровень абстракции. На удивление, оно даже пригодилось ;) В EFI версии для ArcaOS, в промежутке когда EFI клавиатуры уже нет, осевой ещё нет, а потюкать в отладочных целях в шелле загрузчика ну очень хочется - терминальная консоль это единственное доступное средство (в этот момент нет ни bios, ни efi фирмвари, ни драйверов системы). |
PXE
Помимо загрузки с диска, QSINIT грузится и по PXE - при помощи пакета PXEOS4 от Моветона. Работает он, при этом, так же: читает свой ZIP с приложениями и распаковывает его на виртуальный диск, что позволяет, например, просмотреть конфигурацию бездискового PC. Собственно, одной из целей такой фичи был спортивный интерес - скопировать OS/2 (аврору, например) с другого PC вообще без применения флешек и инсталляционного CD :) Это реально, если сделать небольшую промежуточную копию системы (без PM), работающую на FAT:
Ну и, как минимум, по PXE можно скопировать эти самые драйвера для сетевой карты. Загрузить OS/2 по сети можно с помощью PXE из WSOD (но он, в отличие от PXEOS4, не позволяет запрашивать с TFTP сервера произвольные файлы). Однако, более простым способом является распаковка ZIP-а на PAE рамдиск, об этом ниже. |
PAE рамдиск
Известна неспособность оси работать с памятью выше 4Gb (ядро не умеет даже PAE). При этом, на обычном PC с 4Gb памяти - 500-700 метpов сходу пеpемаплены выше этой гpаницы. Т.е. "простая 32-битная система" видит 3-3.5 Gb памяти, а остаток доступен только 64-битной или умеющей расширенные страничные режимы (типа PAE). Но жаба-то душит, душит ;) Для лечения асфиксии в QSINIT добавлено создание "виртуального HDD" из этой памяти. Не только из этой, впрочем (можно частично или полностью использовать и обычную). Для этого диска есть BASEDEV драйвер для OS/2, который представляет его тем же отдельным HDD. Более того, с него можно загрузить систему. Т.е. кладём QSINIT и большой zip с системой на флешку (CD / TFTP сервер), стартуем оттуда, создаём виртуальный диск (гарантированного размера), распаковываем туда этот zip и запускаем с него загрузку. Диск может быть отформатирован в FAT/FAT32/HPFS/JFS (для последних двух, правда, нет записи - только форматирование). Можно просто использовать эту память как некое "посекторное хранилище" (что намного быстрее, чем работа через дисковый i/o). Правда, создание API шареного доступа к этому ещё ждёт своих героев ;) |
EFI версия
Существует EFI версия QSINIT. Это 64-битное EFI приложение, которое может запускаться из EFI шелла или просто как штатный загрузчик OS (bootx64.efi). В пару к нему в каталог /EFI/BOOT точно так же кладётся QSINIT.LDI (архив с модулями и данными). После старта всё работает индентично и 32-битные приложения мирно пасутся в 64-битном окружении. Мультизадачный режим работает точно так же. Единственная до сих пор не реализованная вещь - пищание PC спикера ;) По умолчанию QSINIT сразу пытается включить собственную графическую консоль, поскольку штатная и в коммерческих биосах и в TianoCore обычно черезмерно медленная. Вообще, EFI API местами убог в части интерфейса с пользователем - даже после свежих добавлений. Но это не мешает нам поиграть в тетрис ;) ![]() Загрузка OS/2 из EFI билда QSINIT невозможна - используйте ArcaOS ;) Тамошний EFI загрузчик базируется на этом, но с очень большим числом добавлений (выход в реальный режим, эмуляция биоса, предварительная загрузка драйверов, ремап PCI девайсов, чьи адреса назначены выше 4Gb и прочая экзотика). Эта EFI версия - просто некий утиль для аварийной починки/разбивки дисков и прочих подобных задач. Ну и простенький EFI boot менеджер. Внутренняя реализация, в принципе, содержит некое число стрёмных моментов - например, приходится подменять GDT (0000-0040 это селекторы EFI фирмвари): ![]() В общем, век (якобы) новый - а методы всё те же ;) |
SDK
Это нечто, что лежит на ftp - там полный код QSINIT и возможность при помощи одного ваткома, относительно прямых рук и традиционных заклинаний языка С писать всякие подручные программы ;) Делать это можно в оси, win32/64 и линуксе32/64 - если вы сумеете установить там линуксовый open watcom 1.9 ;) Например, создаём раздел прямо на границе 2Tb - чтобы проверить код бутсектора: #include "stdlib.h" #include "qsshell.h" #include "qsdm.h" void main(int argc,char *argv[]) { // create 40Gb GPT partition directly on 2TB border u32t disk = dsk_strtodisk(argv[1]); if (disk==FFFF) { printf("Invalid disk name (%s)\n", argv[1]); } else { // 32 sectors before 2Tb u32t rc = dsk_gptcreate(disk, 0xFFFFFFE0, 40*1024*1024*2, DFBA_PRIMARY, 0); if (rc) cmd_shellerr(EMSG_QS, rc, "Error: "); } }Прямо из makefile допаковываем результат в QSINIT.LDI - и можно пользоваться. Результат работы такой программы, отформатированный в FAT32 - на скриншоте в начале статьи. Отформатировать, кстати, его тоже можно прямо тут. Если у вас есть TFTP сервер из примера выше - отладка на реальном железе может происходить ещё интересней:
Например, код работы с AHCI для нового OS2DUMP отлаживался именно так. Он вешался и оставлял контроллер в непонятном состоянии, но система оставалась рабочей, как и копирование по PXE - и свежей копии предоставлялась героическая задача всё это разрулить ;) |
Несколько замечаний по выбранным решениям
Общие принципы функционирования "системы" QSINIT:
|
Копирайты и прочее
Лицензия, под которой распространяется код - несовместима с GNU, соотвественно в продукте нет ни строчки стороннего GNU кода. Это означает, также, что ни один юниксоид при написании QSINIT не пострадал ;) Из стороннего кода использованы:
И последний вопрос - а зачем всё это, не лучше ли iOS и ондроид? ;) Ответ прост - скучно :) Когда всё готово, когда кругом ява и C++ и 100500 мегабайт памяти и каждый чих увешан вызовами MySQL и лайками. Можно считать это ностальгией по старому доброму творческому процессу и временам, когда компьютеры уже не были большими, но ещё и не стали маленькими ;). Не знаю - хорошо ли получилось, но потраченного времени, в общем, не жаль :) Развлекайтесь и вы ;) |