0%

操作系统结构

参考: 中国科学院大学 2025年秋《高级操作系统教程》课件

重要设计原则:策略与机制的分离

  • 策略(Policy):要做什么 – 相对动态
  • 机制(Mechanism):该怎么做 – 相对静态
  • 操作系统可仅通过调整策略来适应不同应用的需求

操作系统架构分类:

  1. Monolithic-Kernel, 宏内核
  2. Microkernel, 微内核
  3. Exokernel, 外核
  4. Multikernel, 多内核

操作系统结构的演进与生态:

  • 系统软件需要一条演进之路
    • 尽可能集成现有的POSIX API/Linux ABI
    • 避免棘手的系统调用(如fork)
    • 避免不可扩展的POSIX API
  • 系统软件一直在不断演化
    • 例:Linux Userspace I/O (UIO),向微内核近了一步
    • 单节点下也存在更多的分布式、低时延的可编程设备
    • 非易失性内存的出现可能推动存储层次在OS中的完全改革

Monolithic-Kernel, 宏内核

monolithic

整个系统分为内核与应用两层

  • 内核:运行在特权级,集中控制所有计算资源
  • 应用:运行在非特权级,受内核管理,使用内核服务

实例:Windows, Linux, Unix, BSD, xv6

优点:

  • 宏内核拥有丰富的沉淀和积累
    • 拥有巨大的统一的社区和生态
    • 针对不同场景优化了30年
  • 内核设计者不需要决定哪一部分运行于完整特权之下
  • 操作系统各组件之间更容易交互(但更复杂)

缺点:

  • 结构性缺陷
    • 安全性与可靠性问题:模块之间没有很强的隔离机制
    • 实时性支持:系统太复杂导致无法做最坏情况时延分析
    • 系统过于庞大而阻碍了创新:Linux代码行数已经过2千万
  • 难以满足很多场景
    • 向上向下的扩展
      • 很难去剪裁/扩展一个宏内核系统支持从KB级别到TB级别的场景
    • 硬件异构性
      • 很难长期支持一些定制化的方式去解决一些特定问题
    • 功能安全
      • 一个广泛共识:Linux无法通过汽车安全完整性认证(ASIL-D)
    • 信息安全
      • 单点错误会导致整个系统出错,而现在有数百个安全问题(CVE)
    • 确定性时延
      • Linux花费10+年合并实时补丁,目前依然不确定是否能支持确定性时延

Microkernel, 微内核

microkernel

设计原则:最小化内核功能

  • 将操作系统功能移到用户态,称为”服务”(Server)
  • 在用户模块之间,使用消息传递机制通信: IPC

优点:

  • 易于扩展:直接添加一个用户进程即可为操作系统增加服务
  • 易于移植:大部分模块与底层硬件无关
  • 更加可靠:在内核模式运行的代码量大大减少
  • 更加安全:即使存在漏洞,服务与服务之间存在进程粒度隔离
  • 更加健壮:单个模块出现问题不会影响到系统整体

缺点:

  • 性能较差:内核中的模块交互由函数调用变成了进程间通信
  • 生态欠缺:尚未形成像Linux一样具有广泛开发者的社区
  • 重用问题:重用宏内核操作系统提供兼容性,带来新问题

实例

Mach 微内核

第一代微内核,CMU 开发

实现功能:

  • 任务和线程管理
    • 任务,是资源分配的基本单位;线程,是执行的基本单位
    • 对应用提供调度接口,应用程序可实现其自定义的调度策略
  • 进程间通信(IPC):通过端口(port)进行通信
  • 内存对象管理:虚拟内存
  • 系统调用重定向:允许用户态处理系统调用
    • 支持对系统调用的功能扩展,例如,二进制翻译、跟踪、调试等
  • 设备支持
    • 通过IPC实现(通过port来连接设备)
    • 支持同步设备和异步设备
  • 用户态的多进程
    • 类似用户态的线程库,支持wait()/signal()等原语
    • 一个或多个用户态线程可映射到同一个内核线程
  • 分布式支持
    • 可透明地将任务与资源映射到集群中的不同节点
  • Mach 允许用户态代码实现 Paging
    • 应用可自己管理自己的虚拟内存
  • 重定向功能(Redirection)
    • 允许发生中断/异常时,直接执行用户的二进制
    • 这种连接不需要对内核做修改

