LWN:32位Linux的未来!

关注了就能看到更多这么棒的文章哦~

The future of 32-bit Linux

December 4, 2020
This article was contributed by Arnd Bergmann
https://lwn.net/Articles/838807/

近年来关于处理器(Processor)和 SoC (system-on-chip) 的新闻都是围绕着最新的计算机和智能手机中的 64 位处理器的,因此人们很可能会被误导认为 32 位硬件已经被飞起了。甚至因此有人提议要把 kernel 里面对 32 位硬件的支持代码全部移除,因为这样可以让内核开发者更加轻松。其实,此时此刻售出的嵌入式系统中绝大多数都是在使用 32 位处理器的,因此这里确实有一个问题需要搞清楚:这个现状后续会发生变化吗?也就是说,32 位的设备是否今后一直会是那些资源受限的环境下最适合的解决方案。

为了找出这个答案,我们应该看看 Linux 如今所支持的各种系统,以及它们在 64 位架构出现之后是如何发展的,为什么它们仍然很受欢迎,以及如今和未来会面对哪些挑战。

32-Bit desktops

Linux 起初是为 IBM PC 兼容机的桌面系统而开发的,最终在 1990 年代的时候被移植去支持几乎所有的桌面平台了,包括许多不同架构的早期的 Unix 工作站。慢慢地,这些设备都被替换成了 64 位设备,或者彻底从市场上消失了。Unix 工作站的结局是两种情况都有。最早期的 i386, Arm, MIPS, PowerPC 处理器都慢慢的随着时间推移而慢慢消失了,不过后期的大多数产品则仍然在使用中。

下面的表格展示了最流行的那些 32 位桌面平台,都成功的进入了 Linux mainline 并且一直保留着,一直有一些忠实用户在支持:

PlatformArchitecturesEarliest supported machineLast supported 32-bit machineEnd of marketingReplaced by
Unix workstationm68k
MIPS
SPARC
PA-RISC
PowerPC
Sun-3/60
(1985)
IBM RS/6000 43P-240,
HP Visualize B180L
(1997)
1999x86 Linux, 64-bit Unix
Apple Macintoshm68k
PowerPC
ia32
Mac II (1987)Macbook
(2006)
2007x86-64, arm64 Mac
IBM compatible PCia32PS/2 model 70 486
(1989)
Intel Atom D270 Netbooks
(2009)
2011x86-64 PC
Amigam68k
PowerPC
A2500
(1989)
AmigaOne SE
(2003)
2004-
Atarim68kAtari TT
(1990)
Falcon
(1992)
1993-
Acorn RiscPCArmStrongARM RiscPC
(1996)
StrongARM RiscPC J233
(1997)
2003-
NetwinderArm
x86
Netwinder “Frog” (1999)NetWinder 3100
(2001)
2001-
Android Tablet/LaptopArm
ia32
MIPS
Nexus 7
(2012)
Various, Android 8
(2019)
Ongoingarm64
ChromeOSArmSamsung 303c
(2012)
Asus Chromebook Flip
(2015)
2017x86-64, arm64
Baikal T1MIPSTavolga Terminal
(2018)
Tavolga Terminal
(2018)
Ongoingarm64

上面的表格中,只有使用 Armv7 处理器的 Android tablet 在 2020 年还在广泛使用了,不过看起来也快要退出市场了。基于 64 位的 Armv8 CPU 的 Android tablet 不仅功能更加强大,通常也更加便宜。Linux mainline 里针对许多 32 位 Android tablet 的支持代码是最近才刚刚合入的。不熟悉 Arm 处理器的分类的读者可以看这里 https://en.wikipedia.org/wiki/List_of_ARM_microarchitectures

Baikal T1 芯片很特别,它只是在俄罗斯的国内市场使用,避免依赖芯片进口。它也有一个 Armv8 的新一代产品,不过还没有广泛部署。Baikal T1 的 Linux kernel 支持代码是在 2020 年合入的。

Traditional embedded Linux

