.. Kenneth Lee 版权所有 2024
:Authors: Kenneth Lee :Version: 0.2 :Date: 2024-06-21 :Status: Draft
无价之宝——一个设计仿写的例子
最近评审了一个OS和BIOS的接口设计,我感觉基础定义不合理。我大致总结一下这些我感 受不合理的地方:
它使用一个寄存器传递参数的二进制接口,然后用描述C函数的方式描述这个接口,但 这个二进制接口有两个返回值(我们知道C语言函数调用只有一个返回值)。我感觉这 两个二进制作为返回值的寄存器,其实有一个是用作C函数的返回值,另一个类似Unix 的errno,用来统一表示错误分类的。
但在一个检查某个服务是否被支持的接口中——我们这里假设叫 check_available(service_id)吧,它的返回值是0,而用错误码表示这个服务是否被 支持,这又违背了errno的使用pattern。
errno这样的设计导致了所有错误码都统一编码,但相应的错误在每个请求中其实不共 享。比如请求CPU复位的错误,和取版本号这个错误,错误码是在一个空间里面编码的, 这样毫无意义。
Unix系统中使用errno有它的道理,因为Unix系统大部分时候errno确实是在同一个空 间中使用的。比如你调用malloc,malloc调用了futex,那么malloc报的错可能是它自 己报的,也可能是futex报的,使用一个统一的编码就可以定位到错误出现在哪一层了。 你一个OS和BIOS间的接口又没有这样的关系,为什么需要这样定义?
我把这些问题提出来的时候,有人告诉我,其实这个接口是仿OpenSBI的,OpenSBI的设计 就是这样的。
于是我去看了一下OpenSBI,我的调查结果是这样的:
OpenSBI确实是用了一个C的接口,但它真的明确的基于C的ABI来定义的。它的参数就 是a0-a7,和RISCV的Call Convension是一样的。只是补充了a6,a7用来做扩展名和扩 展中的功能参数。返回值也是按C标准叫a0,但扩展了a1,以便返回errno。所以 OpenSBI确实可以用C的方法来描述接口,因为我们可以直接用C的表达直接对应到二进 制接口的全部行为上。
OpenSBI确实用了errno的模式,这个我认为其实是不合理的。我个人认为长远维护下 去,维护者估计也会看着不爽。不过一般来说OS-BIOS接口没几个人用,感受到不爽的 人也不会太多。这算是个小瑕疵吧。
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中”这个选择,所以设计本质是限制),所以每个设计决定都是一个\
代价
\ (失去自由的代价)。我们把很多的\ 设计决定
\ 综合在一起的时候,需
要综合出所有\ 设计决定
\ 的自由空间的交集,这就会产生\ 冲突
\ ,要消弭冲
突,就要取舍。这时,\ 代价
\ 成本就是这些\ 设计决定
\ “谁后退,谁保持”的
判断依据了。没有\ 设计目的
\ 的\ 设计决定
\ ,我称为“无价之宝”,又叫“铁
索横江”,你不敢动他,因为复杂了以后你根本不知道会导致什么问题。系统中有一堆这
种“无价之宝”,这个系统就没法维护了。
所以,一旦在设计初期就有大量这种原因都搞不清楚,就是在简单复刻别人的设计的设计, 它就是危险的,我本能会反对它。
这样想一想,我这个直觉还是有逻辑的。
只要不侵犯版权,而且可以达成设计目标,复刻别人的设计是个安全的做法,这我认为应
该鼓励。但\ 复刻设计
\ 是复刻经验(所达成的目标),不能复刻样子。