Microkernel Goes General

Microkernel Goes General: Performance and Compatibility in the HongMeng Production Microkernel

来源  https://yangzy723.github.io/posts/2024/08/08/Microkernel-Goes-General-Performance-and-Compatibility.html

 

杨镇源 于 2024-08-08 发布 浏览量 14

原文

  • 商业实用性:兼容Linux API/ABI以复用其生态(程序和驱动)

  • 与传统微内核相比的优化点:
    • IPC
    • capability-based access control
    • userspace paging
  • 性能方面遇到的问题:
    • per-invocation IPC
    • IPC frequency, state double bookkeeping among OS services
    • capabilities that hide kernel objects
  • 解决方案:
    • differentiated isolation classes
    • flexible composition, policy-free kernel paging, address-token-based access control

1. Introduction

微内核的特征:微内核将内核中的功能最小化,并将文件系统和设备驱动程序等组件移动到隔离良好、特权最低的操作系统服务中,从而实现了比Linux等单片内核更好的可靠性、安全性和可扩展性。

单内核(Linux)存在的不足

  • 像Linux这样的单内核在服务器和云等通用场景中占主导地位,但越来越多的新兴场景,如智能汽车和智能手机,除了良好的性能外,还需要更好的安全性、可靠性和可扩展性,而Linux则不太适合。
  • 虽然Linux是通用的,但它更多地向服务器和云发展,使其他场景变得不那么有益。

微内核(SOTA)存在的不足

  • SOTA微内核主要针对一些特定领域,例如嵌入式和安全关键领域。它们通常使用静态资源分区和分配,缺乏运行商用现成应用程序的通用操作系统功能。

微内核改造为通用OS内核面临的主要挑战

  • Compatibility
  • Performance: 当前微内核会造成不晓得性能开销,当微内核被更广泛使用时,IPC频率显著增加(智能手机中的IPC频率比路由器高70倍)

Capability-based access control: Capability被简单地称为“密钥”,它是指定资源并授权对其进行某种访问的单一事物。该Capability是不可伪造的权威令牌。 假设有一个文件系统,文件A有如下权限:
- 用户U1可以读和写 - 用户U2可以读 在能力模型中,这些权限将由不同的能力来表示: - 能力C1:允许U1对文件A进行读写操作 - 能力C2:允许U2对文件A进行读取操作 这些能力可以被系统安全地分发和管理。若U1需要将读取权限传递给U3,系统可以创建一个新的能力C3,仅包含读取权限,并将其安全地传递给U3。

HongMeng做出的关键设计决策:

  • 具有最低权限和良好隔离的操作系统服务的最小微内核。 HM保留了最小化原则,仅在核心内核中保留必要的功能,包括线程调度程序、serial/timer驱动程序和访问控制,并将所有其他组件作为独立的操作系统服务(多服务器)保留在核心内核之外。
  • 通过实现 Linux API/ABI 兼容性和高性能驱动程序复用来最大化兼容性。 HM 通过ABI兼容的shim(shim是一个库,它透明地拦截API调用并更改传递的参数、处理操作本身或将操作重定向到其他地方。Shims 可用于支持较新环境中的旧API,或较旧环境中的新API。shim还可以用于在与开发目的不同的软件平台上运行程序。)来实现完全的Linux API/ABI兼容性,该shim识别并将Linux系统调用重定向到IPC。
  • 通过结构性支持优先考虑性能。 HM实现了灵活的组合,以分层放松受信服务之间的隔离,从而最小化IPC开销,并将紧密耦合的服务合并以最小化IPC频率并消除在性能需求场景中的状态双重记账,同时在安全关键场景中保持分离它们的能力。HM还使用基于地址令牌的高性能访问控制来补充基于能力的访问控制,从而促进高效协作操作,例如无策略的内核分页。

2. The Case for a General Microkernel