嵌入式系统中使用 Linux 是在 1990 年代末期的时候开始的,现在慢慢地已经扩展到了大约 30 种体系架构了,Linux 替换了大多数嵌入式平台的其他操作系统。其中,许多架构都是那些围绕着自己的 CPU 核心来搭建 SoC 的公司所建立的定制化的体系架构。慢慢地,CPU IP 授权逐渐占领了大部分市场,包括 MIPS, PowerPC, x86,SuperH 处理器等,不过后来 Arm 又替代了它们。

下面是 Linux-5.10 中所支持的主流处理器家族中,最新的可以拿到授权的 32 位产品的列表:

CoreArchitectureIntroducedReplacementNew Architecture
Renesas SH-4ASuperH2004(Licensed from Arm)Armv7-A, Armv8-A
AMCC PowerPC 460Power ISA 2.032006X-GeneArmv8-A
IBM PowerPC 470Power ISA 2.042008IBM A2ppc64le
Freescale e500mcPower ISA 2.062008(Licensed from Arm)Armv7-A, Armv8-A
MIPS Warrior P5600MIPS32r52014P6600, I8500MIPS64r6, RV64
Arm Cortex-A17Armv7-A2014(various)Armv8-A
Cadence Xtensa LX7Xtensa LX2016(unknown)(unknown)
Andes D15FNDS32v32017A25, AX25RV32, RV64
OpenCores mor1kx v5OpenRISC 10002017(various)RV32, RV64
Microblaze v10.0Microblaze322017Microblaze v11.0Microblaze32,Microblaze64
ARC HS4xARCv22017HS5x, HS6xARCv3 (32/64 bit)
MIPS Warrior I7200nanoMIPS2017I8100RV64
T-HEAD CK870C-SKY v22018C910RV64
Gaisler LEON5SPARCv82019NOEL-VRV64

从表格中可以看到,几乎所有的 CPU core 都有了来自原有设计者的 64 位版本了,不过大多数厂商会继续支持 32 位产品。Hitachi(现在的 Renesas) 和 Freescale(now NXP) 都提出了它们自己的 SuperH 和 PowerPC 核心的 64 位版本,不过后来都抛弃了自己的设计,转而使用 Arm Cortex-A core 的授权。

OpenRISC 项目仍然活跃,不过许多贡献者都已经去参与 RISC-V 设计了。Cadence Tensilica 还没有宣布它们的 Xtensa LX7 的继任者,不过肯定会继续专注于它自己的 DSP core。

一些 CPU core 在新的 SoC 中使用了很长时间。比如 Arm9 CPU 是在 1998 年产生的,在 2001 年更新了 Arm926EJ-S,不过在最新的 2019 年的 SAM9X60 中仍然在使用。不仅如此,Microchip 还在支持 mainline Linux 中的 2003 年的古老的 AT91RM9200,承诺只要有需求就会继续销售。

厂商针对一款产品定义的生命周期可以作为判断它会流行多久的一个指标,不过这并不等同于它能一直得到 kernel 更新。许多嵌入式设备都是用很早的 kernel 版本来发布的,不会再升级。还有一些产品可能在销售了最后一台设备的很多年之后仍然会被要求提供定期的 kernel 更新。

下面这个表格列出了那些基于很早的 CPU core 或者 CPU architecture 但是今后几年仍会在生产的芯片。多数都有一个更强大、更新的 Armv7 或者 Armv8 的处理器可以用来替换:

SoC nameCPUIntroducedArmv7/v8 ReplacementProjected EOL
Renesas SH7734SH-4A2010RZ, R-Car seriesMarch 2025
NXP QorIQ P3041PowerPC e500mc2010QorIQ LayerscapeJune 2025
NXP MCF5441xColdfire v4 (m68k)2010i.MXSeptember 2025
Broadcom BCM2835Arm1176JZF-S2011BCM2836+January 2026
Qualcomm QCA9531MIPS 24Kc2014IPQ series
Intel Quark SE C1000Quark (486-like)2015-July 2022
Allwinner F1C200sArm926EJ-S2017sunxi series
Microchip SAM9X60Arm926EJ-S2019SAMA5
DM&P Vortex86EX2Dual i686-like2019-February 2029
Mediatek MT7621DATMIPS 1004Kc2019MT7622
Ingenic X2000Xburst2 (MIPS32r5)2020-

