Содержание

2.1. RTC. Транслятор уровня приложений.

Я уже упоминал ранее, что у МЦСТ есть аж целых 2 двоичных транслятора: RTC и Lintel. Как ни странно, они различаются по своим возможностям. Попробуем разобраться вкратце, в чём между ними разница.

Начнём с RTC. Есть суть в том, что он работает в уже запущенной Linux среде. Т.е. у нас есть уже запущенная система под E2K (будь то Эльбрус ОС, Альт Линукс или Астра Линукс), и внутри этой среды мы запускаем мини-среду x86, в которой у нас работает нужный нам x86 код.

Обычно утилита для запуска RTC лежит по адресу /opt/mcst/rtc/bin/rtc_opt_rel_p1_x64_ob. Вот только эта утилита не одна. Их тут 2. Есть /opt/mcst/rtc/bin/rtc_opt_rel_p1_x64_ob, и есть ещё /opt/mcst/rtc/bin/rtc_opt_rel_p1_ob. В чём между ними разница? Одна умеет работать с 32-разрядным x86 кодом (x86-32), а другая – с 64-разрядным x86 кодом (x86-64). И из этого вытекает множество различий.

Но для начала: а как вообще работает запуск этого кода? Да примерно также, как у Apple с их Rosetta 2. У вас x86 команды транслируются в аналогичные E2K команды, и всё это каким-то чудесным образом работает. Даже так скажу: по своей эффективности в целом RTC не уступает Rosetta 2 от Apple. Удивительная информация, и мы её разберём чуть подробнее в главе с тестами на C и C++. Сейчас же мы просто знакомимся с RTC и его возможностями, а также его ограничениями.

И интересно то, что Rosetta 2 от Apple также не транслирует одновременно и x86-64, и x86-32 код. Как эту проблема решила Apple? Перед выходом macOS 11, первой версии macOS, которая также включала поддержку архитектуры ARM, Apple ещё в macOS 10.13.4 стала предупреждать пользователей о скором прекращении поддержки 32-битных x86 приложений, а в macOS 10.15 эти самые 32-разрядные приложения как-раз таки и перестали работать. Заранее подготовив свою аудиторию к тому, что 32-разрядные приложения не будут работать с macOS 11, они сподвигли разработчиков ещё до выхода M1 адаптировать приложения под 64-bit.

У Apple с Rosetta 2 всё получилось просто превосходно, хоть и с рядом оговорок. Причиной тому стало то, что система macOS 11 для x86-64 (Intel) и ARM (Apple Silicon, M1) была едина. Если вы накатывали инсталлятор macOS 11 на флешку для последующей установки, вы могли заметить, что инсталлятор macOS 11 для обеих архитектур один и тот же. И получается, что, устанавливая macOS 11 на ноутбук с ARM, вы получали систему, которая содержала в себе компоненты для работы x86-64 системы. Остаётся только установить системный компонент Rosetta 2 и, вуаля, у вас работает трансляция. Любые зависимости, вызовы любых компонентов для работы вашего кода у вас не вызывали больших вопросов, т.к. работа за macOS с приложениями в режиме трансляции по своему опыту была схожа с работой за macOS на обычной x86 системе. Да, был косяк с тем, что системные API возвращали разные ответы на одни и те же команды, да, Apple переименовывала ID разных аппаратных блоков (в т.ч. блоков кодирования и декодирования видео), что ломало функции некоторых приложений (например, аппаратное кодирование видео в OBS), но в целом опыт был схож, т.к. все обращения у вас шли к нативному ядру в системе, и при этом вызывались ещё нужные компоненты для работы в x86 среде.

С Linux история несколько иная. Начать, думаю, следует с того, что многие Linux дистрибутивы уже давно отказались от поддержки x86-32 систем. В Ubuntu это случилось с выходом версии Ubuntu 18.04. И под свежие версии систем не формируются x32 сборки дистрибутивов, и для них не поддерживаются репозитории с x32 приложениями. Потому, по большому счёту смысла в использовании x32 дистрибутива в трансляции нет. Но есть один маленький, но немаловажный, нюанс, который мы все упускаем.

