Linux для macOS M1: что сделала команда Asahi Linux за январь-февраль 2021

Original author: Hector Martin

Вступительное слово переводчика

Некоторое время назад на Хабре уже писали про проект Asahi Linux.

Если кратко, то это попытка запустить linux на новом маке с M1 архитектурой.

Прошло 2 месяца с момента старта проекта, и разработчики подготовили отчёт о проделанной работе, который помимо перечня сделанного и несделанного, позволяет немного проникнуться сутью работы смеси системного инженера и реверсера.

Отчёт они написали немаленький, так что его перевод будет появляться по частям.

Часть 2 тут

Отчёт о проделанной работе

Рад представить вам первый отчёт о проделанной работе над Asahi Linux! В этих отчётах, по образу и подобию Dolphin playbook, мы будем ежемесячно рассказывать о том, что у нас происходит.

Добавить поддержку Linux для нового SoC это не самая лёгкая задача. Я надеюсь, эти отчёты дадут вам прочувствовать, сколько всего нужно, чтобы Linux заработал на совершенно новом устройстве.

Изначально, я планировал сделать два разных отчёта за январь и февраль, но разработка идёт такими ударными темпами, что я решил сделать один отчёт за оба месяца.

Маленькая вставка о терминологии

В этом отчёте вы можете встретить термины AArch64, ARM64, и ARMv8-A.

AArch64 это набор команд 64-битного ARM;

ARM64 – так в Linux называют поддержку 64-битного ARM.

ARMv8-A это спецификация архитектуры центрального процессора ARM, которая включает AArch64.

Точные значения этих терминов, как вы видите, несколько отличаются, но для наших целей можете читать всё это как “64-битный ARM”.

Путь в тысячу миль

Проект Asahi Linux официально стартовал в начале года, мы тогда все ждали релиза очень важной для нас штуки: поддержки от Apple загрузки сторонних ядер на Apple Silicon системах.

Несмотря на то, что эта фича документирована и практически готова, всё ещё не хватает кое-чего, чтобы она заработала : поддержки kmutil configure-boot команды, которая собственно и даёт вам возможность устанавливать не-Apple ядра.

Но не то, что бы нас останавливало отсутствие этой возможности, ведь первый шаг в портировании ОС на недокументированную платформу – это документировать её!

Apple Silicon Mac-и загружаются вообще не так, как ПК. Их загрузка больше похожа на то, как стартуют embedded платформы (например, Android или, само собой, iOS устройства), однако не без своих специфических нюансов. Вдобавок, Apple предприняла некоторые действия, чтобы процесс загрузки ощущался более похожим на Intel Mac, так что итоговая схема работы выглядит довольно запутанно.

Ну скажем, вы знали, что Apple Silicon Mac-и вообще не могут загружаться с внешних дисков? Или что их загрузчик не может отображать GUI вообще, а Boot Picker это по факту обычное полноэкранное приложение, а не часть загрузчика?

Так что прежде чем мы смогли запустить свои ядра на новых маках, мы описали как там работает весь процесс загрузки, как разбит на разделы встроенный SSD, и в чём отличие этих всех схем от ПК.

Мы писали это не только для себя, но и для всех пользователей, которые интересуются, как работает их компьютер. Некоторые детали и “почему так?” так были раскрыты в материалах Apple, но там есть далеко не всё.

Наводя мосты

Процесс загрузки Apple Silicon Mac не основан на существующих стандартах. Этот  механизм медленно развивался с первых дней iOS устройств, и наконец стал таким, как он есть.

Весь остальной мир 64-битных ARM по большей части придерживается одного из двух соперничающих стандартов: UEFI + ACPI(по большей части для серверов с Windows или Linux) и ARM64 Linux boot protocol + DeviceTree  (используется на небольших системах, так же поддерживается U-Boot и многими другими). Нам нужно было выбрать один из этих стандартов для Asahi Linux, и придумать, как подружить его с тем, что творится внутри Apple Silicon Mac.

UEFI&ACPI довольно сложные штуки, чаще всего используемые для больших ARM систем. Их стандарт по большей части определяется комитетом и UEFI Forum. В отличие от мира x86 ПК, который куда однороднее подходит к этому вопросу, ARM максимально разнообразен и включает в себя всевозможные дизайны SoC, с совершенно разными требованиями к описанию железа. Это значит, что добавить поддержку нового SoC почти всегда означает поправить немножко эти стандарты под себя, добавив поддержку специальных битов, отличающих ваш чип от остальных. Говоря про ACPI – такая работа заняла бы очень много ресурсов, поэтому ACPI почти не используется в малых embedded системах, без Windows. Это не подойдёт и нам по тем же причинам.