表格中的 end-of-life 日期通常是指厂商保证可以发货的最后日期,通常是在首次生产的 10 或 15 年之后,不过对于那些 BCM2835 这种流行的芯片来说,哪怕最后一颗芯片已经发售之后过了很久,也还是需要提供 kernel 更新的。基于 m68k 的 Coldfire MCF5441x 是个很有趣的例子,它代表了 Linux 能运行的最古老的体系架构,同时它至少直到 2025 年都会一直可售,这会是它的 Sun-3 前辈(Linux 支持的最古老的 machine)发售 40 年之后的事情了。那时,它的生命周期就会超过所有其他那些试图取代它的 32 位体系架构了。

最近的使用场景是放在包含 32~256 MB 的 DRAM 的 system-in-package 处理器里面。这样可以降低板级设计的成本,这也是不用常见的 Armv7 产品而使用它的主要原因。

Microcontrollers and DSPs

SoC 和 microcontroller (MCU) 的区别很难定义清楚。通常来说,microcontroller 是指一个高度集成的系统,但是又不包括现代 SoC 内部的若干个基本功能:MMU, data cache, external DRAM memory, 或者 IEEE-754 兼容的浮点运算单元(FPU)。Linux 并没有强制要求要具有这些模块,但是如果没有 MMU 的话会导致许多 application 无法用在这个系统之中。

DSPs (digital signal processor) 是另一种特殊的处理器。跟现在已经被移除的 Blackfin 架构一样,德州仪器的 C6x 和高通的 Hexagon DSP 都可以有限地运行 Linux,不过很少有人这么用。一般情况下这些处理器都是运行 bare-metal code(裸代码)来跟运行在同一颗芯片里的 Arm core 上的 Linux 系统进行通讯。

不带 MMU 的处理器,在 2002 年的 Linux-2.5.45 中就有支持了,不过很快人们就宣称不继续支持了。最高峰的时候又 12 个不带 MMU 的 CPU 架构得到了支持,不过大多数都已经废弃了,最新 mainline kernel 已经不再支持。下面的是 Linux-5.10 中仍然支持的一些 SoC:

MCU nameCPUIntroduced
NXP MCF537xColdfire v32007
NXP LPC4357Cortex-M42012
TI TMS320C6678C662014
J-core FPGA SoCJ22016
ST STM32H7Cortex-M72016
Mediatek MT3620Cortex-A72017
NXP i.MX RT1050Cortex-M72017
Kendryte K210RV642018
Espressif ESP32-S2Xtensa LX72019

现在最活跃的运行 Linux 的 microcontroller 是 STM32 系列。它们比低端的 MIPS32 或者 Armv5 芯片要便宜,所以在那些成本比性能和额外开发成本更高的情况下会使用它们。功耗和芯片面积也是优势。有些产品是完全运行在内置的 2MB SRAM 中的,其他的则使用 DRAM 或者 PSRAM,不过会增加成本。

i.MX RT 系列,MT3620,ESP32 的 Linux 内核支持并没有合入 mainline。Kendryte K210 则是一个特别的不带 MMU 的 64 位 CPU 系统。kernel 支持它主要是因为目前没有其他便宜的 RISC-V 芯片拥有 Linux 支持。Mediatek MT3620 同样很特别,它是针对 Microsoft Azure Sphere 设计的,虽然包含 MMU,但是 Linux 是完全运行在内置的 4MB SRAM 里面的。

microcontroller 上的 Linux 是在跟许多开源实时操作系统在竞争,包括 Zephyr, NuttX, Mbed, FreeRTOS。这些系统通常都只需要更少的 memory,也更适合运行在没有 MMU 的平台上。

Linux on Armv7-A

提及 Armv7 在嵌入式世界中的重要性,无论多么夸张都不为过。这里很大一部分归功于持续不断追求更快更高效的处理器的智能手机们。从 2008 年的高端的 Nokia N96 一直到今年的 Apple iPhone 12,我们看到时钟频率有 10 倍的增长,流水线宽度有 8 倍增长,而 CPU core 的数量则增长了 6 倍。

Cortex-A9 基本上打败了当时竞争的所有 32 位处理器 core。它拥有乱序流水线的优势,可以拥有 4 个 core,NEON SIMD, 40nm 工艺,后来就成为了历史上最成功的可以拿到授权的 32 位 CPU core。在 Linux-5.10 中,有 76 款 SoC (或者说 30 SoC families)的 452 个 devicetree 文件,远比其他的 Arm core 要多,更加超过所有非 Arm 平台的总和。