2.1 回顾微内核

  • 微内核的一个主要特点是最小化原则,它将核心内核中的功能最小化,并将其他功能移至用户空间服务。微内核本质上比宏内核更安全、更可靠、更可扩展。
  • 当前微内核主要应用领域还在嵌入式和安全关键系统上,关于如何将微内核扩展为智能汽车和智能手机等新兴场景的通用操作系统内核的研究很少。
  • 工业界常采用混合内核,将核心微内核(例如 XNU 中的 Mach)与内核空间中的所有其他服务(作为一个整体)结合起来。尽管混合内核也最小化了核心内核中的功能,但它们并没有继承微内核的许多优点。例如,混合内核中的操作系统服务不仅不是特权不是最小化的,而且隔离也不好。因此,任何受损或有缺陷的操作系统服务都可能损坏系统,导致严重后果,例如损坏用户数据。

2.2 通用微内核的需求

  • 软件生态(POSIX兼容性、Linux ABI兼容性)
  • 高效的资源管理和公平的资源分配
  • 在特定领域的场景中,微内核优先考虑安全性和严格的资源(例如时间)隔离,主要用于静态应用程序,其中性能不是主要关注点。然而,在新兴场景中,性能也是首要任务,这直接决定了用户体验,从而影响内核的广泛部署

2.3 Linux操作系统存在的问题

Linux已经主导了服务器和云市场,并且越来越多地渗透到PC和嵌入式等其他领域。然而,它是以牺牲安全性、可靠性和性能为代价的,特别是在新兴场景中。

  • 安全和可靠性 文件系统 (FS) 和设备驱动程序等Linux模块覆盖了其3000万行代码库的大约80%。它们造成了大多数缺陷和漏洞(过去4年中1000个CVE总数的90%),并显着降低了可靠性和安全性。通过适当的隔离可以避免这些泄露。
  • 通用性与专业化 虽然Linux目标是通用场景,但最近的补丁和功能表明,创新主要由服务器和云计算驱动,这甚至会影响其他场景的性能。(有专用于服务器/云计算的趋势)。定制内核通用难度大。
  • 定制化 vs. 演变 与上游同步需要大量的努力来重新应用更改,而不与上游同步可能会使系统暴露于安全漏洞中。因此Linux的可定制性受到限制。

“与上游同步”是指保持软件或代码基的更新和维护,与其原始或主版本(即“上游”版本)保持一致。这通常应用于开源软件项目,其中“上游”是指软件的官方源头或主要开发者发布的版本。例如,在Linux内核开发中,当开发者对内核进行特定的定制时,保持与上游版本的同步意味着定期将上游的更新(如bug修复、安全补丁和新功能)合并到他们的定制版本中。

3. Revisiting Microkernel for Going General

3.1 Microkernel at Scale

image

观察:

  • 新兴场景中IPC频率迅速增加
    • 图(a)显示了智能手机和车辆的IPC频率远高于路由器
    • 高IPC频率的原因不仅是更高的系统调用频率(61k/s,比路由器高13倍),还有发起了大量文件操作(IPC到文件系统)和触发了内存映射文件的多个page fault(5k/s)
  • 分布式多服务端导致状态双重记账
    • 最小化原则决定了没有用于共享对象(如文件描述符(fd)和页缓存)的集中式存储库,而是将这些对象分布在多个地方

image

  • 能力(Capabilities)阻碍了高效的协作
    • 将内核对象隐藏在其背后的能力(Capabilities)由于某些内核对象(例如页表)的频繁更新而引入了显着的性能开销,并阻碍了它们之间的高效协作。
  • 生态兼容性要求不仅仅是POSIX合规性
  • 在新兴场景中部署需要高效的驱动程序复用

3.2 Overview of HongMeng

HM遵循微内核的核心设计原则,但又不至于极端,通过谨慎的妥协来解决新兴场景中的性能和兼容性挑战。

image

image

