Motivation 和论文目标

守旧派往往认为, 第一代 μ\mu-kernel 微内核具有非常低的 performance/flexibility, 但是本文希望能测试第二代微内核的性能和灵活性, 实验手段是测试一些老的系统性能测试以及加上一些新的有针对的测试

微内核的优点之一是, 内核小巧, 部件坏的概率小

微内核只提供 mechanism 但是不提供 policy, 但是也需要上面一层安全控制的 pager, FS 等资源, 这些往往依赖于 UNIX Server 实现

Introduction

L4 kernel 本身是一个第二代微内核, 拥有 lean & fast 的特性

最初的 L4 kernel 是开发于 Pentium Platform 的, 但是为了证明这个内核抽象能够独立于硬件平台, 所以本文将 L4 在 Alpha21164 平台上重新完整实现了一次并且保留了传统 L4 的接口 (interface); L4 当下是支持 Pentium, Alpha 和 MIPS 三个架构, 后两者为新开发的功能

Pentium 内存空间优化

L4/Pentium 版本在 small-address-space 情况下有 optimization:

  • 如果某个线程用到的虚拟地址空间比较小(例如 4MB 到 512MB), 那么它可以被认为是 small space
  • L4 可以让这种小空间在所有页表中 物理共享, 并利用 Pentium 的 分段机制 来保护
    • 这样做的效果是: 当线程切换时, 不需要频繁刷新整个 TLB(Translation Lookaside Buffer), 就好像 CPU 原生提供了 tagged TLB 功能一样
  • 如果某个线程在 small space 里运行, 突然访问了超出 small space 范围的地址, 内核会 自动把它切回到正常的 3GB 地址空间模型
  • 在同一个任务(task)里, 有些线程可能运行在 normal 3GB 空间, 有些则在 small space 中;二者可以并存

L4Linux 设计了一个特殊的 lib 来支持这种内存优化, 并且会将 emulation lib, singal
thread 映射到靠近 app 的位置来实现小内存空间优化, 这样的优化可以避免很多系统资源调度冲突 (因为减少了很多 TLB flush)

本系统中用到这个哲学的是 pager

Linux 双层 it handler

Linux 的中断处理是双层的, 包括一个高优先级 (top-halves) 中断处理器和一个低优先级 (bottom-halves) 中断处理器;
前者的中断无法被打断, 往往由硬件驱动直接触发, 后者则只能被 top-halves 打断;
Linux server 的 用户态会存在多个 it-handler 线程, 其中 1 个是 bottom-halves 而其他都是 top-halves, 这样做其实可以避免并发处理中断

Device Driver

由于 L4 内核是基于 Pentium 架构的, 但是我们的设计目标是尽量保持 Linux Server 整体代码不动, 主要修改 L4 Kernel, 所以我们要求外设 Device Driver 基本上直接使用 Linux/x86 版本的

Linux 进程机制

一般来说 Linux 进程的组成是 执行流 thread 和 内存空间 address space 的结合, 但是这两个资源都是属于 L4 内核的, 这里控制应该要用远程进程间通信 RPC (远程一般默认能跨平台, 所以更适合用在这里), 例如在 Linux 中发生了 page fault, 那么就会将这个报错传递给 L4 内核然后由 L4 使用 RPC 发到 Linux server 进行处理, 这里可能涉及一些 syscall 调用(后文会讨论) 例如 map/unmap 指令 然后再返回给对应 Linux 进程即可

Map 的实际操作是将复制得到的副本添加一个指向原进程空间的映射/引用, 这就是原文提及的 “recursive”

传统的 Linux 设计是将内核地址映射放到每个用户进程的高地址空间, 这样做的好处是用户态可以直接访问内核指令而不需要切换用户空间到内核, 可以提高效率

System-Call Mechanisms

和上文提及的进程通讯类似, 系统调用由于跨平台的原因也要用 RPC 来实现, 此处一共设计了 3 中系统调用接口:

  1. 一个

Signaling

  • 传统 Linux 内核会将 Signaling 处理变成直接将信号传递到对应的 用户进程的 stack
    上并且操纵 pc/ic 来实现控制, 把 signal handler 压到用户栈上, 然后下一次用户态执行时就跳转到信号处理函数, 具体参考 EECS 482 P2 中的 IT handler 机制.
  • L4 处于安全考虑禁止了这种 inter-thread manipulation to thread sharing the same addr space
    • L4 的适配做法是向目标进程发送一个对应的 manipulate thread 来处理这个 signal thread, 从而让 user thread 进入 Linux Server 的 main thread 来继续执行

Scheduling

调度算法有 L4 内核内部完成实现, 会将时间切片称 Time Slice, 然后只有当到时间切片节点且任务已经完成的时候会考虑更换线程

整个调度算法符合 Priority + Round-Robin: 首先考虑 优先级 , 同优先级下支持 round-robin 轮训, 并且一共四个优先级:

1
interrupt top-half > interrupt bottom-half > Linux kernel > Linux user process

因此在 用户态内所有进程调度其实是遵循纯 round-robin 算法的

内核+用户空间映射 模式的局限性

原生 Linux/x86 的做法

  • 在传统 Linux/x86 中, 每个进程的虚拟地址空间都是 4GB:
  • 高地址部分(通常 1GB): 内核空间, 所有进程共享;
  • 低地址部分(通常 3GB): 用户空间, 进程私有;