广受欢迎的 Cortex-A9 是 Armv7-A 架构的第一代中最先进的 CPU core。同一代中还包括 Cortex-A8, Cortex-A5, PJ4, 以及 Scorpion 作为第二代 Armv7VE core 的不那么受欢迎的结尾。高端的 Cortex-A15, Cortex-A17, Brahma-B15, Krait core 在 2012~2013 年间进入移动手机、汽车电子、网络设备中,非常成功。不过很快遇到了 32 位虚拟地址空间的限制,于是被新出现的 64 位 Armv8 产品替代了。

对应的 Cortex-A7 则是一个相对简单的 in-order CPU core,不过在典型 28nm 工艺下它比起 40nm 工艺的 Cortex-A9 的性能、功耗和芯片面积方面都有优势。它也提供了许多加入 Armv7VE 中的 Armv8 core 中的功能:virtualization, large physical address extensions(LPAE), 最多 8 核,big.LITTLE 配置,硬件整数除法。发布 7 年之后,Cortex-A7 仍然是新发布的 2~4 core 低价嵌入式 SoC 中的常见选择,通常每个 core 搭配 256MB DDR3L 内存,可以放在 system-in-package 里面,也可以直接用板级内存。

Cortex-A9 和 Cortex-A7 加上它们相应的 64 位继承人一起把其他的绝大多数 32 位体系架构都从嵌入式系统中替换掉了。包括以前在无线网络里面常用的 MIPS32r2 core 也在 2017 年左右被替换了。使用 64 位的 Cortex-A53 的 SoC 现在已经比 Cortex-A7 SoC 要多了,不过还是不如 Cortex-A9 SoC。

有两个明显因素会决定 Armv7-A 的最终消逝:

  • 需要超过 2GB 内存的系统、或者需要比起 4 核 Cortex-A7 的性能过程的系统,都会使用 64 位硬件。

  • Cortex-A7 不再支持 28nm 以下的工艺节点,因为 22nm 和 14nm 工艺越来越便宜,比起 64 位 core 来说不再有价格优势。

Cortex-A32 core 是 64 位的 Cortex-A35 所对应的 32 位版本,理论上可以弥补上述的性能和工艺问题,不过目前来说还没有使用它的 SoC 问世。显然,如果 Cortex-A35 能满足功能要求并且额外支持 64 位只带来了稍微增高一点的成本的话,没有必要使用一个功能缩水的 core。这就意味着,除非会出现一个 32 位 Arm 或者 RISC-V core 来抢占超低端市场,否则 Cortex-A7 会是 32 位 Linux 的最后产品了。

这张图显示了随着 kernel 为每个 CPU core 添加 devicetree 源文件,有多少 SoC 使用 Armv7 的各个 CPU core。Cortex-A9 最初增长最高,但此后一直停滞不前,除 Cortex-A7 以外的其他 CPU core 也停止增长了。这个时间线是比硬件推出时间要延后的,因为对旧的 SoC 的支持有时是在硬件生产多年后才加入的。此外 SoC 在新产品中开始使用时间也会有一些滞后。

Year 2038

众所周知,许多 32 位系统将在 2038 年 32 位 time_t 溢出时碰到问题。从目前 Armv7 SoC 的普及程度以及旧架构的芯片得到部署的时间来推断,运行 Linux 的 32 位硬件很可能会一直销售到 2030 年代。有些情况下,产品首次出货后还会继续使用几十年,所以这是一个非常现实的问题。

经过多年的努力,现在内核本身已经完全改为使用 64 位 time_t,而 musl C 库也已经改过来了,但任何基于 GNU C 库(glibc)的发行版仍然会受到这个问题的影响。等到 glibc 的 64 位 time 支持完成后,就需要重新生成使用最新版本的 glibc 的系统软件。

考虑到开发者对 32 位架构的兴趣在下降,发行版有多大可能会被重新构建呢?这是个未知数。许多二进制发行版,如 Fedora、Ubuntu 和 openSUSE Leap,已经放弃了对除 Armv7 以外的其他所有 32 位架构的支持,并且很可能在有新的 glibc 可用之前他们早已经放弃了对 Arm7 的支持。

