工作记录[2]
工作记录2
鉴于之前已经将基于mailbox的连接跑通,虽然对mailbox的一些设计还是没有特别理解,但还是打算先写一些初步的测试代码,以验证其部分功能的正确性。
或许写着写着就能龙场悟道。
测试程序设计
测试程序为mbx_test.c,该程序被编译成的bin文件会被加载到CPU的内存中被执行。
首先先输出一行测试开始的信息,再定义要用到的寄存器的的地址:
1 | LOG_INFO("MBX TEST BEGINS"); |
紧接着卡住了。原以为可以通过邮箱向OT RoT内存中写东西,但现在发现不行。所有RoT的内存空间传输数据的行为都需要通过DMA,这包括:
- 简单的DMA传输请求:
- 说明:请求者根据DMA传输操作的要求指定源地址、目标地址、源空间ID和目标空间ID。集成的OpenTitan主机固件解析对象,检查请求,如果认为传输可以进行,则配置OT DMA控制器。
- 响应对象:预期有响应DOE对象
- 中断:如果启用,可以配置在DMA传输完成后向请求者生成中断。
- 安全存储写入代理
- 说明:由请求者(系统主机或SoC固件元素)使用,以请求OT RoT提供对OT RoT拥有的闪存存储的代理访问。要写入闪存的内容由请求者放置在SoC内存位置中,并通过DOE对象传递写入请求和内存指针。响应者执行安全检查,启动内容到闪存的DMA传输,并完成闪存写入操作。
- 请求者在请求对象中设置以下参数:
- 目标地址:指向从中读取数据的闪存存储地址的指针
- 目标地址ID:= 0x3(FLASH)
- 源地址:放置NV存储(Non-Volatile Storage,非易失性存储)读取数据的内存位置
- 源地址ID:根据请求者要求,为系统内存或CTN内存
- 总大小:要写入的数据块的大小
- 如果OT的策略允许写入闪存的该部分,OT将启动写入访问。
然而,我在曾经对整体架构理解很浅时,写出的连接的代码中DMA连接部分是错误的。在上一次的源代码更改中,我将DMA对应的TL node(主端)从blackbox中删去了。这导致目前只支持mailbox访问,而mailbox访问的主要目的——使用DMA传输数据,则完全无法实现。
没办法,要么先正确连上DMA,要么先测试mailbox的少部分功能。我选择先执行后者?原因有二,一来是先确保一部分功能的正确性,后续debug时能更加容易推出出问题的地方,二来是很快要开组会了,得有点东西好讲。
首先,先把支持读的邮箱寄存器都读一遍:
1 | uint32_t ref_control = 0xffffffff; |
编译测试了一下,很快得到了结果:
1 | I00000 ./src/sw/device/tests/mbx_test.c:11] MBX TEST BEGINS |
很奇怪,为什么status的第0位,即DOE Busy是1?文档中提到,此位由DOE实例在处理接收到的数据对象时设置,但现在明明没有在处理什么事务啊。
略微修改代码,结果:
……肯定哪里出问题了。查询mbx_reg_pkg.sv:
1 | parameter logic [3:0] MBX_STATUS_RESVAL = 4'h 1; |
status寄存器的初始值被设为1。即在复位时,DOE Busy位确实是被设为了1?
但要如何将这一位变为0?一种情况是处理完数据对象,但我并没有往里传数据对象;另一种是处理完Abort,但我更没有给出abort指令。那在这种情况下,他自己又似乎不会无缘无故将busy位设为0,那难道要我给出abort指令?或者我手动将其改为0?
关于DOE busy复位后为1
没找到相关文档,所以首先,我决定看波形。
唉,我是真不想看波形,有种吸一口气然后深潜的感觉。
一番找寻后,终于发现问题所在——在mbx_imbx.sv中,hostif_range_valid_i这个信号是拉低的。这应该是我没设置好base_address和limit_address导致的。
关于以上两个参数(实际上是四个,入站和出站各两个),文档中对其解释为(对于imbx):
- base_address:标记 OT 内部内存空间中启用内存范围起始的基地址。
- limit_address:标记 OT 内部内存空间中 DOE 收件箱内存范围结束的限制。
- 那么为什么之前没设置呢?因为文档里很明确说明SoC通过4个邮箱寄存器与RoT交互。而imbx和ombx的base_address寄存器和limit_address寄存器并不属于这4个邮箱,它们是OpenTitan Internal DOE Registers。即外部无法访问,只能被内部的固件访问(these registers are accessible to the firmware running on IBEX core only)。
翻阅源代码,发现其确实是只能被来自core的tl信号更改,来自SoC的tl信号无法访问这些寄存器(测试过了)。
所以这样就陷入死锁了。我首先想到,是不是应该在RoT的ROM里的boot程序里加东西或者改参数,但看半天相关文档发现显然不太行。
然后我就想干脆把mbx和ombx的base_address和limit_address的复位值改了,使其符合要求不就行了吗。虽然这种做法显然非常有问题,但我一时想不到别的方法。但在改完之后,我发现即使这些值都被正确设置了,但range valid仍为0。
我认为这可能说明range valid不是通过硬件判断的。翻源代码发现确实如此,是来自core的tl信号控制写入的。那这样的话我干脆把range valid的复位值也改为1。虽然这样做问题显然更大了,但我想不到别的办法。但这样设置后,其mailbox中的range valid仍然为0。这是因为判断该valid还需要一个enable信号,这个信号在来自core的tl信号往valid里写入0或1时被拉高。
所以现在又回到了前面的问题。翻阅各个文档完全没有提到这种情况。
后面发现Darjeeling的文档中有提到这么一句:
Communication with the SoC is mainly via the mailboxes, DMA and SoC proxy module. The SoC proxy module serves as a comportable IP frontend for incoming IRQs, reset requests, wake up requests, alerts and the TL-UL egress port into the CTN network.
之前一直只关注mailbox和DMA,而一直忽略了SoC proxy module。这里提到说,这个代理模块处理wake up requests。我查看SoC proxy 的文档,但里面没有对这个代理模块的任何解释。所以我决定先在源代码里找到这个异步唤醒请求信号。
Darjeeling的官方有给出一个chip_darjeeling_verilator.sv,其中实例化了top_darjeeling,用于进行一些模块的简单测试。我找到该端口,发现:
也就是说,SoC应该负责给出这个“唤醒请求”,但以前是认为RoT在被复位后即可直接使用,我认为这二者是冲突的。我不知道这个请求是干嘛的,也不知道其输入的时序逻辑应该是怎样的(因为没有文档,我猜起码要拉高一段时间),但我猜测需要给出这个请求,RoT才能进入“工作状态”,然后core会配置好mailbox的一些只能由内部core访问的参数寄存器。
所以现在的想法是,在复位完成后拉高一段时间这个信号,然后再进行测试。