Maybe we should revisit microkernels

Maybe we should revisit microkernels

也许我们应该重新审视微内核

Microkernels If you want a complete description of what microkernels are then read the wikipedia article, but in one sentence it’s a kernel where everything is in userspace except for scheduling, managing access to I/O devices, and IPC. 如果你想全面了解什么是微内核,可以去阅读维基百科。简单来说,微内核就是除了调度、I/O 设备访问管理和进程间通信(IPC)之外,其余所有功能都运行在用户空间的内核。

Why microkernels? Better security, better reliability, better modularity. Better security because in a microkernel system a bug in one driver only gives an attacker access to that subsystem (or maybe even that driver), as opposed to having unlimited access to the whole system like is the case with mainstream operating systems today. 为什么要使用微内核?因为它具有更好的安全性、可靠性和模块化。安全性更好是因为在微内核系统中,某个驱动程序的漏洞只会让攻击者获得对该子系统(甚至仅限于该驱动程序)的访问权限,而不像当今主流操作系统那样,攻击者可以获得整个系统的无限访问权限。

Better reliability because a crash in one subsystem only crashes that subsystem instead of crashing everything; if windows were a microkernel system then the crowdstrike bug would have just stopped some IT security staff from getting telemetry instead of being front page news. 可靠性更好是因为某个子系统的崩溃只会导致该子系统本身停止工作,而不会导致整个系统崩溃;如果 Windows 是一个微内核系统,那么 CrowdStrike 的故障只会导致一些 IT 安全人员无法获取遥测数据,而不会成为全球头条新闻。

If linux were a microkernel system then the linux kernel team wouldn’t be responsible for merging every driver for every hardware device, and wouldn’t be responsible for vetting code that they would have to become experts on the inner workings of every chip supported by the linux kernel to properly vet. 如果 Linux 是一个微内核系统,Linux 内核团队就不必负责合并每一个硬件设备的驱动程序,也不必负责审查那些需要他们成为每种芯片内部工作原理专家才能正确评估的代码。

Why not microkernels? If microkernels are so much better why isn’t every OS a microkernel OS? Lots of people were asking that question in the 80s and 90s, and a lot of them made microkernel OS’s, and it turned out the answer was that the overhead was too high. The overhead was too high because computers in the 80s didn’t have a way for a userspace process to directly access a particular hardware device. That means that every time eg: the filesystem wanted to do a disk read, it had to do a system call, which triggered a context switch, which triggered a whole bunch of expensive locking and memory copying. 为什么不使用微内核?如果微内核这么好,为什么不是每个操作系统都采用它?在 80 和 90 年代,很多人都在问这个问题,并且开发了许多微内核操作系统,但结果发现开销太大了。开销过大的原因是 80 年代的计算机没有让用户空间进程直接访问特定硬件设备的方法。这意味着每当文件系统想要进行磁盘读取时,它都必须执行系统调用,这会触发上下文切换,进而引发大量昂贵的锁操作和内存拷贝。

Why microkernels now? In a word: IOMMU. Virtually all PCs in use today have IOMMUs, they’ve been standard issue for about a decade. By using IOMMU and shared memory in the right way you can completely eliminate context switches from the happy path (which is the case where you have enough cores that all the work that needs to be done can be done by processes that are currently running), and virtually eliminate it overall if you’re willing to accept a little bit of latency. 为什么现在又提微内核?一言以蔽之:IOMMU。如今几乎所有在用的 PC 都配备了 IOMMU,这已成为过去十年的标准配置。通过正确使用 IOMMU 和共享内存,你可以完全消除“正常路径”(即拥有足够的内核,使得所有工作都能由当前运行的进程完成的情况)中的上下文切换,如果你愿意接受一点点延迟,甚至可以在整体上几乎消除它。

There are three key things that the kernel has to do in a microkernel system: scheduling, inter-process communication, and managing access to I/O devices. The scheduler for a microkernel that’s based on virtualization technology (which IOMMU is part of) would look like the Xen hypervisor. Access to I/O devices is managed in hardware by the IOMMU. 在微内核系统中,内核必须完成三件关键任务:调度、进程间通信(IPC)以及管理 I/O 设备访问。基于虚拟化技术(IOMMU 是其中的一部分)的微内核调度器看起来就像 Xen 虚拟机管理程序。I/O 设备的访问则由 IOMMU 在硬件层面进行管理。

For zero-overhead (at least in the happy path) IPC all you need is the ability to allocate shared buffers between processes and integer atomic compare-and-swap. That lets you use the shared buffer as a command queue; just a ring buffer with atomics on bumping the start and end pointers. That lets you asynchronously pass messages with no context switches, no copying between address spaces and no locks. This pattern is used a lot in things like GPU drivers today. 为了实现零开销(至少在正常路径下)的 IPC,你只需要具备在进程间分配共享缓冲区以及整数原子比较并交换(CAS)的能力。这让你能够将共享缓冲区用作命令队列;只需一个带有原子操作来更新起始和结束指针的环形缓冲区即可。这使你能够异步传递消息,而无需上下文切换、无需在地址空间之间进行拷贝,也无需锁。这种模式在当今的 GPU 驱动程序中被广泛使用。

What about shared libraries? How do shared libraries work when your OS processes are actually VM guests? Link them into the program at launch time and implement everything that doesn’t need to happen in another process locally, exokernel style. These days every app ships with a copy of its own operating system anyway (in the form of electron), so having redundant copies of libraries in memory isn’t the issue it was thirty years ago. 共享库怎么办?当你的操作系统进程实际上是虚拟机客户机时,共享库如何工作?在程序启动时将它们链接进去,并以 Exokernel(外核)风格在本地实现所有不需要在其他进程中完成的功能。如今,每个应用程序都会自带一份自己的操作系统副本(以 Electron 的形式),因此在内存中拥有冗余的库副本已不再像三十年前那样是个问题了。

What would it take to actually implement something like this? Actually not that much. Xen already has most of what you need for the hypervisor layer. You can copy what Mach did and implement the servers for network, filesystem, etc by copying the code from freebsd. DRM is already based around asynchronous command buffers so you could copy the graphics subsystem from linux and run it in userspace (though it might be convenient to run the display server in the same process). A good example is what happened to the Mach kernel, which is the ancestor of XNU, the kernel of macos and ios. They gradually moved all the userspace processes back into the kernel for performance reasons until it was just a regular monolithic kernel. 真正实现这样的系统需要什么?其实并不多。Xen 已经具备了虚拟机管理层所需的大部分功能。你可以借鉴 Mach 的做法,通过复制 FreeBSD 的代码来实现网络、文件系统等服务器。DRM(直接渲染管理器)已经基于异步命令缓冲区,因此你可以从 Linux 复制图形子系统并在用户空间运行它(尽管将显示服务器运行在同一进程中可能更方便)。一个很好的例子是 Mach 内核的遭遇,它是 macOS 和 iOS 内核 XNU 的前身。出于性能考虑,他们逐渐将所有用户空间进程移回内核,直到它变成了一个普通的单体内核。