什么是片上系统(SoC),为什么我们要关心它们是否是开源的?

2020-11-10 04:21:07

现代电子产品通常都是围绕一个高度集成的芯片,也就是所谓的“片上系统”(SoC)来制造的。虽然最早的家用电脑主板由大约100个芯片组成,但摩尔定律将这一数字推低到只有几个芯片,当时80286个PC/AT克隆电脑成为主流,而且这个行业从未回头看过。现在,一个典型的SoC集成了一个CPU核心复合体,外加数十个外围设备,包括模拟、射频和电源功能;甚至有“系统集成”解决方案,可以将SoC、RAM,有时甚至闪存芯片封装到一个塑料封装中。

现代的SoC非常复杂。现代SoC的“完整用户手册”长达数千页,勘误表(“错误列表”)--如果你被允许查看的话--可能就有数百页。我引用“完整的用户手册”是因为即使是最开放、文档最齐全的SoC(例如恩智浦的i.MX系列)也需要严格的保密协议才能访问数千页有关第三方知识产权(IP)块的文档,以实现视频解码、图形加速和安全等功能。除了NDA模块之外,通常还有更深层次的完全未发布的废弃硅文档,例如设计好但没有进行最终切割的外围设备、内部调试设施和预引导设施。这些废弃的功能中有许多甚至在设计芯片的团队中都不为人所知!

废弃的硅是一件事,因为构建芯片不像是把乐高拼凑在一起,而更像是雕刻家在大理石块上雕刻:添加电路比停用电路难得多。增加一个电路可能要花费大约100万美元的新掩膜,同时将项目推迟大约70天(代价是10万个工时的额外工资);如果规划得当,停用一个电路可能就像更改代码或对单个掩模层进行小编辑一样简单,成本可能是1万美元到几天(假设晶片被保存在中间阶段,以促进这种风格的编辑)。

图片来源:Takomabibelot的《拿着木槌和凿子的人浮雕(华盛顿特区)》由CC by 2.0授权。

因此,典型的SoC掩模组从大量额外的功能、备用逻辑和调试设施开始,这些都被凿掉(废弃),直到SoC的最终形状出现。正如米开朗基罗曾经说过的那样:“每一块石头里都有一尊雕像,雕塑家的任务就是发现它。”我们可以说,“每一套SoC面具都有一份数据表,而验证团队的任务就是发现它。”有时最后的打击发生在引导时:错误的功能可能会被甚至在CPU执行其第一条指令之前运行的预引导代码关闭或修补。因此,即使是记录最好的SoC,也将有相当一部分晶体管被废弃和不负责任,理论上对最终用户是看不见的。

从安全的角度来看,SoC中这种“暗物质”的存在令人担忧。忘了担心引导ROM或CPU微码吧--BIST(内置自检)基础设施拥有代码注入所需的一切,只要您能诱使它进入正确的模式即可。此外,SoC集成商都从极少数IP供应商那里购买DDR、PCI和USB等功能块。这意味着,相同的废弃逻辑主题被植入数亿台设备中,即使是在相互竞争的品牌和不同的产品线上也是如此。这就给无法修补、破坏生态系统的安全漏洞埋下了隐患!

Premitive使用FPGA实现其SoC,从而避免了这一风险。现场可编程门阵列是用户可重新配置的,极大地改变了设计错误的成本计算;我们不再凿开一块大理石,而是再一次用乐高积木来建造。当然,这种灵活性是有代价的:一个FPGA的价格可能是同等功能的SoC的50倍,在绝对MHz下大约慢5-10倍。然而,这确实意味着在前身中没有暗物质,因为用于描述SoC的每一行代码都是可见的,以供检查。这也意味着,如果在前身SoC中发现逻辑错误,可以通过更新来修补它们。这极大地降低了迭代SoC的成本,使其在经济上与开源方法更加兼容。在理想的情况下,前身SoC设计将在未来几年内进行彻底的审查和审计,集中在低风险的路径上,走向固定硅的磁带生产,在保持高标准透明度的同时,降低生产成本和提高性能。