Debian 仍然保持着官方的 Armv5 (armel)、Armv7 (armhf)、x86-32 (i386)和 MIPS32r2 (mipsel) 平台的移植版本,以及还有非官方的 32 位版本来支持 PowerPC、SuperH、PA-RISC、Motorola 68000 和 x32。对 Armv7 版本的支持,很可能会像在其他发行版上一样,要比其他所有架构都要长寿。可能在其他这些架构消失后,再过十年。这意味着很可能会有嵌入式用户希望 Debian armhf 能够一直保持工作并超过 2038 年。

虽然有计划在 armhf 上为 Debian 11(Bullseye)移植 time64 glibc,但现在可能还是 Debian 12(Bookworm)会先发布。人们还是有不少争议,关于是否应该替代现有的 armhf 移植版本,或者还是改个新的 multiarch target triplet 名字从而可以和 armhf 共存,当然这样会增加更多的工作量。如果移植者没有足够的兴趣让 Debian 在未来的 32 位架构上继续得到支持,这些问题可能会变得毫无意义,而这似乎是一个越来越严重的问题。

在使用 Yocto Project、Buildroot、OpenWRT 或类似的从源码编译发行版的嵌入式系统中,通常已经可以先用 musl-1.2 library 来获得对 64 位 time_t 的完全支持。

Highmem

当某个 32 位系统的物理 RAM 超过了它能映射的线性虚拟地址空间的时,线性映射无法覆盖的区域都被称为 highmem,需要使用 kmap()、kmap_atomic()或新的 kmap_thread() helper 才能从内核代码中临时访问到。于是导致所有的用户空间内存访问都要基于这些接口进行编写,这不仅是 32 位架构的负担,也是 64 位架构的负担。鉴于随着时间的推移,我们看到拥有大量内存的 32 位系统实际上越来越稀少,所以经常会出现将 highmem 改为 deprecate 的呼声。

这里列举了一些常见的 32 位并且对内存要求较大的系统,以说明 deprecating highmem 对哪些设备影响最大。

PlatformMaximum memoryIntroducedProcessorTypical application
Intel Xeon MP64 GB2002Netburst (x86)Server
Calxeda Midway16 GB2013Cortex-A15Server
HiSilicon HiP0416 GB2014Cortex-A15Server
Annapurna AL51408 GB2014Cortex-A15NAS Server
NXP QorIQ P408016 GB2008e500mp (ppc32)Networking
Intel Axxia 55008 GB2013Cortex-A15Networking
TI Keystone 28 GB2013Cortex-A15Networking
Marvell Armada XP8 GB2012PJ4B-MPNetworking
Nvidia Tegra K1 (T124)8 GB2014Cortex-A15Industrial
Renesas RZ/G1H8 GB2016Cortex-A15Industrial
NXP i.MX 6QuadPlus4 GB2015Cortex-A9Industrial
Baikal T18 GB2015MIPS P5600PC
Rockchips RK32884 GB2014Cortex-A17Chromebook
Samsung Exynos 58004 GB2013Cortex-A15Chromebook
Intel Core Duo3 GB2006P6 (x86)Laptop
NXP MPC74482 GB2005PowerPC G4Laptop

最多的出现在大型服务器系统中,不过多年前就开始被更大的 64 位服务器系统取代。对于大多数拥有 2GB 或更多内存的 32 位 PC 和笔记本电脑系统来说也同样如此。早期的 Chromebook 使用 4GB 内存的 Cortex-A15 或 A17 CPU 内核,它们已经在 2020 年 6 月停止获得软件更新,但通常仍有用户在经常使用中,也可以运行其他的 Armv7 Linux 发行版来作为长期替代。

对于嵌入式工业领域(embedded industrial)和网络系统(networking system),甚至有一些环境在使用 8GB 的 32 位平台,并且仍然需要得到未来的内核更新,但这种产品是很少见的,因为会受到它们使用的 DDR3 内存的限制。一块 8GB 的 DDR3 内存卡需要 8 个 8Gb 的芯片,这些芯片价格昂贵,而且获取渠道不多了,或者用 multi-rank 和使用复杂的板级布局的话可以用 16 个 4Gb 的芯片。相比之下,后来的 64 位 SoC 往往使用 LP-DDR4 内存,用一个 64Gb 芯片就能支持到 8GB。

