Это такое 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 :) Файловое API внутри себя работает в юникоде, т.е., всё знает, только не всегда может сказать юзеру о реальном имени файла ;) Если с помощью команды CHCP выбрать подходящую кодовую страницу (из небольшого числа имеющихся), то имя файла будет отображаться правильно (вместо кучи ???). Пример реакции на CHCP. Русские буквы на скриншоте - результат загруженного шрифта (см. ниже), в BIOS, понятное дело, их нет :) Впрочем, отсутствие какой-то кодовой страницы не мешает копировать файлы с помощью copy *.*, имена будут переноситься в юникоде. Единственная проблема - в HPFS, поскольку он хранит имена файлов не в юникоде, а одной из кодовых страниц, список которых хранится на разделе. Если QSINIT этой кодовой страницы не знает, то будет применять некую "по умолчанию" (850). Это позволяет скопировать файл на тот же FAT, но оригинальное имя, разумеется, будет утеряно (заменено на кракозябры). Помимо всего этого, есть команда VHDD, которая работает с "файлдиском" своего формата. Предназначена, в основном, для тестирования - но варианты полезного использования тоже есть (монтирование iso, vhd, итп). |
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 и проверять ;) В комплекте идут шрифты 10x20 и 8x14 с русской 866 кодовой страницей (8x14 из-за того, что минимум в половине биосов он просто битый) и 9x19 с 850й. Шрифты 8(9)x16 используются из биоса (в 437 странице, очевидно). |
Процессы и треды
В какой-то момент показалось естественным добавить функциональность "нормальной системы", а именно сессии, процессы, треды и прочая. По умолчанию этот режим выключен - и включается только с "толкача" (команды 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 и лайками. Можно считать это ностальгией по старому доброму творческому процессу и временам, когда компьютеры уже не были большими, но ещё и не стали маленькими ;). Не знаю - хорошо ли получилось, но потраченного времени, в общем, не жаль :) Развлекайтесь и вы ;) |