欢迎来到第一个Asahi Linux进度报告!在本系列中,我们将从Dolphin Playbook中拍摄页面并为您提供项目进度的每月更新。
对Linux上的新系统带来支持不是小任务!我希望这个系列能够向每个人提供教育,并让您一瞥在一个全新的设备上进行Linux工作的幕后工作。原计划是为了对1月和2月进行单独的更新,但事情正在移动这么快,很难呼叫截止点,所以我们最终有一个为期两月的更新。
在本报告中,您将看到术语AARCH64,ARM64和ARMV8-A。 AARCH64是指64位ARM架构指令集; ARM64是Linux调用其支持64位手臂的支持; ARMv8-A是ARM CPU架构规范,包括AARCH64。这些术语具有巧妙的不同含义,但是为了我们的目的,您主要可以将它们所有人视为“64位手臂”。
Asahi Linux项目在年初正式启动,但是当时我们都在等待一个关键作品:来自Apple的支持,用于在Apple Silicon系统上启动替代核。虽然该功能已被记录并大多实现,但有一个最终丢失的拼图:对KMUTIL CONFIGURE-BOOT命令的支持,这是您安装非Apple内核的原因。这并没有阻止我们取得进展,然而,作为将OS移植到无证平台的第一步是记录它!
Apple Silicon Mac从PC完全不同的方式启动。他们工作的方式更像是嵌入式平台(如Android手机,或当然,iOS设备),但是有很多定制机制抛出。但是,Apple采取了一些步骤来使这个启动过程感到更近英特尔MAC的那个,所以如何围绕事情实际上有很大的困惑。例如,您是否知道Apple Silicon Mac无法在传统意义上从外部存储器启动?或者Apple Silicon Mac上的引导加载程序根本不能显示图形用户界面,并且“启动选择器”实际上是全屏麦斯科座应用程序,而不是引导加载程序的一部分?
因此,在我们能够在这些机器上运行自己的内核之前,我们开始映射引导过程的工作原理,分区和卷如何在内部SSD上奠定,以及如何与PC进行比较。本文档不仅对我们的项目有用,而且对任何想要更好地了解他们的机器工作的摩托斯用户都是有用的。它的一些功能和潜在的理由(但不是全部)自2011年2月2021年的Apple Platform安全指南版本已被记录。
Apple Silicon Macs的启动过程不基于任何现有标准。相反,它是一个定制的Apple机制,从iOS设备的早期慢慢发展。另一方面,64位ARM世界的其余部分主要融合在两个竞争标准:UEFI + ACPI(主要用于运行Windows或Linux的服务器),以及ARM64 Linux Boot协议+ Devicetree(用于较小的系统,并由U-Boot等支持)。我们需要为asahi linux选择其中一个,并弄清楚“桥接”苹果世界的方式。
UEFI和ACPI通常只用于大型臂系统的复杂性野兽。标准主要受联盟论坛委员会的控制。与X86 PC世界不同,这是一个更加均匀的,ARM世界是极其多样化,片上系统的各种设计,具有不同要求的设计,用于描述其中包含的硬件。这意味着为新SoC添加支持几乎总是要求修改这些标准,以添加使其独特的硬件的“绑定”。对于ACPI来说,这是昂贵和慢的,这就是为什么ACPI几乎从未用于不运行Windows的小型嵌入式系统。这不是我们的可行选择。
各种较小的嵌入式ARM Linux系统几乎总是使用Devicetree标准 - 例如,这是大多数Android设备启动的方式。 Devicetrees比ACPI更简单,因为Devicetree纯粹是一堆描述硬件的数据,而ACPI表是数据和代码的组合。如今,DeviceTree绑定的权限是Linux内核树本身维护的文档:这意味着我们可以在我们编写Linux驱动程序本身时同时修改这些标准。因此,Asahi Linux的引导过程将使用此模型。
有趣的是,Apple还在Apple Silicon上使用自己版本的设备树,称为Apple Device Tree!这是因为它和打开的devicetree标准都基于开放的固件规范,这是许多PowerPC系统引导,包括较旧的Mac。遗憾的是,虽然这是一个嵌入式Linux开发人员对均匀熟悉的均匀,但我们不能直接使用它们:二进制格式不同,无法自动转换,而无需有关数据所代表的高级别信息。最重要的是,用于设备的实际绑定非常不同。虽然Linux和MacOS在PowerPC Mac上的工作方式和直接兼容,Linux在Apper空间中的Apple中有十年的分歧。试图统一Apple和Linux的想法,了解设备树的工作将是噩梦。
为了使Apple World适应一个Devicetree World,我们正在开发M1N1,这是一个用于Apple硅机的引导加载程序。它的目标是尽可能多地照顾好“苹果isms”,使生活尽可能简单,或者在下游的其他任何东西。
您可以将M1N1预先添加到Linux内核(仅使用Cat M1n1.macho initrd.bin devicetree.dtb image.gz> m1n1-kernel.macho为最小固定内核安装工作),使用Apple的KMutil工具将其安装在Mac上,它将完成制作Linux启动所需的一切。使用M1N1引导Linux时,这大致是它的:
读取Apple的Bootloader,IBoot提供给它的引导信息:这包括以下内容以及RAM中的帧缓冲区(屏幕上显示的视频内存的地址)。
初始化内存管理单元。这是能够使用CPU高速缓存所必需的,无论哪些一切都非常慢。
禁用看门狗定时器。没有这个,在一分钟左右后,Mac会自发重启,因为它认为启动过程已被卡住。
数字突出它将启动的内容:Linux内核,devicetree和(可选)initramfs ramdisk包含启动时应用程序,如果已被附加到它。
初始化所有其他CPU核心并应用所需的鸡位,然后在“旋转表”中设置它们,为Linux占用。
从Apple设备树中获取信息,并自定义提供的DeviceTree模板以匹配。这用于从机器到机器的设置以及从版本到Apple的Iboot固件(如内存大小)的版本,如内存大小,有关FrameBuffer的信息,种子才能初始化Linux的随机数生成器等。 M1N1还添加了自己的一些信息,例如内核的旋转表详细信息和命令行参数,如果有的话。
“旋转表”是两个标准之一,武器上的Linux可以用于在DeviceTree World中打开额外的CPU核心。而不是依赖特定于平台的驱动程序,而是有两个标准方法可以使用所有平台使用。旋转桌子,这是最简单的表,只需提前启动引导加载程序,并在循环中留下它们等待(“旋转”)。要从循环中释放CPU,Linux将值写入RAM,告诉它们在哪里跳入内核。这对于简单的平台非常好;唯一的实际限制是CPU无法再次完全停止,因为接管来自引导加载程序的CPU是单次交易。但是,它们可以使用其他机制投入各种低功耗模式。我们现在正在使用这种方法,这是我们将需要的一切。
替代品被称为“psci”,它是一个臂标准,它被设计为适当的服务,即系统的固件即使在Linux正在运行时也可以提供,以允许在运行时控制CPU(和其他组件)。通常,这是通过在“EL3”(即安全固件或TrustZone)上运行的代码完成的,或者通过在“EL2”的VM虚拟机管理程序 - OS运行在EL1上运行。然而,EL3和EL2都是ARMV8-A CPU的可选功能 - 事实证明,M1上没有EL3支撑。 EL2可用,但我们希望支持在Linux下运行的VM,这需要将Linux本身运行为EL2 - 因此我们不能将另一种虚拟机管理程序放在上面。这意味着我们今天不能使用PSCI,因为没有为我们工作的PSCI的标准界面。在不久的将来,可以开发替代机制,使我们能够使用它。这可能是支持全系统睡眠模式的必要条件 - 尽管如此,如果细粒度的电源管理足够好,我们可能不需要“真正的”全系统睡眠以获得非常好的电池寿命(现代设备与更精细的工作非常好-Greated睡眠模式)。时间会告诉,这仍然是一个不断发展的地区。
现在,我说我们会使用devicetree - 但这并不意味着我们不能使用UEFI! ARM64系统可以使用UEFI + DevicEtree引导,这是为了获得“类似于”PC的“启动体验,具有Bootloader(如Grub)和用于安装和升级内核的典型流程。但M1N1不支持任何一个,所以我们该怎么办?值得庆幸的是,还有另一部分完成拼图:U-Boot。 U-Boot可以像Linux内核一样启动 - 所以您可以从M1N1启动U-Boot - 它本身可以为GRUB和Linux提供足够的UEFI环境。
所以,最有可能的是,最终用户使用的Asahi Linux的启动链将是:
结合靴子链的特定于苹果特定位,整个启动过程最终看起来像这样:
M1 SoC内的Securerom启动了冷启动,并从NOR闪存加载iboot1
Iboot1在内部SSD中读取引导配置,验证系统引导策略,并选择“操作系统”启动 - 对于我们来说,Asahi Linux / M1N1将看起来像对iBoot1的OS分区。
Iboot2是“操作系统加载器”,并且需要驻留在未启动的OS分区中,为内部设备加载固件,设置Apple设备树,并启动Mach-O内核(或在我们的情况下,M1N1)。
M1N1解析ADT,设置更多设备并使Linux-lim-Live,设置FDT(扁平设备树,二进制DeviceTree格式),然后启动U-Boot。
U-Boot将具有内部SSD的驱动程序,读取其配置和下一个阶段,并提供UEFI服务 - 包括从M1N1转发DevicEtree。
GRUB从磁盘分区启动作为标准的UEFI应用程序,就像任何PC上的GRUB一样。这是允许在我们习惯的方式管理内核的发行版,使用grub-mkconfig和/ etc / default / grub和friends。
最后,Linux内核被引导,使用从M1N1传递的DevicEtree,提供它所需的信息。
ph!这可能对来自PC世界的人看起来有点疯狂,但是像这样的长靴链在嵌入式系统上很常见(实际上,“UEFI”在典型的PC上包括多个阶段,它只是最终用户没有看他们)。例如,蜻蜓410C的一个可能的启动链(基于Qualcomm的平台)可能如下所示:
请注意,我们无法替换iboot2(它需要一个苹果签名),但我们的最终用户安装过程将自动设置一个最小的“麦斯科斯”,包括iboot2和所有必需的支持文件,足以识别它的Apple启动进程作为可引导的操作系统(但排除实际的MacOS内核/文件系统)。安装程序还没有准备就绪,因此由于开发人员尝试使用M1N1 / Linux必须进行单独的全麦斯科斯安装,然后替换其内核。我们写了一步一步的快速入门指南,以指导那些想要加入我们的冒险。
现在,我们的主要开发工作流程是直接从M1N1加载Linux,但Mark Kettenis正在与我们一起使用U-Boot和OpenBSD支持。
但M1N1不仅仅是运行Linux。事实上,它甚至不是心脏病的靴子!
M1N1将过去追溯到Mini,这是我为Nintendo Wii的安全CPU写的最小环境。它对于实验和BootMii的后端是有用的 - 对于拥有Wii并熟悉它的人来说,Mini是您在BootMii菜单中的时候在ARM CPU上运行的内容。
你问的是什么与Apple Silicon Bootloader有关?嗯,迷你真的只是一个非常简单的软件,在裸金属32位臂系统上运行,没有任何外部库或依赖关系。它为构建裸金属代码的一个很好的,简单的基础,因此我们将其移植到AARCH64和Apple芯片,并将其重命名为M1N1。但更重要的是,迷你和M1N1有一个诡计他们的袖子:由于迷你的遗留作为在需要从主CPU的独立处理器上运行的固件,并且从过去的实验与Wii硬件研究,它有一个内置的RPC代理在串行端口上运行。这意味着您可以实时从开发计算机中“遥控”迷你和M1N1。 M1N1允许您使用在任何计算机上运行的简单Python脚本使用M1硬件,甚至可以使用Interactive Shell。它将最好被描述为硬件实验工具,该工具刚刚发生在Linux Bootloader。
这使得一个很棒的平台来了解有关硬件的更多信息并发现Apple的所有专有功能。例如,此脚本测试了一个特殊的Apple功能,该功能将支持某些X86特定的浮点配置位对其CPU添加,它们用于加快Rosetta x86仿真。此脚本搜索所有Apple自定义CPU寄存器并打印它们的值及其访问限制。此脚本会自动介绍如何通过Apple专有的管理程序配置寄存器自定义这些访问限制。而且,当然,此脚本将为您启动Linux内核,直接从串行端口流式传输。
将M1 Mac Mini引导到M1N1需要大约7秒钟,并且所有这些脚本都可以在不重新启动的情况下以交互方式运行(直到您崩溃机器)。 M1N1也可以加载自身,因此M1N1本身的开发周期也非常快:您可以留下旧版本的M1N1,并只需在重新启动后在运行时加载最新的。
使用M1N1,我们在工作中一直很难记录Apple的自定义ARM指令,特定于Apple的系统Segisters,诸如Apple中断控制器等硬件等。
在未来,我们将继续向M1N1添加功能,使其成为一个更强大的研究工具。一个特别令人兴奋的目标是将其转化为一个非常薄的VM虚拟机管理程序,可以启动麦克斯,并拦截其访问到M1硬件。这将使我们能够调查Apple的司机如何工作,而无需拆卸它们,这使得具有非常合法的方法,而且通过复杂的专有驱动程序代码还比追踪更效益。您中的一些人可能会认识到Nouveau以成功逆向工程师NVIDIA GPU的同一个方法 - 尽管在这种情况下,他们使用Linux驱动程序并仅修改内核,而不是添加虚拟机管理程序。
但等待 - 完成所有这些,您需要一个串行端口。 M1 Mac上的串行端口在哪里?我很高兴你问过!
要在新系统上进行低级调动工作,但有一个串行端口几乎是必不可少的。串口,有时称为UART端口,实际上是最简单的通信硬件,并且为一个非常方便的低级调试工具制作。通过串口发送消息仅需要几个CPU指令,因此可以很早地设置,并用作文本终端进行开发。
当然,现代PC用于拥有RS-232串行端口,但那些很长一段时间。在许多嵌入式系统(例如大多数家庭路由器)上,低压串行端口仍然在内部存在,但您需要删除该案例以在连接器上访问它,或直接在电路板上的测试点。 M1 Mac怎么样?
事实证明,M1 MAC实际上具有串行端口,可以在壳体外部访问 - 超过其中一个USB-C端口!但是,要启用它,您需要通过USB-PD发送一些特殊命令。 USB-PD(USB电力传递)是一种在C型端口上的“配置通道”引脚上运行的协议。像往常一样,对于USB标准,它是一个超前的庞然大物,这比实际提供的电力更多 - 不仅用于配置电压并识别充电器,还用于识别电缆类型,加密窗,诸如DisplayPort等替代模式,并且,在这种情况下,作为Apple专有配置消息的频道。这些消息让我们要求Mac在一个特定类型C端口的两个引脚上公开其串行端口。其他简洁的功能包括重启系统远程重启的功能(不可或缺的快速开发),将其进入DFU恢复模式,访问内部总线,如I²C等等。
我们的第一个解决方案来获得这些MAC的串口是VDMTool:使用Arduino的DIY电缆,USB-PD PHY(接口)芯片,以及某种1.2V串口适配器。这对具有DIY技能的人来说很好,但对于那些不习惯建立自己的硬件的人来说并不是很实际的。有许多烦恼:没有良好的USB-PD PHY突破板,所有必需的C型信号,1.2V UART适配器是罕见的等。
因此,我们提出了第二种解决方案:如果您碰巧有两个M1 Mac,请高兴!所有您需要的是标准类型C线(Superspeed / USB 3.0类型)和MacVDMTool。这个小麦克斯应用程序允许您将一个M1机器转换为另一个M1机器,以便将M1N1脚本和引导Linux内核直接从MacOS运行。 Apple的API允许我们将MAC自己的端口配置为串行模式,并发送所需的消息,以将远程MAC配置为串行模式,这使得所有这些都可以使用无关紧要的硬件。
但当然,另一个MAC为相当昂贵的串行电缆!因此,我们将以更全面的USB-PD调试电缆作为开放式硬件项目开发,不仅可以作为M1 Mac的串行适配器,而且还可公开其他特殊功能。事实上,它将超越MAC,也可以作为其他设备的调试接口,例如许多Android手机。它还将作为USB-PD开发平台,能够作为通用源(电源)或水槽(电源消费者)等,以试验USB-PD充电器和设备。它仍在规划阶段,但留在更新的情况下!我们的目标是最终使这一社区广泛使用,所以任何人都可以点击一个按钮并购买一个。
最后,虽然硬件串行端口是低级调试和开发的最佳解决方案,但它有局限性:它非常慢,速度为150 kb / s。然而,M1 Mac也可以表现为正常的USB设备(例如iPhone),例如,我们可以使它们显示为USB串行设备(CDC-ACM),在大多数OS上没有驱动程序。这为我们提供了USB的完整带宽,并且能够使用正常类型C电缆(或键入C电缆)的便利性,以便与任何其他计算机连接。 USB还提供流量控制,这意味着在接收方时不会丢失数据
......