夜雨聆风学习资料网

ARTICLE · 1133945

硬件和软件之间,为什么还有个固件?

硬件和软件之间,为什么还有个固件?
点击上方“公众号” 可以订阅哦!

固件从业二十几年的业内人士来回答一下:软件与硬件之间,本没有一道截然的鸿沟,是一条连续的光谱。光谱的一端,逻辑凝固为电路;另一端,逻辑流淌在代码里。而固件,只是光谱正中间那一档。

软件和硬件是“图灵等价”的

1936 年,图灵提出了一个抽象的计算模型:一条无限的纸带、一个读写头、一个有限状态控制器。这就是图灵机。它笨拙、缓慢、毫无工程价值,但它给出了“可计算”这个概念的精确定义。任何真实计算机,只要忽略内存有限的限制,在计算能力上都等价于图灵机。

这里有两个术语:

  • 图灵完备
    (Turing complete):能模拟通用图灵机,也就意味着能计算一切可计算的东西。C、Python、Rust、JavaScript 都图灵完备。
  • 图灵等价
    (Turing equivalent):两个系统能互相模拟,能力完全对等。 

对通用处理器和通用软件来说,这两件事都成立。于是得到一个关键推论:

一个用软件实现的功能,原则上一定可以用硬件电路实现;一个用硬件电路实现的功能,也一定可以用软件实现。

举个例子,密码学里的 AES 加密,最初是用几千行 C 写成的;今天每一颗 ARM 芯片里都有一个 AES 指令,本质上是有人把那段 C 代码“翻译”成了电路。反过来,显卡的着色器本质上也是把过去 CPU 上的浮点运算搬进了硬件。

图灵本人对这件事有一句非常精辟评论。他在设计 ACE 计算机时说:

“

“We have often simplified the circuit at the expense of the code.”

(我们常常为了简化电路而牺牲代码。)

电路和代码之间,是一道可以移动的线。 图灵在 1947 年就明确指出,为了让电路更简单,程序员要多写代码、多费工夫,反之亦然。软硬件之间没有天定的鸿沟,只有人做的取舍。

光谱上的位置,由应用范围决定

逻辑上等效,工程上却不是一模一样。一个功能落在光谱的哪一档,由三个因素来决定:性能、成本、可改性。

专用电路并行度高、延迟低,永远优于通用指令;可它开发昂贵,一旦定型便难以改动。软件开发便宜、迭代自由,性能却受制于所栖身的硬件。于是,量越大、越快、越不容更改的功能,越往硬件那头靠;反之,留在软件这边。这条边界一直在动:浮点运算、MMU、音视频编解码、加密、AI 加速,都曾从软件迁往硬件;也有成本过高、不够灵活的硬件模块,重新被“软化”回软件。

键盘扫描为何用软件?矩阵会变,会加键,会改消抖算法。硬盘磁头伺服为何必须是硬件?它跑在纳秒级的反馈回路里,且一旦调好,再不用动。可见:硬件的代价是不可变性,软件的好处是可变性。 你愿意为“以后还能改”付出多少,功能便站在光谱的哪一档。

把这张表摊开来看,就是一条连续的光谱:五个档位之间没有断层,只有渐次移动的分界线,固件恰好站在正中间。

光谱正中间那一档:固件

固件的定义是:固化在硬件里的程序,一般存储在 ROM 或 Flash 中,硬件一通电它便开始运行,比操作系统早得多,是基础软件中的基础软件。有人认为固件,是“写下来会变成电路”的软件。

对软件而言,固件是软件中的硬件。写固件的人,每天都在与寄存器、时序、电气特性打交道,每一行代码都要对着芯片手册反复核对。操作系统想触达硬件,一般要经过固件这道中间层;在上层软件眼里,固件几乎就是硬件的一部分。这行有一句自嘲:别人写代码面对的是软件 API,我们面对的是各种硬件spec。

对硬件而言,固件是硬件中的软件。因为它是可以被更新的。主板上那颗 BIOS 芯片,早年间不少还是只读的 ROM;如今哪块主板不支持刷 BIOS?刷一次,也许修掉一个兼容性 bug,改掉一个安全漏洞,也许也能解锁一颗新 CPU。SSD 固件、网卡固件、路由器固件,皆是这个道理:芯片流片定型后改不了,但固件能改 —— 这是硬件出厂之后最廉价的一次“后悔药”。 当然,这也注定固件从业者,是硬件问题的背锅侠。硬件出了问题,因为改固件最方便,就由固件来做workaround。改完之后,就变成了:“不是你的问题,为什么要改?”

光谱上另一段特别的位置:FPGA

要体会“硬件也可以被软件化”,最直观的例子是 FPGA。

FPGA 是一块可以反复重写的芯片。用硬件描述语言画出“电路图纸”,编译成一段配置文件(bitstream),上电时加载进芯片里的逻辑单元阵列,这块芯片便“变成”了你想要的电路。今天加载加解密引擎,它就是加密芯片;明天换一份配置,它又成了 AI 加速器;你甚至可以在里面放一个软核 CPU—— 用硬件逻辑“软”出一个处理器,再在这个处理器上跑程序。到这一步,软硬件彻底融为一体。

与之相对的是 ASIC:电路在流片那一刻便已定型,想改功能,只能重新设计、重新流片,动辄数百万美元。业内有个比方:ASIC 是印好的书,印错一个字,整批作废;FPGA 是可擦写的黑板,写错擦掉重来;固件是夹在书页里的活页 —— 书已印完,内容还能换。

其实,固件与 FPGA,其实是同一笔权衡的两个方向。 都在光谱中间,固件偏向软件,FPGA偏向硬件。固件选择代码,以一点性能换取灵活性;ASIC 选择电路,以灵活性换取性能;FPGA 站在中间,提供可反复重写的中间态,却保留了电路的全部硬件成本,只买来灵活性,于是每一代都比固件贵出一个数量级。但也并不意味着,“用了 FPGA 就不用固件”,有时候,两者还是可以搭配使用,相得益彰。

固件补上了两头的缺口

把目光收回光谱两端,便知道为什么还要有固件存在。

纯硬件缺的,是可变性。出厂那一刻,它能做什么便已凝固,需求一变,只能望洋兴叹。纯软件缺的,是对硬件的直接性。它必须穿过层层抽象方能触达硬件,而每一层抽象,都在损耗性能与精确性。这两头之间,是一个巨大的能力缺口。

固件补的正是这个缺口。它让软件可以更“硬”:当一个功能必须贴着硬件跑 —— 时序精确到纳秒、直接操作寄存器 —— 把它做成固件,便同时获得了硬件的能力与软件的敏捷。我做 UEFI Shell 应用时写的是 C,跑在没有操作系统的环境里,直接读写内存与 I/O 端口 —— 这是软件,干的是硬件的活。它也让硬件可以更“软”:当一个硬件需要适应性 —— 随配置切换行为、随新需求升级、甚至更改硬件的bug —— 把逻辑写成固件,便获得了软件的能力。硬盘的 FTL、显示面板的时序控制、服务器的 BMC,皆属此类。

所以固件的地位并不尴尬,而是不可或缺。它在“必须精确”与“必须可改”这两个相互矛盾的要求之间,找到一条窄窄的通道,然后站进去。硬件与软件之分,与其说是本质之别,不如说是工程之择;而固件,正是这道选择题中重要的一项。

参考资料

相关学习资料