前身的SoC是使用Litex制造的。Litex是由Florent Kermarrec创建的一个框架,用于使用Migen/MiSoC FHDL定义SoC,而Migen/MiSoC FHDL本身是用Python3.6+编写的。Litex的核心是一组自动在总线标准和宽度之间进行调整的“处理程序”。这使设计人员可以轻松地混合搭配各种控制器和外围设备

上图是截至2020年10月的前身系统芯片(SoC)框图。重要的是要注意文档上的日期,因为基于FPGA的SoC可以而且会随着时间的推移而改变。我们通常会避开像这样漂亮的手绘框图,因为它们几乎在完成的那一天就过时了。相反,我们的CI系统在每次代码推送时都会动态生成相当于“程序员手册”的内容。对于Rust程序员,我们有一个工具svd2UTRA,它可以自动将Litex生成的SVD文件转换为Rust API板条箱。对于基于FPGA的开源SoC,自动化CI不仅是最佳实践,而且是必不可少的,因为子模块依赖关系中的小补丁(有时是重要的补丁)会定期影响您的设计。

“核心复合体”目前由一个RISC-V核心组成,使用Charles Papon的VexRiscV实现。我们将其配置为支持“RV32IMAC”指令子集,为其提供了MMU,并增强了缓存。VexRiscV将缓存大小限制为4kiB,但可以通过提升缓存关联性来增加有效容量。通过将内核调优为具有双向I-缓存和四路D-缓存,我们获得了大约10%的性能提升。我们还提供了32 KiB引导ROM,它目前包含三条指令,但有朝一日会扩展到包括对从外部存储器加载的代码进行签名检查,以及用于紧密耦合/更高安全性操作的128kiB板载SRAM。CPU内核通过Litex适配并仲裁到多控制器Wishbone总线,并通过专用CSR桥进一步适配到CSR总线,该专用CSR桥被配置为在4-KiB页面边界上自动分隔外围设备,以便它们可以单独地与MMU重新映射。还有一个IRQ处理程序,用于管理散布在芯片周围的外围设备产生的中断。

核心复合体还包括一组主要是样板的CSR,它们执行以下功能:

定时器0是Litex提供的默认定时器。它是一个高分辨率的32位定时器,时钟频率与CPU内核相同。

“CRG”是一个控制FPGA时钟发生器的接口。目前我们在这方面做的还不多,但最终这将在电源管理和延长电池寿命方面发挥核心作用。

“Git Info”是一个静态寄存器,它提供有关构建前身的Git repo的状态信息。

“BtSeed”是一个64位的数字,它可以被随机化,以便在终端用户不需要修改代码(否则,构建是完全可重现的)的情况下,将熵强制到布局布线过程中,以避免最终的FPGA网表对于他们的设备来说是唯一的(否则,构建是完全可重现的)。

“TickTimer”是一个低分辨率的64位计时器,以1ms为增量计时。它是XOUS操作系统的时间来源。

紧邻核心建筑群的是一个调试块。Debug模块具有全速USB MAC/PHY,可以通过隧道传输Wishbone数据包,并充当CPU的备用Wishbone控制器。我们使用它来驱动CPU上的调试接口,从而使gdb即使在CPU停止时也可以通过USB连接到前身。事实上,人们可以在没有RISC-V CPU的情况下构建前身,只需通过USB传输Wishbone数据包来进行调试和驱动程序开发。调试块还包括一个称为“Messible”的小型CSR外设,它是一个64个条目、8位宽的FIFO,在调试期间用作邮箱/便签簿。

RISC-V CPU的存储空间通过Wishbone总线映射到各种外设和内存块上。对于传统的SoC设计者来说,Wishbone有点像AXI,但它是开源的。Wishbone支持多主控、流水线和块传输等奇特功能。Wishbone总线空间的一部分进一步映射到称为配置和状态寄存器(CSR)总线的总线上。