设计原则:

  1. 保持最小化
    • 微内核的安全性、可靠性和可扩展性源自三个基本的架构设计原则,包括分离策略与机制、解耦和隔离操作系统服务,以及实施细粒度访问控制
    • HM仅在核心内核中保留最小和必要的功能,包括线程调度器、串行和定时器驱动程序以及访问控制。所有其他功能都在隔离的操作系统服务中实现,例如进程/内存管理器、驱动程序和文件系统。此外,HM采用细粒度的访问控制以保持最小权限原则。服务只能访问对功能至关重要的严格受限资源(内核对象)。因此,HM继承了微内核的安全性、可靠性和可扩展性
    • Retained:具有良好隔离和最低权限的系统服务的最小化微内核
  2. 性能优先
    • 微内核的巨大优势因新兴场景中其架构固有的性能问题而受到损害。因此,HM并不会强制执行统一但过强的隔离,而是提供结构上的支持来组装系统,以满足性能和安全要求
    • Flexibilized:通过提供结构性支持以实现灵活组装,适应多样化场景,从而优先考虑性能。
  3. 最大化生态兼容性
    • HM通过一个shim(上图中的❸)实现与现有软件生态系统的集成,确保Linux ABI兼容性,该shim将所有Linux系统调用重定向到适当的操作系统服务,并作为中心存储库存储和转换Linux抽象(例如fd),以高效支持如poll等功能
    • HM通过驱动程序容器(上图中的❹)复用未修改的Linux设备驱动程序,这种容器直接从主线Linux中派生所需的运行时,所需工程工作量较小
    • Enhanced:通过实现 Linux API/ABI 兼容和高性能驱动程序重用来最大限度地提高兼容性。

HongMeng的威胁模型: HM保留了微内核的架构设计原则,因此维持了类似于现有微内核的威胁模型,这一模型防止恶意应用程序和操作系统服务访问彼此的内存,并确保数据的机密性、完整性和可用性(CIA),但有以下不同之处:

  • 兼容性原因需要集中式内存管理,例如“文件系统”应用
  • 为了性能考虑,存在对附加攻击面、故障域的不同划分以及对精心选择的对象的额外数据泄漏可能性(不会破坏内核)的妥协

4. Performance Design of HongMeng

4.1 Synchronous RPC-like IPC Fastpath

image

IPC通常假设两端是对称的,具有相同的执行模型。因此,以往的研究提议异步IPC可以避免在多核上的串行化,允许双方在不阻塞的情况下继续执行。

然而,在新兴场景中,作者观察到大多数IPC都是过程调用(procedure calls),调用方和被调用方可以清楚地识别。此外,操作系统服务主要是被动调用的,而不是连续工作的,并且应用程序的后续操作大多依赖于过程调用的结果。因此,同步远程过程调用(RPC)是服务调用更合适的抽象。

HM采用类似RPC的线程迁移作为服务调用的IPC快速路径。当发送IPC时,核心内核执行直接切换(绕过调度),只切换堆栈/指令指针(避免切换其他寄存器)以及保护域。

性能问题 尽管HM绕过了调度并避免切换寄存器,但由于权限级别/地址空间切换和缓存/TLB污染(占总IPC成本的50%),仍然面临显著的性能下降。

Resource Allocation

  • 考虑IPC的内存占用
  • HM通过在每个线程中预绑定经常使用的操作系统服务(例如进程/内存管理器和文件系统)的堆栈,同时保持一个大小在运行时自适应调整的堆栈池,找到了一个折中点。当剩余堆栈低于阈值时,操作系统服务将分配更多以减少同步分配。HM通过在调用同一服务(例如ABA-like调用)时在IPC链中重用相同的堆栈,进一步减少了内存占用

Resource Exhaustion

如何解决“堆栈池耗尽而出现内存不足(OOM)时,操作系统服务无法分配新的堆栈来处理IPC请求”的问题:

HM通过保留一个单独的堆栈池来缓解这一问题。一旦发生OOM,内核将使用该池同步IPC到内存管理器进行内存回收(反复进行),直到用户的IPC成功。因此,保证了应用程序的IPC能够被正确处理。

Resource Accounting

  • IPC在处理请求时假定一个不同的执行实体,因此将消耗的资源归属于操作系统服务。然而,由于在新兴场景中竞争的应用程序需要明确的资源核算,因此消耗的资源应准确地归属于调用者应用程序
  • HM在处理IPC时记录用户应用程序的身份(IPC链中的根调用者),并将消耗的资源归属于它