Если для запуска x86 Linux кода это не сулит особых проблем, т.к. в Linux среде давно уже полностью дистрибутивы собираются под x64, и софт собирается под x64, а x32 редко мелькает в x64 Linux среде (из коробки в x64 дистрибутивах вообще нет x32 ПО), то в Windows всё не так однозначно.

Дело в том, что в винде многие x86-64 приложения могут полагаться на x86-32 компоненты, доступные в т.ч. в качестве отдельных подключаемых модулей, отдельных дочерних процессов и с этим связано множество нюансов. Но проблемой это на винде не является. Почему же? Да потому, что в винде существует WOW64: подсистема, позволяющая в x64 Windows-среде запускать x32 приложения. Она довольно эффективна и идёт из коробки.

Но зачем я об этом всём рассказываю? Мы ведь думаем, как нам в Linux-среде на Эльбрусе запускать x64 приложения. К чему инфа про винду здесь?

К тому, что Wine работать не будет в x64 среде. x64 Windows без x32 компонентов – это явно не нормально работающее решение.

Не верите мне? Хорошо, возьмите в руки флешку с установщиком Windows, залейте на неё несколько Portable версий своих x64 приложений, далее попробуйте загрузиться с флешки,и запустить эти приложения (нажмите Shift+F10 для вызова командной строки и оттуда запустите программу). Увидите, что проблемы с запуском возникают, когда вы запускаете или обычное x32 приложение, или x64 приложение, которое полагается ещё и на x32 компоненты. Причина в том, что на флешке с установщиком винды не работает WOW64, та самая подсистема, которая позволяет запускать x32 приложения в x64 среде. Она устанавливается вместе с системой, но на самой флешке с установщиком она ещё не пашет. Вот так и выходит, что, если у нас нет возможности в x64 среде работать с x32 приложениями, вы не сможете работать с Windows приложениями, поэтому Wine на Эльбрусе с RTC может работать только в полностью x32 среде. И это сулит своего рода сложности, там тоже есть нюансы. К этому всему мы вернёмся позже.

Сперва вопрос: а каким образом я буду работать с транслятором RTC в Альт Линукс или Эльбрус ОС, которые, в отличие от macOS, не имеют «универсальных приложений», в которых исполняемый файл содержит инструкции под обе архитектуры?

Вот тут интересный момент. Вам нужно загрузить себе x64 дистрибутив Linux для работы с x64 приложениями, либо же загрузить x32 дистрибутив Linux для работы с x32 приложениями.

Но зачем нам загружать полный дистрибутив, который ещё надо устанавливать? Всё куда проще. Нам достаточно загрузить маленький rootfs образ с минимальным набором системных компонентов. Это мини-образ системы, в который вы будете выполнять своего рода chroot. Что такое chroot? В Linux-среде это когда вы «ныряете» внутрь другого дистрибутива. У вас в качестве основной системы в рамках сессии в Терминале начинает функционировать та мини-ОС, в которую вы «нырнули». Обычно сделать такое невозможно, если у вашей рабочей системы и системы, в которую вы «ныряете» разные архитектуры. Но это решается тем, что вы используете транслятор. Иначе зачем его было бы использовать?

Ну и, разумеется, помимо официальной документации, которая поставляется вместе с RTC, можете информацию вычитать и на сайте Альт Линукса. Там в целом понятная информация. Более того, я как-то обнаружил один баг в RTC версии 4.1 (связан с монтированием гостевой системы с параметром user), и в Alt Wiki информацию про этот баг добавили. Это не критичный баг, т.е. достаточно просто монтировать (подключать) раздел с этим мини-образом системы без той самой опции user, и всё будет работать замечательно (я её вообще по привычке применял, не придавал ей значения).

Но, тем не менее, баг подметили, и, как я понял, после багрепорта через других людей (сам то я доступа к багзилле не имею), этот баг будет устранён.

Итак, суть: у вас есть хостовая операционная система, собранная под E2K машину, из которой мы запускаем гостевую x86 систему. В качестве гостевой системы я сперва использовал Ubuntu 20.04.3 base.

