Итак, Тетрис QSINIT. Что это?

Это такое 32-битное нечто, которое формально можно назвать небольшой OS (для которой можно писать приложения) и которое (попутно) является загрузчиком ядра OS/2.
А "Тетрис" потому, что самым первым приложением и был тетрис.

 И как вообще до этого дошло? ;)

Всё началось с частичного участия в проекте реверса осевого ядра - под названием OS/4 ;) В его рамках есть свой штатный загрузчик ядра, внешне похожий на исходный от IBM.
Основная проблема в том, что это практически COM файл - т.е. файл размером < 64k, со сложной внутренней структурой, который обязан делать кучу дел, но умещаться, при этом, в один 16-битный сегмент.

После долгих войн за каждый байт (когда я ещё принимал участие в этом), пришла в голову мысль написать нечто более удобное для практических задач. А таких задач на загрузке может быть масса:
  • выбрать ядро и запустить его с теми или иными параметрами
  • посмотреть разбивку памяти машины, девайсы на PCI шине, итд
  • сменить активный раздел на диске, создать/удалить раздел
  • запустить какой-то иной загрузчик или загрузку с произвольного раздела диска
  • поискать данные на дисках, отредактировать, снять/поставить dirty флаг разделу
  • сменить буквы дисков для LVM, починить LVM информацию
  • написать что-то, требующее прямого доступа к железу и хоть какого-то системного окружения
  • итд, итп
Всё ограничено только временем и фантазией. Ну и возможностями BIOS, поскольку он выбран в качестве "драйверов".
Промежуточным итогом аж 13 (к июню 23-го) лет творчества является QSINIT в нынешнем его виде :)

Бинарно - это два файла: OS2LDR и QSINIT.LDI, которые надо положить в корень загрузочного диска - всё.

 Стартовать можно:
  • с HPFS/JFS, родных для OS/2 - для бутсектора он ничем не отличается от загрузчика IBM
  • с FAT/FAT32/exFAT, в этом случае надо заменить код бутсектора раздела
  • по PXE с TFTP сервера (см. ниже)
  • с CD/DVD - в no-emulation mode
  • EFI версия - как обычное EFI приложение/загрузчик
  • с дискеты :) (да, оно ещё работает)
Установка на FAT/FAT32/exFAT никак не связана с OS/2, в этом случае QSINIT грузится своим кодом бутсектора.
Загрузка поддерживается и на 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, либо один из вариантов меню:
  • выбор ядра для загрузки (BIOS)
  • выбор раздела для загрузки (BIOS)
  • выбор EFI модуля для старта (EFI)
  • меню собственных приложений

 Меню выбора ядра

Слегка пугающий пример из подопытной виртуальной машины, в нормальных случаях такого меню не требуется ;)
Kernel selection

Стрелка вправо вызывает диалог настроек ядра, там можно изменить много всякого, включая название самого файла ядра.

Для особых ценителей - запустить загрузку можно и из шелла, командой BOOTOS2 :)


 Меню приложений

В отдельной установке (без OS/2) оно показывается сразу после загрузки.
Все пункты меню просто вызывают команды шелла или отдельные приложения, его содержание целиком настраиваемо.
Apps menu
Вместо Enter можно нажать Ctrl-Enter и команда меню скопируется в строку редактирования новой копии шелла, чтобы что-нибудь в ней изменить ;)

В одном из подменю прячется тетрис:

в другом - просмотр простого и детального списка PCI девайсов, всяческих таблиц BIOS, списка доступных в VESA (или EFI) графических режимов, таблицы памяти PC и тому подобного ...

в третьем монтирование и размонтирование разделов для самого QSINIT и старт шелла в отдельной сессии.

Disk management тут - вызов диалога работы с дисками, о нём ниже.

В подменю "Reboot" прячется несколько способов загрузить что-нибудь ещё:
Boot any partition - выбор загрузки с любого раздела (если там есть что грузить, конечно ;),

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 можно описать список загрузочных разделов - чтобы получилось вот такое меню (ядовитые цвета вполне настраиваемы ;)
Kernel selection