Широкий спектр небольших embedded ARM Linux систем пользуется стандартом DeviceTree, почти что без изменений. Например, его использует загрузчик Android. DeviceTree куда проще, чем ACPI, ведь это по сути просто набор данных, описывающих железо, в то время как ACPI таблицы это мешанина из кода и данных.

Стандарт DeviceTree фактически устанавливается набором соответствий устройств и их описания, который ведётся вместе с разработкой ядра Linux, то есть мы сможем менять то, что нам нужно, вместе с написанием самих драйверов под Linux. Как вы понимаете, загрузчик Asahi Linux будет использовать именно DeviceTree.

Довольно занятно, что Apple используют свою версию DeviceTree для Apple Silicon, которая называется Apple Device Tree! Как же так получилось? А очень просто: сам DeviceTree основан на OpenFirmware, который лёг в основу загрузчика ещё PowerPC, включая старые маки.

К сожалению, несмотря на то, что формат ADT довольно близок embedded Linux разработчикам, это не значит, что мы можем использовать его напрямую: бинарно формат отличается от DeviceTree, и его нельзя автоматически конвертировать без понимания, где какие данные там лежат. Вдобавок к этому, соответствия устройств и их описаний, весьма отличаются. Хотя Linux и macOS работают одинаково на PowerPC Mac-ах, и совместимы друг с другом, Linux прошёл огромный путь совершенствования по сравнению с Apple касательно ARM. Попытка объединить две разные идеи о том, как должны выглядеть деревья устройств, Linux-овую и Apple-овскую, грозит обернуться кошмаром.

Чтобы привести то, как Apple видят device tree, к тому, как это видит стандарт, мы делаем m1n1 – загрузчик для Apple Silicon машин. Его цель – взять на себя заботу о максимальном количестве специфических для Apple вещах, и упростить жизнь для всех, включая Linux.

Вы можете добавить m1n1 к ядру Linux (cat m1n1.macho initrd.bin devicetree.dtb Image.gz > m1n1-kernel.macho), установить его на Mac с помощью kmutil и он сделает всё, что требуется для запуска Linux. Когда вы загружаетесь в Linux с помощью m1n1, он делает примерно следующее:  

  • Инициализирует ЦПУ, выставляет т.н. chicken bit, чтобы он заработал

  • Считывает информацию, которую iBoot (загрузчик Apple) ему даёт: сколько оперативной памяти доступно, адрес framebuffer(видеопамяти, отображаемой на экране) в ОЗУ

  • Инициализирует MMU. Это нужно, чтобы включить использование кэшей ЦПУ, иначе всё будет ужасно тормозить.

  • Заменяет Apple логотип на Asahi Linux логотип :)

  • Убивает watchdog timer. Без этого шага мак бы перезагружался через минуту-другую, потому что думал бы, что процесс загрузки просто завис.

  • Определяет, что же мы будем загружать: ядро Linux, DeviceTree и (опционально) initramfs radmisk с программами, которые могут работать во время загрузки, если таковые были.

  • Инициализирует все остальные ядра ЦПУ, выставляет им chicken bits, и переводит их в режим ожидания spin-table (подробнее об этом - ниже), чтобы их мог использовать Linux.

  • Берёт информацию из ADT (Apple Device Tree) и генерирует соответствующий ему DeviceTree. Этот шаг нужен для поддержки тех параметров, которые могут меняться от машины к машине или от версии iBoot : размер памяти, информация про framebuffer, сид для инициализации Linux random generator, и всякого другого. m1n1 добавляет некоторую собственную информацию, включая подробности о spin-table и cmd аргументы для ядра.

  • Передаём управление Linux, ну или кому-нибудь другому, кто ждёт от нас этого.

Так, а что такое spin-table? Это один из двух стандартов по использованию Linux on ARM дополнительных ядер процессора с помощью DeviceTree. Вместо того, чтобы каждый городил драйверы для своих платформ, есть два ожидаемых варианта поведения: spin-table и PSCI.

Spin-table – загрузчик просто включает все CPU и оставляет их в режиме ожидания (spinning). Чтобы вывести ядро из режима ожидания, Linux пишет в табличку в ОЗУ определённое значение(адрес), которое указывает, какую команду нужно выполнить в ядре. Это идеальный путь для простых систем. Единственный недостаток: нельзя полностью остановить ядро после такого, это путь в один конец. Однако всё ещё можно вводить ядра в разные энергоэффективные режимы с помощью разных других техник. Пока что мы решили использовать этот подход, и не факт, что нам когда-либо захочется его поменять.