4.2 Differentiated Isolation Classes

OS服务的隔离

image

将所有操作系统服务放在用户空间中可能会提高安全性,但无法满足新兴方案中的性能要求。作者观察到,并非所有服务都需要相同类别的隔离。

  • 成熟、经过验证和性能优先的操作系统服务可以进行较弱的隔离,以便在实际部署中获得最佳性能
  • 快速发展的服务可能会经常引入错误和漏洞,因此需要更强大的隔离来防止内核损坏

隔离等级0(IC0)、核心TCB: 经过仔细验证的、极其性能关键的、可信的操作系统服务,如ABI兼容的shim(部署中唯一的IC0服务)。

IC0威胁模型: IC0是核心TCB(Trusted computing base,可信计算基础)的一部分,任何被破坏的IC0服务都可以任意读取和修改其他服务的内存。因此,放置在IC0的服务应经过仔细验证以避免核心内核损坏。

隔离等级1(IC1)、机制强制隔离: IC1适用于性能关键和经过验证的操作系统服务。HM将这些服务放置在内核空间中,并使用机制在服务之间强制隔离。具体来说,HM仔细将内核地址空间划分为不同的域,并为每个服务分配一个唯一的域(IC0/核心内核也驻留在一个唯一的域中)。HM使用ARM观察点Intel PKS来防止跨域内存访问。 为防止这种情况,HM采用二进制扫描和轻量级控制流完整性(CFI,利用ARM指针认证(PA))来确保服务无法执行包含特权指令的非法控制流,并使用安全监视器来保护页表免受代码注入,同时通过VM退出来捕获任何特权指令,作为CFI的补充。(看不懂)

决策:并非所有的操作系统服务都需要相同类别的隔离。采用差异化的隔离类来放松受信任服务之间的隔离,以提高性能。

4.3 Flexible Composition

虽然直观上操作系统服务应该是良好解耦的,例如文件系统和内存管理器,但是作者观察到操作系统服务并不是对称的,因为某些功能需要特定服务之间的紧密合作。例如,文件系统并不是访问文件的唯一入口。POSIX支持通过内存管理器读取文件的文件映射。 (举个例子,假设你有一个大文件需要频繁读取。如果使用传统的文件I/O方法(如fread或read),每次读取都需要进行系统调用,这样会增加开销。而通过内存映射(通常使用mmap函数),你可以将整个文件或文件的某一部分映射到内存中,这样你就可以直接通过指针操作来读取文件数据,像操作数组一样)

隔离等级在同类操作系统服务之间强制执行相同的隔离。因此,没有进一步的结构性支持,HM仍然面临与宏内核相比的性能下降。

  • 解决方法:HM采用了一种可配置的方法,允许在性能需求场景中合并紧密耦合的操作系统服务,以性能换取隔离,同时在安全关键场景中保留分离它们的能力。合并后,不再强制执行隔离,两个服务之间的IPC变为函数调用,而其他服务保持原状(良好隔离)。

性能: Linux > 合并后 > 合并前

安全性: 在实践中,由于智能手机中文件操作的频率极高,其性能目标只能通过将文件系统与内存管理器合并来实现。然而,与宏内核相比,安全性仍然得到提高(与其他服务隔离)。

部署经验:使用差异化隔离等级,HM支持灵活组合,允许关键组件灵活组装(用户空间或内核空间,分离或合并),能够根据场景需求探索隔离和性能之间的权衡,并能够使用相同的代码库从路由器扩展到智能手机。

决策:操作系统服务是不对称的。协调紧密耦合的操作系统服务,并灵活地组装系统,以满足各种场景下(服务合并,尤其是内存管理器和文件系统,手机)的不同需求。

4.4 Address Token-based Access Control

尽管能力(capabilities)在描述内核对象的外部关系(即授权链)方面非常有效,但访问它们的内部内容需要将令牌与操作一起发送到核心内核,这会由于特权切换和多个元数据表的访问而引入显著的性能开销。

HM提出了一种基于广义地址令牌的方法,可以应用于更广泛的对象,从而实现高效的共同管理。