L3/L4

  • L4的IPC性能比Mach快20倍
    • IPC仅传递信息
    • 使用寄存器传参,限制消息长度
    • 内核去掉了IPC的权限检查等功能,交给用户态判断
    • 系统服务的接口直接暴露给用户态,可能导致DoS攻击

启发了大量相关系统: Pistachio, L4/MIPS, Fiasco 等

seL4

  • 基于L4的微内核
  • IPC机制:端点(endpoint)
    • 通过Capability进行IPC的权限判断
    • Capability可被复制和传输
  • 第一个完成形式化验证的内核

QNX Neutrino

满足实时要求: 广泛用于交通、能源、医疗、航天航空领域,如波音

Google Fuchsia

  • Google 开发的全新 OS
    • 试图覆盖多个领域,用途尚未完全宣布
  • 使用 Zircon 微内核
    • 仅提供IPC, 进程管理, 地址空间管理等功能

主要优化目标:优化 IPC 开销

IPC 开销来源

  1. 特权级的频繁转换
  2. IPC 调用本身在进程间的数据拷贝
  1. 减少 IPC 数量
    1. 将部分对性能要求高的 server 重新放回内核(混合内核架构)
    2. 合并部分 server (将 server 之间的 IPC 调用改为函数调用)
  2. 减少单次 IPC 延时
    1. DMA 传输数据
    2. 零拷贝(server 进程间共享部分内存)

Exokernel, 外核

  • 不提供硬件抽象
    • “只要内核提供抽象,就不能实现性能最大化”
    • 只有应用才知道最适合的抽象(end-to-end原则)
  • 不管理资源,只管理应用
    • 负责将计算资源与应用的绑定,以及资源的回收
    • 保证多个应用之间的隔离

设计原则:“将管理与保护分离”, 整个操作系统分为 Exokernel(内核态) + Libos(用户态)

优点:

  • OS无抽象,能在理论上提供最优性能
    • 未修改应用性能最多提升4x,定制化应用性能最多提升8x
  • 应用对计算有更精确的实时等控制
  • LibOS在用户态更易调试,调试周期更短

缺点:

  • 计算资源的利用效率主要由应用决定
  • 定制化过多,导致维护难度增加