在基于 Cortex-A15 的嵌入式系统上,采用 2GB、4GB 的 DDR3 或 LP-DDR3 内存的配置已经很常见了,所以必须长期支持。而更便宜的基于 Cortex-A7 的 SoC 则只有一个宽度不高的 DDR3 接口,这就导致实际只能使用一个或两个 DDR 芯片,每个芯片的容量为 2Gb 或 4Gb,当所有的内存都可以用 1GB 的低内存区域来管理时,就可以避免使用 highmem。LP-DDR4 或其他更高容量的技术很少用在这些最便宜的 SoC 上,因为对于这些小规模产品来说,它们往往太贵了。

基于这些观察,一个去除 highmem 的粗略计划可以这样展开:

  • 随着时间的推移,对 highmem 的支持会越来越差,因为内核会被改得更适合在 64 位系统上工作,与此同时在 32 位内核上就导致了更大开销。这种情况可以从增加 kmap_thread() 的过程中看到。

  • 32 位机器使用大内存的场景,也就是那些超过 4GB 的,都是很罕见的情况,这样它们最终可以停止获得内核更新。Keystone2 和 GZ/G1H 目前 8GB 的机器还需要内核更新,4GB 的 i.MX6 也是类似情况。

  • highmem 区域的压缩 swap page 技术可能今后还是会得到支持,而不是直接向用户空间提供 highmem 来用。

  • 基于 Armv7VE core (Cortex-A7、-A15 和 A17)的 SoC,在配置 2-4GB 内存的情况下,可以转向使用 CONFIG_VMSPLIT_4G_4G ,这将允许访问接近 4GB 的物理内存,同时也为进程提供 4GB 的虚拟内存。这要付出比 highmem 更高的性能代价,但由于它是基于 Armv7 MMU 的特性,所以不会像过去在 x86 上使用时那么差。

  • 与 Armv7VE 相同的技巧也可能用在使用 MIPS32r5 处理器的 Baikal T1 上,但在那里实现起来比较困难。老的 MIPS32 机器由于硬件限制,最多只能支持 512MB 的低内存。

  • 其他 32 位架构可以使用 CONFIG_VMSPLIT_2G_OPT,在不支持 highmem 的情况下,会减少用户虚拟内存,使物理内存最多可支持到 2GB。这可以用于 Cortex-A9 以及 x86 和 PowerPC 机器,在这些机器上,由于硬件限制或缺乏兴趣,CONFIG_VMSPLIT_4G_4G 选项不太可能得到实现。

如果 CONFIG_VMSPLIT_4G_4G 的计划成功的话,那么在 highmem 被移除后,应该只有不到 1% 的机器会在新内核失去支持,而且随着时间的推移,这个数字还会下降。如果没有 CONFIG_VMSPLIT_4G_4G 的话,大部分 32 位机器都无法很好支持,所以只要用户继续更新 Armv7 内核,那么 highmem 就必须继续保留。不管是哪种方式,这个话题在未来的几年里都会保持热度,因为人们会根据优先级的变化继续做出妥协。

64-Bit hardware

持续向 64 位硬件发展,意味着大多数用户不用再担心 32 位系统的问题,比如 time_t 溢出、虚拟地址空间和物理地址空间的限制等,但并非所有人都能不用担心了。比如说:

  • 有很多用户可能需要继续运行的历史遗留的一些二进制程序,特别是在 x86 机器上,需要保持对过去 30 年的程序的向下兼容性,比如从 32 位 Windows 移植的游戏。

  • 同样,尽管谷歌在自己的 Play 商店中推动应用程序编译时选择 64 位或不依赖体系架构,但在一些消费市场中,Android 应用程序往往仍在以 32 位 Arm 二进制文件的形式发布,目的是达到最广泛的硬件兼容。

  • 随着 64 位处理器占领低成本市场,它们会与更小的内存配置结合起来,只要一个 2Gb 的 DDR3 放在 system-in-package 系统内就可以获得 256MB 的物理内存。在这种情况下,运行 64 位代码会有很大的开销,人们会很希望能运行 32 位代码来节省空间,而不是将内存容量增加一倍。