image

具体来说,如上图所示,在HM中每个内核对象被放置在一个独特的物理页面上。将内核对象授予操作系统服务需要将该页面映射到其地址空间(❶)。因此,映射的地址作为令牌,用于直接从硬件访问内核对象,而无需内核参与。内核对象可以被授予(映射)为只读(RO)或读写(RW)。操作系统服务可以在不涉及内核的情况下读取只读的内核对象。要更新它们,需要使用新的系统调用writev,传递目标地址和更新值,核心内核将通过参考内核对象的元数据来验证权限(❷)。对于读写内核对象权限,一旦授予,操作系统服务可以在不涉及内核的情况下更新它们(❸)。此外,对于小于一个页面且具有相同属性(权限)和相似生命周期的对象,HM在分配时将这些对象批量放入一个页面,从而允许它们被集体授予和撤销。

功能、安全性、同步、性能、使用场景…

决策:能力机制将内核对象隐藏在内核中,并在数据平面上进行干预(效果并不理想)。补充使用地址令牌以实现高效的共同管理。

4.5 Policy-free Kernel Paging

  • HM通过一个集中的内存管理器来管理内存。为了保持简洁性,内存管理器位于核心内核之外,负责管理物理和虚拟内存,并处理所有应用程序和操作系统服务的页面错误
  • 慢速用户空间分页,效率低

image

为了提高处理匿名内存页面错误的性能,HM预先做出策略驱动的决策,并在核心内核中留下无策略的页面错误处理机制,从而消除了关键路径上的额外IPC往返。具体来说,内存管理器提供匿名内存的地址范围以及一些预先分配的物理页面。如图7所示,如果页面错误在范围内触发(❶),核心内核可以直接将其映射到预先分配的物理页面(❷和❸),并记录一个操作日志(OPLog,❹),内存管理器将使用该日志异步更新其内部状态(例如,映射的匿名页面计数器)。否则,如果地址在指定范围之外(非性能关键)或预先分配的页面已耗尽,核心内核将向内存管理器发出IPC。

涉及的内核对象通过地址令牌由内存管理器共管理,包括页表、操作日志、记录匿名内存布局的VSpace存储预分配页面的PCache

妥协 通过提前做出政策驱动的决策,策略(是否/哪些进行映射)仍然保持在核心内核之外。唯一妥协的能力是在预分配到PCache后更改政策,这降低了灵活性。PCache还引入了一些额外的内存占用。然而,由于PCache可以定期补充(不在关键路径上),其大小保持相对较小,使这些权衡是可以接受的。

决策:通过抢占政策驱动的决策来启用无政策内核分页

5. Compatibility Design of HongMeng

5.1 Linux ABI Compatibility

在新兴场景中部署需要与 Linux ABI 兼容,这在多服务器微内核中带来了挑战。

HM通过将符合ABI的shim放置在IC0(内核空间)中实现Linux ABI兼容性,该shim将Linux系统调用重定向为针对适当操作系统服务的IPC(通过系统调用编号识别,本地系统调用绕过shim)。

部署经验: HM通过了所有AOSP兼容性和供应商测试套件(CTS/VTS)的测试,这些测试检查了内核功能和驱动程序行为。尽管大多数二进制文件可以直接运行,但作者发现一些应用程序依赖于不稳定或未记录的Linux行为,在HM上运行失败。

决策:通过与ABI兼容的shim实现LinuxABI 兼容性。

5.2 Driver Container

Linux无疑拥有最丰富的设备驱动程序生态系统。此外,一些驱动程序并不提供源代码,这使得移植变得具有挑战性。因此,重用Linux驱动程序对于广泛部署至关重要。

HM通过驱动程序容器重用Linux驱动程序,旨在找到兼容性、工程努力和关键路径性能之间的最佳平衡点。

image

兼容性 Linux驱动容器(LDC)通过重用Linux代码库作为用户空间运行时,提供所有必要的Linux KAPI,使现有的 Linux 驱动程序能够无修改地运行。HM创建了另一个设备管理器,管理 Linux和本地驱动程序容器(本地驱动程序所在的地方)。除了初始化驱动程序容器外,它还在虚拟文件系统 (VFS) 中注册条目 (❶ 在上图中),以便通过VFS的驱动程序调用(例如,ioctl ❷)可以正确重定向到相应的驱动程序容器 (❸)。