生态问题:Linux as a LibOS?

  • 将Linux作为LibOS或Unikernel
    • 例:LKL - Linux kernel library (https://github.com/lkl)
    • 将系统调用变为普通函数调用
    • 可提供一定的兼容性,有效避免重复开发
  • 许多新问题
    • Linux是否适合作为LibOS/unikernel?
    • fork()如何处理?
    • 尚在探索阶段

LibOS

  • 策略与机制分离:将对硬件的抽象以库的形式提供
  • 高度定制化:不同应用可使用不同的LibOS,或完全自定义
  • 更高性能:LibOS与应用其他代码之间通过函数调用直接交互

Exokernel 外核设计

功能:

安全绑定(Secure binding)

将 LibOS 与计算资源绑定

  • 可用性:允许某个 LibOS 访问某些计算资源(如物理内存)
  • 隔离性:防止这些计算资源被其他 LibOS 访问

例:利用software TLB保证LibOS只使用了自己的物理内存

  • LibOS 可直接修改页表,因此可能会将自己的页表指向其他 LibOS 物理页
  • Software TLB 是软件可控的 TLB,MIPS 等处理器支持
  • 每次发生 TLB miss 时,由 Exokernel 负责遍历页表并填写对应的 TLB 项
  • Exokernel 可在填写 TLB 项时检查 LibOS 对内存的使用是否合法

显式回收(Visible revocation)

  • Exokernel 与应用之间的协议
    • Exokernel 显式告知应用资源的分配情况
    • 应用在租期结束之前主动归还资源

中止协议(Abort protocol)

  • 若应用不归还资源,则强制中止
    • Exokernel 拥有对资源的控制权
    • 主动解除资源与应用间的绑定关系

实例

Unikernel(单内核)

  • 可以看做虚拟化环境下的LibOS
    • 每个虚拟机只使用内核态
    • 内核态中只运行一个应用+LibOS
    • 通过虚拟化层实现不同实例间的隔离
  • 适合容器应用场景
    • 每个容器就是一个虚拟机
    • 每个容器运行定制的LibOS以提高性能

部分开源项目:

  • Rumprun
    • POSIX接口,BSD兼容的运行时环境
    • 运行在Xen虚拟化平台之上
  • Drawbridge
    • 来自微软,兼容Win32接口的运行时环境
  • OSv
    • 与Linux兼容的应用环境,单地址空间

Libra

基于虚拟机实现的JVM
Libra

Drawbridge

Drawbridge

MultiLibOS

MultiLibOS

Multikernel, 多内核

设计动机:解决多核与异构带来的扩展性问题

  • 多核:OS内部维护很多共享状态
    • Cache一致性的保证越来越难
    • 可扩展性非常差,核数增多,性能不升反降
  • 异构: GPU 等设备越来越多
    • 设备本身越来越智能——设备有自己的CPU
    • 通过PCIe连接,主CPU与设备CPU之间通信非常慢
    • 通过系统总线连接,异构SoC

设计思路:

  • 默认的状态是划分而不是共享
    • 硬件资源在操作系统启动时必须静态划分
  • 维持多份状态的copy而不是共享一份状态
    • 提供单一系统镜像
  • 显式的核间通信机制
MultiKernel
  • 在每个core上运行一个小内核 (包括CPU、GPU等)
  • OS整体是一个分布式系统
  • 应用程序依然运行在OS之上

问题:

  1. 资源调度困难
  2. 安全性问题:内核 A 可以通过直接访问底层硬件(每个内核的特权级都是最高的)访问内核 B 的资源
    • 软件无法解决
    • 硬件方案:标签化内存控制,IBM 的硬件隔离虚拟化

Barrelfish

第一个多内核架构 http://www.barrelfish.org/documentation.html

  • 来自ETH Zurich和微软研究院
  • 支持异构CPU
  • 在CPU核与节点之间提供通用异构消息抽象

设计结构:

Barrelfish
  • 每个core对应一个内核
    • 类似”CPU驱动”,适应不同CPU
    • 负责执行系统调用,处理中断/异常
    • 事件触发,单线程,不可中断
    • 内核调度并运行”Dispatcher”
  • Dispatcher
    • 类似线程
    • 多个Dispatcher组成一个Domain
  • Domain
    • 类似进程

提供本地 IPC 和远程 IPC 实现对于不同资源的访问

Popcorn Linux

Popcorn Linux
  • 支持异构体系结构(ARM、x86等)
  • 多个 Linux 内核副本
    • 一套代码编译不同副本
    • 不同 ISA 不同副本
    • 多个副本同时向上提供 OS 服务

将 Linux 移植为 Popcorn Linux ,需要改启动代码,虽然扫描到所有硬件,但只能使用其中一部分硬件(静态划分)

Tessellation

Tessellation

设计理念:

  • 时空分割(STP,Space-Time Partition)
  • 二级调度(Two-Level Scheduling)
    • 应用先分配到内核上,再由内核分配到相应的 CPU 上
Tessellation Schedule

FOS

  • 设计理念
    • 空间共享取代时间共享
    • 将应用程序与系统服务区别对待,为系统服务提供专用核心
    • 消息传递机制代替共享内存机制,内核之间不共享数据
  • 三层架构
    1. 微内核层
    2. 系统服务层
    3. 应用程序层
FOS
  • 每个核上跑一个 microkernel
  • 应用程序只绑定到服务该程序的内核,减少上下文切换和 cache 切换

HeilOS

设计理念:

  • 多内核、单一镜像架构
    • 一个主内核 + 其他微内核
  • 亲和度(Affinity Metric)
  • 二级编译
HeilOS

K2

K2
  • 双内核:适配强弱核
  • 基于同构 ISA ,调度大小核

LegoOS

SplitKernel

  • 分离内核功能
    • 每个核上跑一个 microkernel
    • 把一个内核的功能拆开,每个子功能作一个 microkernel 分给其他核
  • 不同的硬件上运行不同的硬件程序
  • 模块之间通过消息传递来交换
  • 全局的资源和错误管理