PSCI (ссылка) – это ARM стандарт по управлению ядрами (и не только) во время исполнения. Обычно, такое управление осуществляется из EL3 (secure firmware or TrustZone), или же через VM гипервизор, запущенный в EL2 (ОС обычно работает в EL1).

Примечание переводчика

Чтобы внести немного ясности для тех, кому ARM не очень близок. Вам может быть знакомо такое понятие, как protection ring:  https://en.wikipedia.org/wiki/Protection_ring

По-простому, оно определяет, кому какие команды ЦПУ можно выполнять, и куда в памяти можно обращаться. Обычно говорят про ring 0  как про уровень ядра, 1-2 уровень драйверов, а 3 – уровень приложений.

Так вот на ARM всё решили назвать наоборот:

учитывайте это, и не удивляйтесь.  

Однако, EL2 и EL3 – опциональные фичи для ARMv8 CPU, и оказалось, что в M1 EL3 не поддерживается. EL2 есть, но мы хотим поддерживать запуск VM с Linux на борту, что само по себе требует запускать Linux в EL2, так что мы уже не сможем добавить туда ещё один гипервизор.

Для нас это означает неприменимость PSCI прямо сейчас, однако в ближайшем будущем ситуация может измениться.

Тут нужно заметить, что без PSCI не будет поддержки полноценного режима сна. Однако может быть, если мы достаточно хорошо обкатаем наш power management, нам и не понадобится полноценный  режим сна, и это не будет сказываться на жизни батареи. (многие современные устройства работают без полноценного режима сна!).

Время покажет, как оно будет.

Итак, ладно, мы договорились, что у нас будет devicetree, но это же не значит, что у нас не может быть UEFI!

ARM64 системы могут загружаться используя UEFI+DeviceTree, чтобы обеспечить пользователю видимость загрузки “как на ПК”, использовать GRUB и прочие стандартные механизмы для установки и обновления ядер. Однако, m1n1 не поддерживает ничего из вышеперечисленного, так что же делать?

К счастью, ответ есть, и это U-Boot. U-Boot умеет загружаться как ядро Linux – так что мы можем просто загрузить U-Boot из m1n1 – и даёт неплохое UEFI окружение для GRUB и Linux.

В общем, скорее всего, последовательность запуска Asahi Linux будет примерно такой:

m1n1-> U-boot -> GRUB -> Linux

Если добавить сюда установку разных Apple-specific битов, то весь процесс выглядит так:

  • SecureROM внутри M1 SoC стартует и загружает iBoot1 из NOR flash памяти.

  • iBoot1 читает загрузочный конфиг с встроенного SSD, валидирует системную политику загрузки, выбирает ОС для загрузки – в нашем случае Asahi Linux / m1n1 будет выглядеть как раздел с ОС для iBoot1

  • iBoot2, который по сути и является загрузчиком, и должен находиться на разделе с загружаемой ОС, загружает firmware для встроенных устройств, строит apple device tree, и загружает Mach-O ядро (в нашем случае m1n1)

  • m1n1 разбирает ADT, превращает его в понятный для Linux набор описаний (Flattened Device Tree), и загружает U-boot

  • U-boot, у которого будут драйвера для встроенного SSD, читает конфиги и даёт нам UEFI, включая поставку devicetree из m1n1

  • GRUB загружается как обычное UEFI приложение, работает так же, как и на любом ПК. Именно он позволит нам управлять ядрами так, как мы привыкли, через grub-mkconfig и /etc/default/grub.

  • Наконец-то, ядро Linux запускается, используя DeviceTree, сгенерированное ещё m1n1.

Фух! Выглядит немного дико для людей из ПК-мира, но на самом деле долгие последовательности загрузки это норма в embedded системах (по факту UEFI на ПК тоже включает в себя целый ряд шагов, просто пользователю они не видны).

Вот вам для примера одна из возможных цепочек запуска DragonBoard410c (Qualcomm платформа):

PBL->SBL->QSEE->QHEE->LK->U-boot->GRUB->Linux

Заметьте, мы не можем заменить iBoot2 (он подписан Apple, и эта подпись проверяется), но итоговый процесс установки будет автоматически настраивать минимальную “macOS” вместе с iBoot2 и всем чем надо, достаточным, чтобы mac распознал этот образ как загружаемый раздел с ОС (а вот реального ядра macOS или его файловой системы там не будет). Установщик ещё не готов, так что пока всем, кто захочет проверить, глубока ли кроличья нора, придётся последовать нашему гайду.

Пока что мы грузим сразу Linux из m1n1, но Mark Kettenis работает с нами над поддержкой U-Boot и OpenBSD.