工程量 …

关键路径性能 HM通过在本地驱动程序容器中创建一个双驱动程序来应用控制平面和数据平面分离,该双驱动程序处理性能关键路径上的I/O IRQ(上图中的❹)。双驱动程序重写数据处理程序,因此可以在较弱的隔离下强制执行(位于内核空间的IC1),从而显著提高性能。控制平面包含像初始化/挂起/恢复这样的繁琐程序,仍然保留在LDC中(❺)。

决策:通过控制/数据平面分离的驱动程序容器高效重用Linux设备驱动程序。

6. HongMeng in the Wild

HM的核心内核主要是用一个有限的C子集实现的,包含90,000行代码(LoC),其中包括基本功能。所有其他操作系统服务都是解耦的,可以单独部署,总计超过100万行代码。HM的构建系统可以根据为各种场景指定的详细配置组装操作系统服务,例如将操作系统服务放置在不同的隔离类中或合并某些操作系统服务。

对于更广泛场景的容错(例如,丰富操作系统中的有状态操作系统服务)需要额外的努力来存储状态并保持其一致性,这一点留待未来工作。

在对性能要求高的场景中,如智能手机,HM将性能关键的操作系统服务放置在IC1(内核空间),包括进程管理器、内存管理器、文件系统和本地驱动程序容器,并将文件系统与内存管理器合并。Linux驱动程序容器和其他非性能关键的操作系统服务,如CPU频率调节器和电源管理器,仍然保留在IC2(用户空间)。

Performance

  • 应用冷启动时间:微内核的主要开销来自状态双重记账和慢速分页,而HM消除了这些问题
  • 应用负载:HM中提出的技术显著减少了最小性和细粒度访问控制的开销。更轻的负载也使HM能够比Linux实现更好的性能和能效
  • 掉帧:HM中的自定义QoS引导调度
  • 中断延迟:HM通过使用一种以用户体验为首的定制策略,将所有处理程序一次性执行

Lessons and Experiences

  • 兼容性优先,然后逐步本地化
    • 产品通常更倾向于为各种平台使用统一的代码库,以降本增效
    • 一些第三方应用程序/驱动程序以二进制形式分发
    • 即使旨在重建新的软件生态系统,许多基本库仍然需要Linux兼容性
    • 因此,只有首先具备兼容性,新的操作系统才能得到广泛部署,并有机会向本地接口演变,以提高性能
  • 仅符合兼容标准是不够的,检查兼容性需要大规模测试
    • 实现完全兼容是困难的(如果可能的话),主要是由于Hyrum定律
    • HM不是满足某些规范,而是通过大规模测试来检查兼容性,这对于发现隐藏的兼容性问题是必要的
  • 先部署,然后持续优化
    • 微内核很难在最初满足所有性能目标,需要全系统的优化(例如,框架,甚至硬件)
    • 没有部署,促进多个团队之间的合作进行这些优化是困难的
  • 尽可能使用自动化验证
    • 由于代码规模和功能的快速增长,完全形式验证(使用交互式定理证明)是不可持续的
    • 对关键组件采用半形式验证,并使用自动化验证和验证引导测试来提高代码质量
  • 规模效应导致硬件错误/bug放大
    • 一些低概率的硬件故障或错误在大规模部署时相对容易发生,显著影响用户体验,并且在安全关键场景中可能是致命的
    • HM通过将关键驱动程序隔离在不同的LDC中、在TEE中重启无状态驱动程序以及创建监控看门狗来缓解这些问题
  • 大内核锁在新兴场景中不可扩展
    • 手机的系统调用频率很高(61k/s),导致了显著的争用
    • 新兴场景需要一些复杂的功能,持续时间较长

 

============ End

 

posted @ 2025-09-07 19:57  lsgxeva  阅读(79)  评论(0)    收藏  举报