固件

固件布局

基于 CSS 的固件结构用于所有平台上的 GuC 版本和 DG1 之前的 HuC 版本。从 DG2/MTL 开始,HuC 使用 GSC 布局。CSS 固件布局如下所示

+======================================================================+
|  Firmware blob                                                       |
+===============+===============+============+============+============+
|  CSS header   |     uCode     |  RSA key   |  modulus   |  exponent  |
+===============+===============+============+============+============+
 <-header size->                 <---header size continued ----------->
 <--- size ----------------------------------------------------------->
                                 <-key size->
                                              <-mod size->
                                                           <-exp size->

固件可能包含模数密钥和指数数据,也可能不包含。头、微码和 RSA 签名是驱动程序必须使用的组件。每个组件的长度(全部以双字为单位)可以在头中找到。如果固件中不存在模数和指数,即截断的映像,长度值仍然会出现在头中。

驱动程序将根据以下规则执行一些基本的固件大小验证

  1. 头、微码和 RSA 是必须有的组件。

  2. 如果存在所有固件组件,则它们按照上面布局表中的顺序排列。

  3. 每个组件的长度信息可以在头中找到,以双字为单位。

  4. 驱动程序不需要模数和指数密钥。它们可能不会出现在固件中。因此,驱动程序在这种情况下会加载一个截断的固件。

基于 GSC 的固件结构用于所有平台上的 GSC 版本和从 DG2/MTL 开始的 HuC 版本。较早的 HuC 版本则使用基于 CSS 的布局。与 CSS 头不同,GSC 头使用目录+条目结构(即,有一个指向特定头扩展的地址数组,这些头扩展由名称标识)。尽管头结构相同,但一些条目是 GSC 特有的,而另一些条目是 HuC 特有的。清单头条目(包括有关二进制文件的基本信息,如版本)始终存在,但根据二进制类型命名不同。

HuC 二进制文件以代码分区目录 (CPD) 头开始。驱动程序中我们感兴趣的条目是

  1. “HUCP.man”:指向 HuC 的清单头。

  2. “huc_fw”:指向固件代码。在支持通过 DMA 加载和两步 HuC 身份验证(即 MTL+)的平台上,这是一个完整的基于 CSS 的二进制文件,而如果 GSC 是执行加载的(这种情况仅发生在 DG2 上),则此部分仅包含微码。

基于 GSC 的 HuC 固件布局如下所示

+================================================+
|  CPD Header                                    |
+================================================+
|  CPD entries[]                                 |
|      entry1                                    |
|      ...                                       |
|      entryX                                    |
|          "HUCP.man"                            |
|           ...                                  |
|           offset  >----------------------------|------o
|      ...                                       |      |
|      entryY                                    |      |
|          "huc_fw"                              |      |
|           ...                                  |      |
|           offset  >----------------------------|----------o
+================================================+      |   |
                                                        |   |
+================================================+      |   |
|  Manifest Header                               |<-----o   |
|      ...                                       |          |
|      FW version                                |          |
|      ...                                       |          |
+================================================+          |
                                                            |
+================================================+          |
|  FW binary                                     |<---------o
|      CSS (MTL+ only)                           |
|      uCode                                     |
|      RSA Key (MTL+ only)                       |
|      ...                                       |
+================================================+

GSC 二进制文件则以布局头开始,其中包含二进制文件各个分区的位置。我们感兴趣的是 boot1 分区,在该分区中我们可以找到 BPDT 头,后跟条目,其中一个条目指向分区的 RBE 子部分,其中包含 CPD。GSC blob 不包含基于 CSS 的二进制文件,因此我们只需要查找清单,该清单位于 “RBEP.man” CPD 条目下。请注意,我们不需要查找实际固件代码在映像中的位置,因为 GSC ROM 本身会解析头来查找它并加载它。GSC 固件头布局如下所示

