.. 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中”这个选择,所以设计本质是限制),所以每个设计决定都是一个\ ``代价``\ (失去自由的代价)。我们把很多的\ ``设计决定``\ 综合在一起的时候,需 要综合出所有\ ``设计决定``\ 的自由空间的交集,这就会产生\ ``冲突``\ ,要消弭冲 突,就要取舍。这时,\ ``代价``\ 成本就是这些\ ``设计决定``\ “谁后退,谁保持”的 判断依据了。没有\ ``设计目的``\ 的\ ``设计决定``\ ,我称为“无价之宝”,又叫“铁 索横江”,你不敢动他,因为复杂了以后你根本不知道会导致什么问题。系统中有一堆这 种“无价之宝”,这个系统就没法维护了。 所以,一旦在设计初期就有大量这种原因都搞不清楚,就是在简单复刻别人的设计的设计, 它就是危险的,我本能会反对它。 这样想一想,我这个直觉还是有逻辑的。 只要不侵犯版权,而且可以达成设计目标,复刻别人的设计是个安全的做法,这我认为应 该鼓励。但\ ``复刻设计``\ 是复刻经验(所达成的目标),不能复刻样子。