Это меню можно сделать стартовым - и вместо загрузчика 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
Apps menu

Это меню будет стартовым по умолчанию в EFI версии, если в QSINIT.INI присутствует его описание.



 Из любого меню доступны:
  • F3 - шелл QSINIT
    Шелл - это просто шелл :) (на скриншоте команда, с помощью которой эти скриншоты сделаны)

    Довольно простой шелл, без многих фич. Отсутствует, например, привычное перенаправление ввода/вывода, итд.
    Но совместимость с типичным DOS-Like шеллом вполне приличная.
    Пример dir /w /s:

    Всякий мелкий сервис тоже в наличии (Ctrl-Left/Right, история команд по стрелкам/PgUp, относительно полная справка по командам, итд).

    Вопрос может вызвать странное имя диска: 1:\ на некоторых старых скриншотах (отдельным добрый десяток лет ;).

    Оно связано с позаимствованным из старых версий FatFS (см ссылку в конце текста) альтернативным наименованием дисков: 0:..9: вместо A:..Z:
    A:..Z: тоже поддерживаются.

    Эти буквы дисков - своё монтирование QSINIT, они никак не связаны с буквой диска LVM и OS/2.
    • A: - всегда загрузочный раздел. Если этот раздел - FAT/FAT32/exFAT, то он примонтирован автоматически, с полным доступом (чтение/запись).
      Если это HPFS, JFS или ISO9660 - тоже самое, но доступ только для чтения.
    • B: - виртуальный диск с приложениями QSINIT (после старта это содержимое архива QSINIT.LDI). Это рамдиск, т.е, свободное место у него - вся доступная память
    • диски C:..Z: - буквы свободные для монтирования разделов жестких дисков и/или флешек (если биос/фирмварь их видит).
      Монтирование не сохраняется между перезагрузками. Выполнить его можно командой mount, из меню или в Disk Management.

    Ну, собстно, опцией можно выставить автоматическое монтирование по буквам осевого LVM, но это будет каждый раз замедлять загрузку на время требуемое для монтирования разделов. Диск A: в этом случае всё ещё загрузочный раздел, который попутно замаплен и на свою родную букву при помощи команды SUBST.

    Если вы долго мечтали написать FORMAT C: - теперь это возможно ;) Монтируем любой ненужный раздел на C: и вперед.
    Это, кстати, вполне актуально - например отформатировать в exFAT с 512k кластером - для свалки фильмов ... или просто отформатировать раздел в любой тип FAT на "дисковом" диске с Advanced Format (формат по умолчанию выравнивает начало обеих копий FAT и области данных на 4k сектора физического диска).

    Смена буквы LVM тоже есть, но отражается она только в OS/2:

    Синтаксис командных файлов довольно типичен ;)
    Пример рабочего cmd файла:
    xcopy.cmd text

    Забавный пример использования был когда умерла батарейка CMOS и часы при включении всегда показывали 01/01/2002.
    В магазин идти далеко и лень, поэтому целую неделю оно спрашивало дату и время как когда-то на PC XT:
    if NOT "%date%"=="01.01.2002" goto timeok
    date /s
    time /s
    :timeok
    

  • F5 - вызовет SysView (см. ниже).

  • F7 - показывает в консоли список разделов всех видимых через BIOS дисков.
    Поддерживаются и MBR и GPT (для дисков больше 2Tb, могут быть проблемы в старых биосах).

    Примеры - BIOS версия, 2 диска и уже созданный PAE рамдиск (см. ниже):

    EFI версия, загруженная с системного EFI раздела на GPT флешке (второй диск - CD с каким-то мусором, эмулируемый самой флешкой, третий - GPT с HPFS разделом ;))   

  • F8 - внутренний лог.
    Он же доступен через компорт и отдельную команду в консоли.

  • F10 / Alt-F10 - сбросит текстовый режим на дефолтный или предложит выбор.



 SysView

Это такое "сборное" приложение, написаное на старом добром Turbo Vision, куда добавляется всё, что требует "обширного интерфейса" ;)
Мыши нет, но диалоги не так уж велики и проходятся кнопкой Tab.