虽然Wishbone是高性能的,但它需要更多的接口逻辑,当外围设备的位宽与总线宽度匹配时,它是最令人满意的。CSR具有面积效率高的特点,从硬件和软件API的角度都能很好地容纳任意位宽的寄存器,但性能较低。因此,CSR非常适合于中低速I/O任务(例如同名配置和状态寄存器),而Wishbone则非常适合内存映射I/O,在这种I/O中,改进的带宽和延迟值得付出面积开销。

在设计过程中,大多数外设的生命周期都映射到CSR空间,然后升级到内存映射实施,以满足性能需求。因此,先驱上的大多数外设都是仅支持CSR的设备,这并非巧合。以下是对每个CSR外围设备的简要说明。提醒一下,您可以随时查阅我们的参考手册,了解更多详细信息。

“COM SPI”是连接到嵌入式控制器(EC)SoC的SPI总线。它是一个20 MHz的SPI外设,具有16位的固定传输宽度。此块的目标是升级到内存映射I/O块。

“I2C”是一个I2C总线控制器。目前,只有实时时钟(RTC)芯片和音频编解码器芯片连接到该I2C总线。

“BtEvents”是一个包罗万象的块,用于处理各种外部实时中断源。目前,它处理来自EC和RTC芯片的中断。

“KeyScan”是键盘控制器。它使用一个32 kHz的慢速外部时钟源,可以扫描9×10键盘矩阵中的按键。通过将键盘扫描器与系统核心时钟分离,系统可以在等待键盘按下时进入较低的功率状态,从而延长了前体两次充电的天数。

“BtPower”是一组专门用于管理权力的GPIO。它可以打开和关闭音频和离散TRNG,覆盖EC的电源控制命令,激活USB C类端口的升压模式(允许作为DFP或“主机”操作),并启用自毁机制。

“JTAG”是一组环回到FPGA的JTAG引脚的GPIO。这些功能与我们的eFuse API驱动程序结合使用,可在7系列FPGA上自行配置AES位流加密熔丝。

“XADC”是7系列XADC模块的接口,它是一个12位、多通道ADC。这主要用于系统电压的自我监控。在最终的生产版本中,还将提供至少一个ADC通道作为GPIO内部接口上的配置选项,以便用户可以更轻松地将模拟传感器集成到前身中。

“UART”是一个简单的115200、8-N-1串行接口,它连接到控制台I/O的调试头。

“BtGpio”是一个直接的数字I/O块,用于驱动GPIO内部接口上的引脚。请注意,由于FPGA实现的性质,在不更新位流的情况下无法在数字GPIO功能和模拟GPIO功能之间进行切换。

除了CSR I/O外,还对少数I/O设备进行内存映射以实现高性能:

“外部SRAM”是一个32位宽的异步接口,内存映射16MiB的外部SRAM。SRAM有电池支持,因此它可以在SoC断电时保持状态。其目的是通过减少睡眠/唤醒开销来优化电源。然而,这也意味着自毁程序必须首先清除SRAM中的敏感数据,然后才能激活击穿SoC的最后一击,因为自毁电路也是由SRAM的备用电源供电的。外部SRAM模块还具有CSR接口,用于读出SRAM的配置模式。

Audio是外部音频编解码器的I2S接口。除了配置I2S接口的CSR模块外,它还包括一对256×16条目内存映射的样本FIFO。

“SPI OPI”是一个与外部闪存类似的高速SPI接口,其内存映射到128MiB的非易失性存储。OPI中的“O”代表八进制--这是一种运行在100 MHz DDR速度的8位总线。它还包括一个预取器,可以容纳多个缓存线的代码,从而优化了直线代码执行的情况。该总线的高性能至关重要,因为其目的是让CPU以XIP形式运行闪存中的大部分代码。它还具有CSR接口,可控制块擦除和页面编程等操作。

