Этап 6 Supervisor, пакет программ и восстановление службы
Прямая ссылка на отчёт
Историческая запись: команды и пути сборки ниже показывают состояние на дату этапа. Для текущего размещения исходников, тестов и актуальных команд используйте PROJECT_STRUCTURE.md.
Завершён 3 ноября 2026 года для QEMU q35/TCG, одного x86-64 CPU. Проверены 64/128 МиБ RAM. Версия компилятора остаётся GSL 0.0.12: для этого этапа понадобились новые действия и протоколы на GSL, без новых конструкций синтаксиса.
Работающий сценарий
В CPL3 запускаются три программы с отдельными CR3: клиент PID 1, диагностическая служба PID 2 и supervisor PID 3. Supervisor принимает решения о запуске и повторном запуске. Ядро проверяет его управляющее право, поколение службы, допустимый пакет, паузу и лимит. Автоматического перезапуска внутри планировщика нет.
Обычная сборка выполняет следующую проверку:
- Из read-only пакета загружаются клиент и supervisor. Клиенту пока не выдано право отправки службе.
- Supervisor запускает диагностическую службу из того же пакета. Клиент явно запрашивает подключение и получает право первого поколения.
- Служба читает разрешённый ресурс пакета и отвечает на IPC-запрос. Затем по отдельной проверочной операции намеренно выполняет запрещённый переход к адресу 0.
- Ядро изолирует #PF 14/error 20 в службе. Клиент получает PEER_CLOSED, supervisor — отдельное уведомление с причиной и поколением. Клиент и supervisor сохраняют свои адресные пространства.
- Немедленный повторный запуск отклоняется с BACKOFF. После пяти тиков supervisor запускает новый экземпляр. Старые десять страниц службы освобождаются до выделения новых.
- Новая служба получает очищенную память и новую эпоху точки приёма. Клиент запрашивает подключение к поколению 2. Старый дескриптор отклоняется, новый отвечает на свежий запрос.
- Клиент отдельно запрашивает штатное завершение службы. Supervisor получает уведомление о завершении; затем программы заканчивают самопроверку, ресурсы очищаются.
Сбойный запрос автоматически не воспроизводится. Supervisor не переносит повреждённое состояние службы в новый экземпляр. Служба проверяет нулевой начальный маркер в своей странице данных и заново читает ресурс. Это проверка восстановления одной статeless диагностической службы, не произвольного драйвера или файловой системы.
Полномочие и протокол управления
Supervisor — пользовательская программа apps/supervisor.gsl. Его управляющий объект привязан к защищённой записи процесса. Числовой token сам по себе не даёт права: запрос от клиента или службы с тем же token отклоняется. Пример запрета проверяется из обеих программ.
Внутренние слоты ядра: 0 — клиент, 1 — служба, 2 — контроллер проверки, 3 — idle, 4 — supervisor. Пользовательский PID supervisor равен 3. У него отдельный стек входа в ядро и собственные страницы; всего теперь 28 guard pages стеков ядра.
| Syscall |
Операция |
Ограничения |
| 13 |
Запустить пакет службы: token, package ID, ожидаемая эпоха |
Только supervisor, только пакет 2, совпадение эпохи, допустимое состояние, пауза и лимит |
| 14 |
Подключение: service ID, 64-байтный buffer, ожидание |
Только клиент; ожидается поколение новее указанного в buffer |
| 15 |
Уведомление: token, buffer, ожидание |
Только supervisor; очередь из восьми событий |
| 16 |
Прочитать ресурс: ID, buffer, доступная длина |
Ресурс 4 разрешён службе и supervisor, клиенту запрещён |
Syscall 3 со стороны supervisor выполняет ограниченный сон в его собственной записи ожидания. IPC клиента и службы продолжает использовать контракты этапа 5. У supervisor пока нет третьей IPC-точки: управляющие уведомления идут отдельным ограниченным протоколом ядра.
Запись подключения сообщает эпоху, новый локальный дескриптор клиента, PID службы и ID пакета. Запись события содержит тип exit/fault, ID службы, эпоху, состояние, vector/error, адрес fault и номер события. Ожидания ограничены ста тиками и используют idle/HLT, когда готовых программ нет.
Ошибки управления: DENIED=−40, LIMIT=−41, BACKOFF=−42, UNAVAILABLE=−43, BAD_PACKAGE=−44 в представлении u64. Неверная эпоха возвращает STALE; попытка запуска уже работающего экземпляра — FULL/занято. Указатели проверяются по собственной странице данных вызывающего процесса.
Разрешены два успешных запуска службы за проверочный runtime, включая первый. Неверные права и пакет не расходуют этот лимит. Перед повторным запуском выдерживается пять принятых тиков. После второго сбоя дальнейший запуск отклоняется с LIMIT, ожидающий клиент получает определённый отказ. Это ограничитель текущей конфигурации, не готовая общая политика восстановления.
Read-only пакет GUSEVAP1
Пакет bundle.gub встроен в RO/NX-секцию образа. Он содержит три программы GUP1 и один ресурс. Загрузка и проверка выполняются на GSL в supervisor.gsl; Python только собирает пакет на машине разработки.
Заголовок: восемь little-endian u64 — magic GUSEVAP1, версия 1, размер заголовка 64, четыре записи, размер каталога 256, начало данных 320, общий размер, флаги 0. Запись каталога занимает 64 байта: ID, тип, смещение, длина, FNV-1a-64, маска роли, флаги 0 и резерв 0.
| ID |
Объект |
Разрешённая роль |
| 1 |
Клиент GUP1 |
Клиент |
| 2 |
Диагностическая служба GUP1 |
Служба |
| 3 |
Supervisor GUP1 |
Supervisor |
| 4 |
Ресурс GUSEVA16, 8 байт |
Служба и supervisor |
Проверяются версия, размеры, ID, типы, разрешённые роли, отсутствие пересечений и лишних данных, границы, выравнивание и checksum каждого объекта. Программы дополнительно проходят GUP1-проверку. Общий пакет ограничен 64 КиБ. Полномочия определяет политика ядра; изменение роли в каталоге не создаёт новое право.
В обычной сборке пакет занимает 18744 байта. FNV здесь обнаруживает повреждение; он не является подписью и не аутентифицирует издателя. Доверие к встроенному пакету следует из доверия к загруженному EFI-образу. Secure Boot, обновления пакетов и внешние хранилища пока не реализованы.
Программа и ресурс загружаются по каталогу пакета, а не через Windows loader в гостевой ОС. ELF/PE user.exe на хосте остаётся промежуточным результатом сборки. Пользовательского API записи в пакет нет; аппаратные права RO/NX проверяются вместе со всеми секциями ядра.
Память, поколения и очистка
На программу по-прежнему выдаётся десять страниц: четыре таблицы, код, данные и четыре страницы стека. В максимуме одновременно работают три такие программы — тридцать страниц. При одном восстановлении суммарно выделены и освобождены сорок страниц: клиент 10, supervisor 10, два экземпляра службы по 10.
Старый CR3 службы уже не активен, когда supervisor вызывает повторный запуск. Очистка выполняется на CR3 supervisor, после чего GSL-загрузчик создаёт новый экземпляр. Физические адреса могут использоваться повторно; идентичность службы задаётся эпохой и правами, а не адресом страницы.
Таблицы прав IPC и поколения tickets не обнуляются при восстановлении. Старый SEND-дескриптор клиента освобождается, его слот получает новое поколение. В обычном прогоне старое значение 65794 заменяется на 131330; после замены старое возвращает STALE. Повторное подключение выполняется только по запросу клиента.
Для диагностики перед освобождением сохраняются запись и страницы первого экземпляра в защищённый буфер 40 КиБ внутри образа. Это позволяет независимо проверить права, старое содержимое и владение страницами, даже если allocator повторно выдал те же адреса. Буфер недоступен пользовательским программам. Нулевой начальный маркер нового экземпляра проверяется самой службой и нативным тестом загрузчика.
После проверки отсутствуют живые IPC-права, requests и ожидания, очередь supervisor пуста, все выдававшиеся страницы возвращены PMM. Остаётся одна прежняя контрольная страница менеджера памяти. Снимок первого экземпляра — фиксированная диагностическая память ядра, не динамическая утечка.
Проверки
Прошли 46 автоматических тестов: 26 компилятора и 20 инфраструктуры ядра. Новый нативный тест исполняет GSL-код проверки пакета, авторизации, эпохи, backoff и лимита, очистки, загрузки свежей памяти и подключения. Повреждённые заголовки, checksum, роли, перекрывающиеся записи и некорректная программа отклоняются. Сохранены прежние 2000 операций PMM, 500 состояний планирования и 500 IPC-обменов.
Прошли 33 сценария QEMU: обычные 64/128 МиБ, полное исчерпание/восстановление PMM с 64/128 МиБ, три дополнительных сценария supervisor, восемь IPC-вариантов, одиннадцать прежних пользовательских проверок и семь аварий ядра.
| Supervisor-вариант |
Запусков / повторных |
Результат |
| recover, обычная сборка |
2 / 1 |
Первый экземпляр fault, явное подключение к новому, штатное завершение |
| exit-recover |
2 / 1 |
Первый экземпляр штатно завершается без ответа; новый обслуживает клиента |
| restart-limit |
2 / 1 |
Два fault, третьего запуска нет, клиент получает LIMIT |
| no-fault |
1 / 0 |
Три программы завершаются штатно без восстановления |
supervisor_check.py независимо декодирует фактически загруженный пакет, все три текущих адресных пространства и сохранённый первый экземпляр. Проверяются реальные кадры CPL3, неизменность кода, допустимые изменения данных, маркеры очищенной памяти, ресурс из пакета, поколения, события и причина fault, пауза, подсчёт syscall/IRQ всех воплощений и очистка. Намеренно испорченные снимки не проходят проверку.
Сохраняются W^X, CR0.WP, EFER.NXE, TSS/IST, блокировка FP/SIMD, отсутствие пользовательского доступа к ядру и всех лишних отображений. PMM отдельно сверяется с картой UEFI и полной битовой картой после очистки. Подтверждены исходный CR3 контроллера, IF=0 и замаскированный PIC.
В обычной сборке: три программы, четыре объекта пакета, два запуска службы, один повторный запуск, два подключения, один намеренный fault, 45 syscall и 40 освобождённых страниц. На backoff приходится пять idle-тиков. При 128 МиБ PMM содержит 19691 страницу, при 64 МиБ — 3307; после проверки занята одна контрольная страница.
Размер EFI — 146944 байта, загруженного образа — 1011712, дискового образа — 17825792. Это размеры текущего прототипа, не оценка готовой ОС.
Доказательства: build/supervisor-report.json, supervisor-state.bin, embedded-bundle.gub, first-service-pages.bin, снимки трёх процессов и таблиц, memory-report.json, protection-report.json и boot-report.json. Сводка всех прогонов — STAGE6_VALIDATION.json. Старые отчёты описывают соответствующие архивные версии.
Повторение
python outputs/guseva-kernel/build.py
python -m unittest discover -s outputs/gsl-compiler -v
python -m unittest discover -s outputs/guseva-kernel -v
python outputs/guseva-kernel/test_boot.py
python outputs/guseva-kernel/run.py
Отдельный вариант:
python outputs/guseva-kernel/build.py --supervisor-case restart-limit
python outputs/guseva-kernel/test_boot.py --build outputs/guseva-kernel/build-supervisor-restart-limit
Прежний обычный IPC-прогон теперь вызывается явно: --ipc-case exchange, папка build-ipc-exchange. Пользовательские и аппаратные аварийные варианты сохраняют прежние аргументы.
После сборки окно нужно закрыть и открыть заново. Экран STAGE 6 показывает результаты проверки; затем CPU намеренно останавливается. Supervisor пока не остаётся постоянной фоновой службой после завершения демонстрации.
Границы
Три фиксированные целочисленные программы, одна восстанавливаемая stateless-служба, один read-only пакет с фиксированным каталогом, ограниченный управляющий объект. Нет общего spawn, службы имён, файловой системы с записью, state transfer, восстановления произвольного драйвера, обновлений и пользовательских квот. Следующий этап — учёт и ограничения ресурсов компонентов.
Восстановление служб имеет известные аналоги, например reincarnation server MINIX. Здесь реализованы собственные действия GSL и явный протокол смены поколения с ограниченным повторным запуском; абсолютная новизна механизма не утверждается.