Есть 2 варианта запуска: с использованием скрипта (как правильно) или напрямую обращаясь к транслятору (как делал я). В общем-то на сайте Альт Линукса описан как-раз второй вариант, которым я и пользовался.

                            /opt/mcst/rtc/bin/rtc_opt_rel_p1_x64_ob --path_prefix /mnt/ubuntu/ -b /etc/hosts -b /etc/resolv.conf -b /etc/shadow -b $HOME -b /etc/group -b /etc/passwd -b /home/ikakprosto -b $HOME/.Xauthority -b /mnt/shared -b /run/pulse -- /bin/bash
                        

Команда длинная, но сейчас поясню, что она значит. В начале мы вызываем транслятор. В качестве опций мы передаём ему информацию, что наш образ Ubuntu 20.04.3 (располагается по пути /mnt/ubuntu/), далее мы «биндим» файлы. Что значит «биндим»? Мы их привязываем. Мы делаем так, что данные, генерируемые службами в нашей текущей системе E2K, становятся доступны и в x86 системе. Для примера, нам не надо заново поднимать DHCP клиент и не надо заново поднимать DNS клиент. Вместо этого мы просто получаем информацию об используемом DNS-сервере из имеющейся системы, и интернет пашет. Мы прокидываем и нашу домашнюю директорию, чтобы иметь доступ к нашим обычным файлам из окружения транслятора. Также мы пробрасываем в гостевую систему ещё информацию о пользователе, скрытую в файлах /etc/group и /etc/passwd (вернее, мы пробрасываем ту информацию, что описывает, к какой группе какой пользователь принадлежит), и под конец мы прокидываем 2 немаловажных файла: .Xauthority и pulse. Первый нужен для того, чтобы у нас приложения с графическим интерфейсом внутри RTC нормально работали с нашим текущим используем дисплейным менеджером X.org (короче, чтобы у нас приложения с графическим интерфейсом работали). Второй нужен для того, чтобы у нас звук работал в приложениях. Точно также мы используем не транслируемые компоненты для работы звука, а уже имеющиеся нативные. К слову, звук лучше прокидывать, даже если не собираетесь им пользоваться, т.к. некоторые приложения в Linux виснут, если не могут вывести звук.

Там ещё много тех компонентов, которые и без нас прокидываются в гостевую директорию, чтобы обеспечить нормальную работу, их не надо прописывать вручную. По идее можно было бы не вбивать всё это в команду, а воспользоваться скриптами для проброса всех этих файлов, но я пошёл по тому пути, что вы видите. Ну и после двух знаков тире -- у нас вызывается /bin/bash, командная оболочка с которой мы взаимодействуем. Вместо этого вы можете вызывать уже готовую программу. Например, запускать сразу Telegram. Правда, если вы сидите на Альт Линукс, это не имеет особого смысла, т.к. там имеется нативный Telegram в репозитории. Но суть вы понятна: так вы запускаете практически любую программу, какую надо.

Почему практически? Есть приложение, которое внутри RTC мне завести не удалось, что в случае с x32 образом системы (использовал Альт Линукс 10), что в случае с x64 образом (Ubuntu 20.04.3). Это приложение ни одному приобретателю Эльбруса не нужно на этом самом Эльбрусе. Но, всё же, упомянуть стоит.

Ошибка при запуске Steam.

Скриншот 24. Ошибка при запуске Steam.

Только смеяться на этой частью не надо. Да, игры на Эльбрусе – баловство, но почему бы и не побаловаться разок? Короче, Steam у меня пашет с Lintel, но не пашет с RTC с теми же образами систем. Такие дела.

Зачем мне вообще тестировать RTC, когда есть Lintel? Сам по себе RTC намного эффективнее Lintel (если мы рассматриваем x86_64 Ubuntu 20.04.3 в обоих случаях), т.к. не транслируются, а исполняются в нативе всё ядро и спуск в него при system call и подъём обратно в user space. Это очень тяжёлые операции, трансляция которых требует больших ресурсов. И то, что вместо трансляции всей системы и всех драйверов для всего оборудования мы используем нативные ядро ОС, драйверы и прочие компоненты в случае с RTC, позволяет достичь высокой эффективности при трансляции.

А вот зачем нужен Lintel, мы рассмотрим сейчас.