В 2026 году написать операционную систему с нуля — это либо академическое упражнение, либо попытка решить реальную проблему. OptimaOS — второе: проект исследует, можно ли построить одно ядро, которое без форкинга и переписывания обслуживало бы десктоп, сервер, Edge и AI-устройство одновременно. В этой статье — мотивация, архитектурные решения и статус проекта.

Почему в 2026 году кто-то пишет новую ОС

Ядра, на которых работает большинство современного железа, — Linux (1991), Windows NT (1993), Darwin (2001) — написаны в эпоху, когда о memory safety никто особо не думал, а слова «edge computing» и «AI accelerator» звучали как научная фантастика. Эти системы решают свои задачи хорошо — но несут 30+ лет технического долга и архитектурных решений, принятых в совершенно других условиях.

Конкретная проблема, которая меня беспокоила: фрагментация через форкинг.

  • Android — это форк Linux с тысячами кастомных патчей, которые upstream годами не принимает

  • Embedded Linux — ещё один набор форков под конкретные SoC-и от каждого вендора

  • RTOS для IoT/Edge — как правило, отдельные кодовые базы с несовместимыми API

  • AI-ускорители живут под своими специализированными стеками с минимальной совместимостью

Итог: вместо одной хорошо проверенной, аудированной кодовой базы — зоопарк форков с разным уровнем безопасности, разными системными вызовами и разным поведением в граничных случаях. Каждый форк — это отдельный security-аудит, отдельная команда, отдельный регресс.

Гипотеза OptimaOS: можно построить одно ядро, которое через механизм runtime-профилей обслуживает принципиально разные сценарии — без форкинга исходного кода.

Механизм vs политика: ключевое архитектурное решение

В операционных системах есть классический принцип, сформулированный ещё в работах UNIX: ядро должно предоставлять механизмы, но не диктовать политику. На практике большинство ядер этот принцип нарушают — туда просачиваются решения, которые правильнее было бы оставить userspace’у.

В OptimaOS это разграничение проведено жёстко и зафиксировано в архитектурном решении ADR-0002:

Что живёт в ядре (механизмы, неизменны для всех конфигураций):

  • Управление памятью (регионы, mmap/munmap/protect)

  • Планировщик процессов и потоков

  • IPC-шина с типизированными endpoint’ами

  • Capability-граф (права доступа к ресурсам)

  • Syscall ABI (optima_syscall_v0)

Что живёт в профилях (политика, меняется runtime):

  • Правила политик (какой процесс что может делать)

  • Конфигурация userspace-сервисов (запускать ли сетевой стек, с какими параметрами)

  • Параметры планировщика (latency vs throughput)

  • Разрешённые syscall-паттерны

Практически это выглядит так: бинарный образ ядра один и тот же для десктопного home-профиля и серверного server-профиля. При старте загружается соответствующий policy-файл, и policy-service применяет его поверх ядра через runtime API. Никакой пересборки ядра, никакого форкинга.

Это не новая идея — похожий подход используется в seL4 и некоторых RTOS. Но в сочетании с Rust и современным toolchain’ом результат получается интересным.

Почему Rust

Выбор Rust для системного программирования в 2026 году уже не требует долгих обоснований — Microsoft, Google, Linux kernel, Android открыто говорят о переходе. Но для нас конкретные причины были следующими:

1. Memory safety без GC. Ядро не может позволить себе garbage collector. Rust даёт compile-time гарантии отсутствия dangling pointers, use-after-free, buffer overflow — без рантайм-оверхеда. Это не просто удобство, это требование к TCB (Trusted Computing Base).

2. #[forbid(unsafe_code)] как политика. В kernel-core это не рекомендация, а запрет на уровне компилятора. Весь unsafe-код изолирован в HAL-слое (hardware/mod.rs) и явно аннотирован. Количество unsafe-строк можно посчитать за минуту.

3. Ownership model отлично ложится на capability-модель. Capabilities в OptimaOS — это токены владения ресурсами. Rust ownership и lifetime semantics естественно выражают те же инварианты на уровне типов.

4. Toolchain и экосистема. cargo test, cargo build --target x86_64-unknown-uefi, встроенная поддержка no_std — инфраструктура для написания ОС из коробки намного лучше, чем была в C 30 лет назад.

Архитектура OptimaOS

Проект организован как Rust workspace с несколькими crate’ами:

kernel-core/        — единственный execution engine, всё ядро здесь
linux-compat/       — Linux ABI bridge (L1/L2 staged)
policy-service/     — userspace policy manager
device-manager/     — userspace device manager
filesystem-service/ — userspace filesystem service
network-service/    — userspace network service
profile-service/    — userspace profile overlay service