+================================================+
|  Layout Pointers                               |
|      ...                                       |
|      Boot1 offset  >---------------------------|------o
|      ...                                       |      |
+================================================+      |
                                                        |
+================================================+      |
|  BPDT header                                   |<-----o
+================================================+
|  BPDT entries[]                                |
|      entry1                                    |
|      ...                                       |
|      entryX                                    |
|          type == GSC_RBE                       |
|          offset  >-----------------------------|------o
|      ...                                       |      |
+================================================+      |
                                                        |
+================================================+      |
|  CPD Header                                    |<-----o
+================================================+
|  CPD entries[]                                 |
|      entry1                                    |
|      ...                                       |
|      entryX                                    |
|          "RBEP.man"                            |
|           ...                                  |
|           offset  >----------------------------|------o
|      ...                                       |      |
+================================================+      |
                                                        |
+================================================+      |
| Manifest Header                                |<-----o
|  ...                                           |
|  FW version                                    |
|  ...                                           |
|  Security version                              |
|  ...                                           |
+================================================+

一次写入保护内容内存 (WOPCM) 布局

在写入 GuC WOPCM 大小和偏移寄存器后,WOPCM 的布局将固定下来,这些寄存器的值由 HuC/GuC 固件大小和一组硬件要求/限制计算和确定,如下所示

  +=========> +====================+ <== WOPCM Top
  ^           |  HW contexts RSVD  |
  |     +===> +====================+ <== GuC WOPCM Top
  |     ^     |                    |
  |     |     |                    |
  |     |     |                    |
  |    GuC    |                    |
  |   WOPCM   |                    |
  |    Size   +--------------------+
WOPCM   |     |    GuC FW RSVD     |
  |     |     +--------------------+
  |     |     |   GuC Stack RSVD   |
  |     |     +------------------- +
  |     v     |   GuC WOPCM RSVD   |
  |     +===> +====================+ <== GuC WOPCM base
  |           |     WOPCM RSVD     |
  |           +------------------- + <== HuC Firmware Top
  v           |      HuC FW        |
  +=========> +====================+ <== WOPCM Base

GuC 可访问的 WOPCM 从 GuC WOPCM 基址开始,到 GuC WOPCM 顶部结束。WOPCM 的顶部保留用于硬件上下文(例如 RC6 上下文)。

GuC CTB Blob

我们分配单个 blob 来保存 CTB 描述符和缓冲区

偏移量

内容

大小

0x0000

H2G CTB 描述符(发送)

4K

0x0800

G2H CTB 描述符 (g2h)

0x1000

H2G CT 缓冲区(发送)

n*4K

0x1000 + n*4K

G2H CT 缓冲区 (g2h)

m*4K

每个 CT 缓冲区 的大小必须是 4K 的倍数。我们不希望在任何时候都有太多的消息在飞行中,除非我们使用 GuC 提交。在这种情况下,每个请求至少需要 2 个双字,这使我们最多可以排队 256 个请求。希望这有足够的空间来避免驱动程序上的背压。我们增加接收缓冲区(相对于发送)的大小,以确保 G2H 响应 CTB 有一个着陆点。

除了提交之外,G2H 缓冲区还需要能够为可恢复的页面错误通知保留足够的空间。页面错误的数量是中断驱动的,并且可能与可用的计算资源数量一样多。但是,这些工作的大部分实际上是在单独的页面错误工作线程中完成的。因此,我们只需要确保队列有足够的空间来处理所有的提交和响应,以及一个用于传入页面错误的额外缓冲区。

GuC 节能 (PC)

当启用 GuC 提交时,GuC 节能 (PC) 支持多种功能,以实现 GT 的最有效和最佳性能,包括频率管理、渲染 C 状态管理和各种用于功率平衡的算法。

单循环节能 (SLPC) 是 GuC 固件中连接的节能功能套件的名称。该固件向主机公开一个编程接口,用于控制 SLPC。

内部 API

TODO