Тут собрана работа с дисками (см. ниже), штатный текстовый редактор (оригинальный из Turbo Vision), простой бинарный редактор, разные меню загрузки, поиска, копирования секторов, калькулятор, просмотр лога, CPU/BIOS info и просмотр/редактирование физ.памяти:

Диалог CPU info делался из тестовых соображений (хоть кто-то помнит в деталях все фичи всех новых моделей процессоров? ;)
Ниже в нём же - немного информации о биосе из DMI.


 Работа с дисками

Полный список разделов на всех дисках можно вызвать прямо из меню приложений - кнопкой F7.

В более удобном виде оно присутствует в диалоге Disk Management в SysView. И есть команды шелла, которые делают то же самое.

Что вообще можно делать:
  • монтировать FAT/FAT32/exFAT разделы, читать/писать на них.
  • монтировать HPFS/JFS разделы и читать с них. Файлы > 4Gb поддерживаются, т.е. вполне реально скопировать их с JFS на exFAT, например.
  • ISO-9660, по крайней мере, при загрузке с него. В EFI версии должны быть видны все диски. Есть поддержка multi-extent (level 3), т.е. можно скопировать 20-гиговый файл с br на exFAT
  • монтировать любые другие разделы и форматировать их в FAT/FAT32/exFAT/HPFS/JFS.
    Свой код бутсектора на HPFS не зависит от наличия осевой MBR/BM/AirBoot, можно прописать его на любой HPFS раздел. Свой код бутсектора для JFS тоже ни от чего не зависит, но некоторые промежуточные версии осевого CHKDSK настолько кривы, что лучше этот код не использовать (CHKDSK восстанавливает часть секторов загрузчика на исходный вариант).
  • создавать и удалять разделы в MBR и GPT формате разбивки.
  • инициализировать чистый диск, прописывая ему пустую MBR и OS/2 LVM инфо (при желании) - или GPT,
    конвертировать MBR диск в GPT
  • работать с OS/2 LVM:
    • обновлять данные LVM после создания раздела за пределами OS/2
    • записывать служебные LVM сектора (DLAT) на диск, если их там нет
    • ставить/менять букву диска LVM, менять текстовое имя диска/раздела
    • в редакторе секторов можно непосредственно покопаться в DLAT секторе, если вы, конечно, знаете, где он находится ;) Диалог сам пересчитает CRC после изменений
  • клонировать данные диска целиком или пораздельно. Для этого есть диалоги в Disk Management или консольная команда "dmgr clone".
    QSINIT ничего не знает о содержании разделов, но прямое копирование не должно нарушить ничего важного в файловой системе ;) (стартовый номер сектора в BPB клонирование всё-таки апдейтит)
  • бэкапить/восстанавливать структуру разделов диска (без данных)
  • снимать/ставить Volume Dirty для FAT и HPFS разделов
Чтение с FAT/exFAT в QSINIT кэшируется. Кэш работает без отложенной записи, чтобы не создавать лишних проблем, загрузочный раздел не кэшируется вообще - по этой же причине :)

Образцом производительности кэш не является, но с ним копирование с диска на диск (с помощью 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 в качестве первого всё-таки можно, но с некоторыми предосторожностями:
  • Windows надо ставить на primary раздел
  • Линукс может быть загружен из GRUB в бутсекторе его раздела
  • Менеджером загрузки можно использовать QSINIT, для него потребуется небольшой primary FAT/FAT32 раздел, который надо сделать активным
    (с тем же успехом это может быть и exFAT со свалкой фильмов на 500 га ;)).
  • Код MBR (опционально) можно заменить
В итоге - все живут счастливо (кроме DOS, для которого битый CHS фатален по определению).


 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 - тут доступна почти вся наличная функциональность

Пример: много свободного места, надо его как-то применить
Free space

Создаём небольшой (100 Gb) раздел в конце:
Make small
остальное честно делим пополам:
Make step 2 Make step 3

Форматируем наш небольшой (100 Gb) раздел в FAT32, но по глупости выбираем Long format.
Quick здесь - быстрый формат, без чтения поверхности, Long - чтение (поиск бэдов), Wipe - запись старого доброго байта F6 на весь диск.
Long format