处理这个问题最常见的方法是运行 64 位内核,但引导起来的文件系统则是使用 32 位用户空间程序的文件系统。这样做是可行的,因为内核长期以来通过为每个不兼容的接口实现第二组系统调用入口函数,即 "compat" 层来支持这两种类型的应用程序。在设备驱动程序中有少数不支持 compat 方式,但这些例外情况大多限于 mainline 内核之外的第三方 module。

这个 compat kernel 功能允许把 32 位和 64 位 container instance 混合起来运行,以及在一个 "multilib "或 "multarch " 根文件系统内混合两种类型的应用程序。使用 compat 模式可以避免 highmem 的大部分问题,但仍然需要解决了 time64 问题的 C 库来重新编译所有 32 位用户空间应用代码,才能确保运行在 2038 年以后仍可使用。

在 x86 和 MIPS 机器上,还有另一种选择,就是直接在 64 位硬件上运行 32 位内核,这样可以更好地兼容设备驱动程序,让用户在 32 位和 64 位硬件上使用相同的内核和 root 文件系统,但这会重新引入 32 位内核的虚拟地址限制,并且会缺少一些只有在 64 位编译环境下可用的内核功能。理论上,这在许多 Arm 处理器上也是可以实现的,但有许多限制:

  • Armv8 处理器缺少某些指令(setend、cp15 barrier、swp/swpb 原子操作),而这些指令可能在旧的 32 位二进制文件中用到了。虽然 64 位内核在 compat 模式下模拟了这些指令,但 32 位内核的指令模拟实现并不那么完整,所以现有的能在 64 位 Armv8 内核和 32 位 Armv7 系统上运行的二进制文件可能无法在 Armv8 硬件上运行的 32 位内核上运行。

  • 大多数 CPU 的具体实现都需要在内核中进行一些 errata workaround 才能确保正常工作。32 位 Arm 内核有适用于所有 Armv7 内核的 errata workaround,但没有 Armv8 core 的 errata。在最坏的情况下这会导致出现不确定的行为或者数据损坏。

  • 许多安全特性都需要 64 位内核,要么是因为硬件要求,要么是因为 32 位内核中没有实现。这包括内核页表隔离(用来避免"Meltdown" 攻击)、内核地址空间布局随机化(kernel address-space layout randomization)、PAN、UAO、BTI、PTR_AUTH 和硬件加密等。因此,运行 32 位内核可能会降低安全性。

  • 一般来说这种配置并没有人进行很好的测试,因为内核开发者理所当然地认为使用 64 位内核是更好的选择。

  • 最新一代的 Armv8.2 内核已经完全放弃了运行 32 位内核的硬件功能。这包括作为"little" 的 Cortex-A55 以及从 Cortex-A76 开始的所有 "big" core。这些 CPU core 仍然可以在兼容模式下运行 32 位用户空间代码。未来的一些 core 也会放弃 32 位用户模式,但似乎只要有需求,"little" core 仍可以支持。事实上,会有一些系统只能在部分核心上运行 32 位代码。

尽管有这些限制,但已经有大规模的 32 位 Arm kernel 部署在 64 位硬件上,特别是在 Raspbian 发行版中,该发行版可以在 Armv6(Raspberry Pi 1 和 Zero)、Armv7-A(Raspberry Pi 2)和 Armv8(Raspberry Pi 3 和 4)中使用相同的代码,还有一些低端 Android 系统在这么做,主要为了避免更严格的 General Kernel Image(GKI)规则要求在发布 Android 10 时必须使用 64 位 Arm kernel。

