仓库源文

.. Kenneth Lee 版权所有 2024

:Authors: Kenneth Lee :Version: 0.2 :Date: 2024-06-21 :Status: Draft

无价之宝——一个设计仿写的例子


最近评审了一个OS和BIOS的接口设计,我感觉基础定义不合理。我大致总结一下这些我感 受不合理的地方:

  1. 它使用一个寄存器传递参数的二进制接口,然后用描述C函数的方式描述这个接口,但 这个二进制接口有两个返回值(我们知道C语言函数调用只有一个返回值)。我感觉这 两个二进制作为返回值的寄存器,其实有一个是用作C函数的返回值,另一个类似Unix 的errno,用来统一表示错误分类的。

  2. 但在一个检查某个服务是否被支持的接口中——我们这里假设叫 check_available(service_id)吧,它的返回值是0,而用错误码表示这个服务是否被 支持,这又违背了errno的使用pattern。

  3. errno这样的设计导致了所有错误码都统一编码,但相应的错误在每个请求中其实不共 享。比如请求CPU复位的错误,和取版本号这个错误,错误码是在一个空间里面编码的, 这样毫无意义。

    Unix系统中使用errno有它的道理,因为Unix系统大部分时候errno确实是在同一个空 间中使用的。比如你调用malloc,malloc调用了futex,那么malloc报的错可能是它自 己报的,也可能是futex报的,使用一个统一的编码就可以定位到错误出现在哪一层了。 你一个OS和BIOS间的接口又没有这样的关系,为什么需要这样定义?

我把这些问题提出来的时候,有人告诉我,其实这个接口是仿OpenSBI的,OpenSBI的设计 就是这样的。

于是我去看了一下OpenSBI,我的调查结果是这样的:

  1. OpenSBI确实是用了一个C的接口,但它真的明确的基于C的ABI来定义的。它的参数就 是a0-a7,和RISCV的Call Convension是一样的。只是补充了a6,a7用来做扩展名和扩 展中的功能参数。返回值也是按C标准叫a0,但扩展了a1,以便返回errno。所以 OpenSBI确实可以用C的方法来描述接口,因为我们可以直接用C的表达直接对应到二进 制接口的全部行为上。

  2. OpenSBI确实用了errno的模式,这个我认为其实是不合理的。我个人认为长远维护下 去,维护者估计也会看着不爽。不过一般来说OS-BIOS接口没几个人用,感受到不爽的 人也不会太多。这算是个小瑕疵吧。

  3. OpenSBI那个检查服务是否支持的功能叫sbi_probe_extension(),人家确实是用返回 值来表示服务是否存在,而不是用errno来表示服务是否存在的。更关键的一个问题是, RISCV是一个以大量扩展为基础的方案,所以它这类检查必须以扩展为单位。而我们现 在谈的这个方案完全不是这回事,这里用服务ID再分功能的方式,其实没什么道理。

其实我看完这个OpenSBI的接口后,我确实发现我评审的这个方案几乎是像素级在复刻 OpenSBI的设计。但我依然认为OpenSBI的设计算不上太好,但还是质量在线的。而上面那 个设计的质量,我在直观感觉上认为是不在线的。

“质量不在线”是个“感受”而不是理性的逻辑分析。作为一个经常对人家的设计有一堆意见 的架构师,我希望通过写这个总结反思一下,我是不是过于苛刻了。

从直觉想逻辑,我觉得作为一个架构师,如果我允许一个这样设计放在系统中,那么后面 的设计也会复刻前面设计的风格,而这种风格在整个系统中一传递,这个系统后面就很难 维护了。

那么,这个“风格”是什么呢?

我觉得主要还是“无目标导致的无规律”。比如,它也用r6和r7作为扩展ID和功能ID,但 OpenSBI用的是a6和a7啊大哥,a6和a7是RISCV ABI接口中的X16和X17啊。人家是有目的的, 选择了所有的输入参数的最后两个作为输入。你这里用顺序的第六和第七个寄存器作为输 入,这个选择就莫名其妙了。

然后就是前面说的这个检查服务是否存在的调用,设计成那样(用错误码当作返回值用), 明显就是没有搞清楚errno的真正作用所以才是这样的。

这样,你从这个接口上看不到设计选择的明确目的,那么以后补充其他设计的时候,后面 的人就不知道如何取舍了。

每个\ 设计决定\ ,本质都是一个\ 限制\ (“第一个参数放在R0中”,就拒绝了 “第一个参数放在R1中”这个选择,所以设计本质是限制),所以每个设计决定都是一个\ 代价\ (失去自由的代价)。我们把很多的\ 设计决定\ 综合在一起的时候,需 要综合出所有\ 设计决定\ 的自由空间的交集,这就会产生\ 冲突\ ,要消弭冲 突,就要取舍。这时,\ 代价\ 成本就是这些\ 设计决定\ “谁后退,谁保持”的 判断依据了。没有\ 设计目的\ 的\ 设计决定\ ,我称为“无价之宝”,又叫“铁 索横江”,你不敢动他,因为复杂了以后你根本不知道会导致什么问题。系统中有一堆这 种“无价之宝”,这个系统就没法维护了。

所以,一旦在设计初期就有大量这种原因都搞不清楚,就是在简单复刻别人的设计的设计, 它就是危险的,我本能会反对它。

这样想一想,我这个直觉还是有逻辑的。

只要不侵犯版权,而且可以达成设计目标,复刻别人的设计是个安全的做法,这我认为应 该鼓励。但\ 复刻设计\ 是复刻经验(所达成的目标),不能复刻样子。