ждём... ждем... ну его нафиг, долго:
Formatting... Break format

Выбираем Quick, готово:
Format ready

Метка диска сейчас спрашивается тут же, но эти скриншоты сделаны когда этого ещё не было (этим же объясняются различия в строке меню ;))


 Посекторный редактор диска

Ближайший аналог этого редактора - diskedit из NU (опять же, кто-то помнит? :))
Функциональность сравнительно небольшая - редактирование, копирование/заполнение секторов, запись в файл и из файла, поиск по диску и возможность посмотреть сектор в виде MBR / бутсектора:

При боязни пробовать редактор на реальном диске - объектом издевательств может служить (PAE) рамдиск. Образ диска из команды VHDD тоже подходит.

На скриншоте в списке доступных для редактирования - загрузочный раздел и два физических диска, в фоне - MBR сектор
(строчка %QS% в начале сектора - это исполняемый код, несущий функциональную нагрузку - если что ;)
Edit virtual disk

Ищем строчку на диске, в данном случае описание точки монтирования в регистри Windows XP:
Search on disk Searching...
Все найденные позиции заносятся в историю поиска и по ней можно откатиться назад.


 Графика

Все полуосевики знают "панораму" - драйвер 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 могут изучить регистры до и после установки:
MTRR with no WC MTRR with WC on

С учётом того, что поддержка 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, сигналы, итд, итп

Тасклист в двух переключаемых формах - список процессов и список сессий:
Process list Session list
Такое странное деление объясняется тем, что экранная сессия это свойство треда, а не процесса. Т.е. тред может создать сессию и переключиться в неё или вообще её не иметь.

Пример команды 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:
  • архивируем нашу аврору в rar, с EA (QSINIT EA не поддерживает)
  • архивируем небольшую ось, с текстовым шеллом в ZIP и кладём её на TFTP сервер (ей не нужен EA и её можно распаковать на FAT)
  • загружаемся по PXE, разбиваем QSINIT-ом диск на разделы, назначаем LVM буквы, форматируем небольшой раздел под FAT16 (или используем PAE рамдиск из следующего пункта).
  • распаковываем на этот раздел ZIP с TFTP сервера и ставим QSINIT командой sys - первая полуось есть :)
  • копируем с TFTP сервера rar с реальной системой (всё тем же QSINIT)
  • грузим эту микро-ось и уже в ней распаковываем rar (с EA) на будущий системный раздел, sysinstx - готово :)
Конечно, всё это можно проделать и более простыми способами ;) - но возможность обойтись без флешки (и без драйвера сетевой карты!) - в любом случае не помешает. Тем более, что во всех встроенных картах (реалтек, атерос) PXE есть и, обычно, работает.
Ну и, как минимум, по 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 фирмвари):
поскольку в EFI нет ни слова об этом (сочиняли, ж, его исходно под неудавшийся IA64). Точно так же - прямым патчением таблиц - ловятся и исключения.
В общем, век (якобы) новый - а методы всё те же ;)


 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 сервер из примера выше - отладка на реальном железе может происходить ещё интересней:
  • грузитесь по PXE, запускаетесь и зависаете ;)
  • прибиваете старую версию вашего процесса через тасклист
  • копируете новую с TFTP сервера обычной командой copy
Цикл можно повторять до трапа/исключения (и то если лень было поставить try..except на критичный участок ;)

Например, код работы с AHCI для нового OS2DUMP отлаживался именно так. Он вешался и оставлял контроллер в непонятном состоянии, но система оставалась рабочей, как и копирование по PXE - и свежей копии предоставлялась героическая задача всё это разрулить ;)


 Несколько замечаний по выбранным решениям