内核本身对内存的消耗可能会变成一个理由来推动在 32 位 Arm kernel 中加入对 Armv8 处理器的适当支持,从而在低端机器中挤出最后百分之几的可用内存。据估计,64 位内核在多个领域增加了无法避免的开销,可能多达几十兆:

  • 与支持 Thumb2 的 Armv7 内核相比,内核映像文件本身大约要大 50%。在一个典型的配置下,它可以从 10MB 增长到 15MB,如果 64 位配置包括对额外硬件的支持,就像 Android GKI 一样,甚至会增大更多。

  • 由于系统中每一个 4KB 的页面都需要一个 struct page,而它在 64 位内核上通常要多占用 32 个字节,因此每安装 128MB 的内存就会多消耗 1MB 内存,这仅仅是为了存储 mem_map 数组。

  • 每个线程都有自己的 kernel stack,它从 8KB 变为了 16KB。每 128 个线程就需要增加 1MB 字节的内存。

  • page table 需要一到两个额外的中间层来描述更大的虚拟地址空间,每个进程至少增加 4KB。

  • 内核中的 slab cache 往往也比较大,尤其是 inode cache 会使用大量的内存资源。这很难量化,因为 inode cache 的大小是动态变化的。只要有内存可用,它就会增长,但在内存不够时就会缩小。

在没有 native 32 位模式的处理器上,也可以为 64 位指令定义一个 "ILP32" ELF 格式。事实上,这在 MIPS 上的 "n32 "和在 x86 上的 "x32 " 都是类似的概念。两者在实际应用中都没有广泛部署,而为 64 位 Arm kernel 添加相同功能的 patch 也一直没能合并,因为希望避免用不兼容的二进制格式来让生态系统变得更加碎片化。

新兴的 RISC-V SoC 在运行 Linux 时只提供 64 位模式。Arm 处理器的所有选项,理论上也都可以在那里直接用。但既然没有 32 位 RISC-V Linux 生态系统,那么 RISC-V 将完全跳过这一步,而直接接受更高的内存消耗代价。有一些 32 位 RISC-V 内核包含了 MMU,如 Rocket、Andes A25、VexRiscv 和 Cloudbear BI-350,但到目前为止,32 位 RISC-V 只设法进入 microcontroller,虽然理论上该架构可以利用 compat 模式,但 kernel 以及真正的 CPU 实现都没有提供支持。这里有一个极端的例子是最近公布的一款低成本 SoC(https://www.cnx-software.com/2020/11/09/xuantie-c906-based-allwinner-risc-v-processor-to-power-12-linux-sbcs),使用 64 位 RISC-V CPU,内存只有 64MB。

目前,64 位 Arm 处理器比 RISC-V 占有优势,因为它们有两个成熟的软件生态系统可以运行,对于 1GB 以下的机器可以使用更节省空间的 32 位用户空间。随着内存需求和容量的增长,更多的应用可以使用 64 位构建运行得更好,那么这种差异就变得不那么重要了。

Conclusion

一般来说,领先(cutting-edge)技术的寿命都会很短,因为它很快就会被下一代技术所取代,而任何比竞争对手更便宜地来实现其功能的东西都可以在很长一段时间内、甚至可能是几十年内保持流行。这种效应可以从摩托罗拉 68000 架构、Arm9 CPU 内核和 Raspberry Pi Zero 板上看到,它们活得比一代又一代的优秀替代品还要长久。这种效应让那些等待终结 highmem 的人们看到了希望,因为唯一需要 highmem 内存配置的硬件在 5 年或更久之前就已经是领先技术了,可以预计在未来 5 年内就会退役。

无 MMU 的 microcontroller 和使用最小内存配置的嵌入式系统可能会在同一时间段内以不同的方式死亡,因为这些产品通常都部署在高度定制的环境中,没有更新 kernel 的计划。一旦使用它们的公司停止在新的 kernel 上部署系统,它可能就会最终结束了,就像 Arm7TDMI 或 Blackfin 等曾经流行的架构在 Linux 中消失一样。

在这两个极端之间,有大量的嵌入式 SoC 目前仍然流行,随着时间的推移,基于 Cortex-A7 的设计会成为新的 32 位 SoC 的唯一可行选择。这些产品比它们下面的任何产品都要便宜和优秀,而更强大的产品又被 64 位产品所取代。一旦 64 位 core 在性能、功耗和成本上击败 Cortex-A7,那么这最后一个市场就会转投新产品,而 32 位 Linux 内核将只需要用于支持现有的平台。在最后一颗 Armv7 芯片诞生后的 5 到 10 年内,还是会有相关的新电路板设计出来,但在这之后,可能还需要 10 年的时间,剩余用户才会最终停止升级内核或者干脆更换硬件了。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值