“MemLCD”是LCD的帧缓冲器。Sharp Memory LCD拥有自己的内部存储器,即使在主机断电的情况下,它也可以保留图像。因此,MemLCD帧缓冲器是LCD本身的高速缓存。它管理LCD的哪些线是脏的,并在通过CSR发出请求时仅将脏线刷新到LCD。这提高了LCD的感知更新率,如果整个屏幕正在更新,则该速率被限制为10 Hz,但与静态屏幕的比例成反比。

到目前为止,所描述的所有功能都消耗了大约20%的FPGA逻辑;Premired公司的FPGA中的大部分逻辑都专门用于加密复合体。

上面是一张变形虫图,显示了前身SoC设计中各种功能的相对大小。一些模块,如半冗余的SHA-512和SHA-2加速器,目前之所以包括在内,只是因为我们可以在FPGA中同时安装这两个模块,而不是因为我们严格需要这两个模块。幸运的是,删除SHA-2块就像注释掉四行代码一样简单,节省了大约2800个片LUT或大约9%的设备资源。Litex和svd2rust脚本负责处理其他所有事情!

“Engine25519”是素数域2^255-19运算的算术加速器。这是一个微码的256位算术引擎,能够在大约1微秒内计算256位乘法和归一化,比在RISC-V CPU上运行同等代码快约30倍。它消耗了大量的资源,但被认为是必不可少的,因为Betrusted安全通信应用程序是基于双棘轮算法构建的,该算法严重依赖于这种类型的数学计算。CI文档可能是更多地了解Engine25519实现的最佳起点。这个区块足够大,稍后它会有一整篇帖子专门解释它的功能。

“SHA-512”和“SHA-2”是硬件加速的SHA哈希块。它们源自谷歌的OpenTitan SystemVerilog源代码。SHA-2模块直接来自OpenTitan,主要是因为它易于集成。SHA-512模块是我们自己改编的SHA-2模块。这就是为什么我们在当前的Predicor版本中同时拥有这两个散列的历史原因,尽管大多数应用程序只需要一个散列或另一个散列来进行硬件加速。

“AES”是一个AES加速器,也是直接从Google OpenTitan项目升级而来的。它能够执行AES 128、192和256,并支持ECB、CBC和CTR模式下的加密和解密。

“KeyROM”是一个256×32的ROM,使用FPGA中的固定位置LUT实现。由于ROM的位置是固定的,我们可以使用PrjXray来确定在FPGA的位流中KeyROM位的位置。这允许我们将密钥ROM直接编辑到FPGA位流中,从而将信任从低级eFuse AES密钥转移到前身SoC的高级功能。我们将在即将发布的帖子中更多地讨论最近在FPGA eFuse AES密钥中发现的一些重要漏洞。

“TRNG”是一种基于环形振荡器的片内TRNG。它使用多个小环来收集熵,然后将其合并成一个大环进行最终测量。先驱的TRNG的构建和验证也将在未来的某个时候获得自己的职位。

“ICAPE2”是对FPGA结构中未使用的内部调试端口的显式绑定。ICAPE2是Xilinx允许FPGA自省和访问内部配置状态的方式。我们显式绑定它,这样其他函数就不能尝试声明它。此外,由于ICAPE2位于比特流中的公知位置,因此可以编写一个对比特流执行编译后检查的工具,以验证ICAPE2块实际上已停用。

这就是我们的前身SoC的短暂之旅!我们已经在对功能和安全性至关重要的部分进行了雕琢,并希望开发社区能添加更多。通过注释掉几行代码,您可以清除不必要的代码块,并为您自己的创作腾出空间。Premitive的代码库是完全开放的,可供检查-不需要隐藏的测试逻辑或微码斑点,也不需要NDA来跟踪从RESET释放到执行第一条指令的明确、周期准确的路径。缺乏“暗物质”和设计的完全透明性,这在基于证据的案例中又增加了另一个论点,那就是把你的私事托付给前身的硬件。

如果你喜欢这篇文章,请查看先驱的活动页面,了解更多细节和项目更新!