Важный момент: policy-service, device-manager и остальные сервисы не зависят от kernel-core как от библиотеки. Они общаются с ядром через typed IPC + capabilities — ровно так, как должно быть в микроядерной архитектуре. Только linux-compat явно зависит от kernel-core, потому что реализует маппинг Linux syscall’ов на optima_syscall_v0.

Ключевые модули и их назначение:

Ключевые модули и их назначение:

Модуль

Назначение

runtime.rs

KernelRuntime — state machine жизненного цикла, главный execution engine

syscall.rs

Syscall ABI (optima_syscall_v0), структура Kernel

ipc.rs

In-memory queue IPC с типизированными endpoint’ами и owner PID

memory.rs

Регионы памяти, mmap/munmap/protect

scheduler.rs

Планировщик процессов и потоков

capability.rs

Граф capabilities, grant/revoke/transfer

policy.rs

Policy rules, overlays, per-PID overrides

audit.rs

Audit trail, экспорт и верификация событий

console_transport.rs

Transport v1 (UEFI shim ↔ runtime)Console Transport: двухслойная архитектура

Console Transport: двухслойная архитектура

Это одно из нетривиальных решений, зафиксированных в ADR-0003. UEFI shim и kernel runtime разделены явным транспортным протоколом:

  • Stage A (UEFI shim): transport + diagnostics только. Пересылает input-события в runtime, рендерит output. Не исполняет команды.

  • Stage B (kernel-core runtime): единственная точка исполнения команд. Все sys.* команды обрабатываются здесь.

Жизненный цикл: BootInit → ShimReady → RuntimeAttach → Interactive → Degraded

Смысл такого разделения: UEFI-код работает в привилегированном режиме с доступом к boot services. Если дать ему возможность исполнять команды напрямую, boundary между boot и runtime размывается, и аудировать систему становится сложнее. Строгое разделение позволяет верифицировать каждый слой независимо.

Linux ABI совместимость: зачем и как

Самописная ОС без совместимости с существующим ПО — это интересный эксперимент, но не более. Поэтому linux-compat реализует маппинг Linux syscall’ов на optima_syscall_v0 в несколько этапов:

L1 (реализовано): clone, exit, nanosleep, mmap, munmap, sendmsg, recvmsg, минимальные сигналы, минимальный epoll.

L2-A (реализовано): fd lifecycle (open/close/read/write), dup/dup2, poll/epoll_wait.

L2-B (реализовано): signal masks, pending queue.

L2-C (реализовано): epoll_ctl(DEL/MOD), расширенная epoll-семантика.

Важная оговорка: Linux bridge API помечен как draft — это не стабильный публичный ABI, совместимость не гарантируется между версиями до явного объявления стабильности.

Почему поэтапно, а не всё сразу? Потому что каждый новый syscall — это расширение attack surface. Сначала верифицируем L1, потом L2. Каждый этап закрывается compatibility matrix тестами.

Что дальше

Ближайшие технические задачи в порядке приоритета:

  1. Физическое device bring-up — загрузиться на реальном x86_64, пройти on-device smoke тесты, зафиксировать реальные perf-числа.

  2. Linux L2 completion — завершить L2-C и начать расширенные signals (signalfd/eventfd).

  3. Android L2 — маппинг Android Binder IPC на optima_syscall_v0 (в backlog, после L2).

  4. Win32 L3 — самый сложный слой, далёкая перспектива.

  5. Unicode + image rendering в GUI framework.

Глобальная цель — проверить гипотезу: один kernel binary, работающий с разными профилями на десктопе, сервере и Edge-устройстве. Если это реализуемо без деградации производительности — интересно идти дальше.

Заключение

OptimaOS — это рабочий прототип, а не продукт. Но за этим прототипом стоит конкретная архитектурная гипотеза о разделении механизмов и политик, о runtime-конфигурируемости вместо форкинга, о Rust как фундаменте для ядра с верифицируемой memory safety.

Результаты пока обнадёживают: ядро компилируется и тестируется детерминированно, Linux ABI совместимость реализуется поэтапно без нарушения syscall контракта, xHCI драйвер работает под QEMU. Следующий серьёзный рубеж — реальное железо.

Если вам интересна тема проектирования ядер, Rust systems programming или Linux ABI совместимость — буду рад обсудить конкретные технические решения в комментариях. Особенно интересны взгляды тех, кто работал с seL4, Zephyr или L4-микроядрами — есть что сравнить.

Проект находится в активной разработке. Исходный код пока не опубликован — планирую сделать это после достижения вменяемой работоспособности.