Общие принципы функционирования "системы" QSINIT:
  • исполняемые модули: обычные EXE файлы в формате LE или LX.
  • общее "плоское" адресное пространство.
  • ring 0, полный доступ ко всем ресурсам.
  • отсутствие мультитредности по умолчанию. Процесс может сделать exec потомка и только, в точности как это было в DOS.
  • DLL модули и их данные - глобальны и шарятся всеми использующими их процессами.
  • система состоит из 2 файлов :) Загрузчик - файл размером ~40-50k и zip архив с модулями и данными.
  • загрузчик может быть запущен из FSD механизма загрузки OS/2 (FAT, HPFS, JFS, PXE загрузка) или просто загружен и запущен на исполнение кодом бутсектора FAT/FAT32/exFAT раздела.
  • для работы в качестве основного диска используется небольшой виртуальный диск в памяти, куда и распаковывается zip архив.
  • высокая степень модульности. Отдельные подсистемы - расширенная консоль, кэш, поддержка мультитредности, работа с разделами дисков - опциональны и могут быть удалены без заметного вреда для прочей функциональности.
Причины именно таких решений:
  • общее адресное пространство:
    • простота и универсальность реализации (всё-таки, изначально это не ОС).
    • размер кода загрузки модулей и обслуживания защищённого режима.
    • совместимость с моделью памяти UEFI.
  • загрузчик:
    • наличие загрузчика определено логикой работы FSD механизма OS/2.
    • он обеспечивает минимальные сервисы: переход в PM, вызов реального режима, работу с памятью, загрузку LE/LX модулей, unzip.
    • в сумме этот набор сервисов умещается в 50k, являющиеся лимитом для файла типа OS2LDR - и предоставляет всё нужное для запуска прочих модулей.
    • содержимое в zip:
      • позволяет сократить "систему" до минимально необходимого числа файлов - двух ;)
      • встроенная проверка целостности модулей (crc32 zip файла). Встречались ситуации, когда SSD диск возвращал мусор при чтении в PIO режиме, без всякой ошибки.
      • сокращение размера читаемой информации (с диска или по сети в случае PXE).
      • простой для модификации в любых условиях формат архива.
  • виртуальный диск:
    • "система" работает на "обычном диске", с чтением и записью. Все приложения и данные, соответственно - файлы на нём.
    • возможность бездисковой работы (PXE загрузка).
  • LX/LE модули:
    • определяется необходимостью загрузки ядра OS/2 (LX модуль).
    • формат поддерживает 16-битные сегменты, переходы 16<->32, оптимизацию хранения фиксапов и проч.
  • Turbo Vision:
    • наиболее внятная оконная библиотека для текстовых режимов.
    • быстрота написания интерфейсов и диалогов (стоит учитывать ограниченность доступных человеко-часов ;).


 Копирайты и прочее

Лицензия, под которой распространяется код - несовместима с GNU, соотвественно в продукте нет ни строчки стороннего GNU кода. Это означает, также, что ни один юниксоид при написании QSINIT не пострадал ;)

Из стороннего кода использованы:
  • старый добрый PMODE, который был доступен в исходниках в дремучих 90х
  • FatFs by ChaN - для доступа к FAT/FAT32/exFAT. Неплохо отлаженный код FAT, используемый на куче платформ. Код форматирования сделан на его базе
  • небольшой фрагмент zlib для распаковки архивов
  • Turbo Vision, отданный Борландом (светлая ему память) в public domain.
    Для портирования был взят "народный" код, бродивший в FIDO лет дцать назад и якобы использовавшийся в IDA.
    Число авторов исправлений там довольно велико (как и косяков после них ;) ).
Остальное содержимое QSINIT - шелл, загрузка модулей, загрузка ядра, треды, консоль, итд - написаны с нуля. Код доступен в виде исходников в SDK.

И последний вопрос - а зачем всё это, не лучше ли iOS и ондроид? ;) Ответ прост - скучно :)
Когда всё готово, когда кругом ява и C++ и 100500 мегабайт памяти и каждый чих увешан вызовами MySQL и лайками.
Можно считать это ностальгией по старому доброму творческому процессу и временам, когда компьютеры уже не были большими, но ещё и не стали маленькими ;).

Не знаю - хорошо ли получилось, но потраченного времени, в общем, не жаль :)
Развлекайтесь и вы ;)

Автор.

p.s. свежие версии обычно тут: FTP, HTTP.