Но нужно же понимать, что m1n1 он не о том, чтобы запустить Linux. Честно говоря, это даже не загрузчик на самом то деле!

Продолжение перевода тут

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 8

    0

    читал это на английском, эпическую работу люди делают, мягко говоря.


    Помню как разработчики Байкала добавили поддержу своей SoC в апстрим ядра Linux и это подавалось как большая победа. А тут мало того что куда более сложная, так ещё и практически не документированная система.

      0

      меня интересует что об этом думают сами ребята из купертино. понятно что помогать они не будут, им это не выгодно, бяки они… но не начнут ли втыкать палки в колёса? я вот давно хочу себе недобук на арме, только вот макось меня слабо интересует, а существующие pinebook и его аналоги не блещут производительностью..

        0

        Один из инженеров Apple, работавших над загрузчиком:


        It's pretty gratifying to see how quickly this all came together. Some engineers were highly supportive of the alternate-kernel mechanism to nominally enable linux, others were skeptical it would ever get used. I was in the former camp, but I thought it would take a lot longer!

        https://twitter.com/XenoKovah/status/1370131505620652038

        0
        Linux был портирован на M1 Corellium несколько месяцев назад (исходники, инструкция, твиттер), включая блочный драйвер, сеть, Thunderbolt, периферию для ввода, SMC драйвер, USB и т.д. Объективно — это почти максимум, который можно сделать без поддержки Apple.

        Всё, чем сейчас занимается господин Мартин, — это странная демагогия в твиттере/блоге/стримах, которая создаёт видимость какой-то полезной работы, выполняемой якобы с нуля без копипасты уже готового кода. Всё приличное сообщество ржёт уже который месяц, но получать донаты приятно :D, потому отступать некуда, позади патреон.

        Если по-существу, то сейчас осталось поднять нормально ускорение GPU, но эта задачка, мягко говоря, не уровня команды Asahi Linux, тем более, там подписан микрокод. Так что мы будем смотреть ещё полгода, как товарищи пишут лоадер на питоне.
          +1

          То, что Corellium наклепали на скорую руку, невозможно ни поддерживать, ни интегрировать в апстрим. У них даже документации нет, только инструкция "как попробовать загрузиться и понять, что ничего толком не работает".
          Собрали хайпа на основе предыдущих наработок под iOS-устройства, а дальше развивать им не интересно.


          То, что делает сейчас Мартин — тщательно документирует все особенности новой платформы и заносит "чистые" патчи в апстрим ядра.

            0
            Вы код видели Corellium? Я, пусть и достаточно бегло, но смотрел. Он нормальный. Ничем не хуже значительной части остального кода в Linux. Документации нет, да, но её нет много где. Половина драйвера i915 задокументирована так, что плакать хочется, и это при наличии 01.org. Развивать, полагаю, они очень даже будут, так как им Linux нужен для своих проектов виртуализации.

            Касательно «апстрима» — давайте не передёргивать факты. Никто не умаляет ничьи достоинства, но если господин Мартин и начал выкладывать патчи контроллера прерываний Corellium в mailing list с небольшими правками аккурат во время того, как в Corellium активно работали над остальными драйверами, то это никак не говорит об изначальных намерениях Corellium. Ему просто уступили, так как очень хочется.
              0
              Вы код видели Corellium? Я, пусть и достаточно бегло, но смотрел. Он нормальный. Ничем не хуже значительной части остального кода в Linux.

              Их патчи ломают поддержку других ARM-платформ. Они одноразовые.
              А для внутренних проектов и так сойдёт.


              это никак не говорит об изначальных намерениях Corellium

              Сотрудники Corellium уже 2 месяца не появляются в мейллистах, код на гитхабе ни разу с форка не ребейзился. Для меня их намерения пока очевидны.


              Ему просто уступили, так как очень хочется.

              Что уступили, простите?


              И заодно расскажите, что за такое "приличное сообщество", которое ржёт над Гектором, где оно обитает?

            0
            Смотрите: есть разница между тем, чтобы сделать что-то кое-как, чтобы его потом можно было взять в проприетарный проект и допилить напильником (это то, что сделали Corellium, и это тоже имеет свою пользу), и между тем, чтобы сделать нормальный ресёрч незнакомой платформы, описать его, создать базу, на которой можно делать новые исследования и строить другой open-source софт.

            Поддержкой и расширением Asahi с определённого момента будет заниматься комьюнити, и сейчас разработчики Asahi тратят много усилий на создание удобных инструментов для такой поддержки. Кто и как будет поддерживать Corellium?

          Only users with full accounts can post comments. Log in, please.