处理器如何从 SPI 闪存读取 BIOS?

Ins*_*der 6 x86 bios spi firmware uefi

典型的 x86 系统将固件(也称为 BIOS 或 UEFI)存储在基于 SPI 的闪存芯片中。当上电发生时,处理器开始执行复位向量,该向量指向存储 BIOS 的内存映射 SPI 芯片。从这里开始,引导发生在 BIOS 完成平台初始化、加载引导加载程序,然后加载内核时。

但是,处理器如何知道如何从 SPI 芯片中读取数据呢?我的意思是,那时处理器将不知道 SPI 协议,芯片的哪些寄存器写入命令以及哪个寄存器查找读取的数据。读取是如何发生在如此低的水平上的?

Mar*_*oom 15

Haswell+ CPU 在加电时(在 BIST - 内置自检之后)执行的第一件事是执行微编码例程,这是英特尔 TXT技术的一部分,以4GiB-40h获取FIT并执行 BIOS ACM(身份验证代码)模块),并最终继续测量的引导,或回退到 4GiB - 10 小时的传统重置向量。

无论哪种方式,CPU 都需要从略低于 4GiB 的几个 MiB 的内存窗口中获取指令。
CPU 没有 SPI 接口,出于安全原因,对这个窗口的请求总是被重定向到 DMI 接口。
您可以在第 8-9代数据手册 Vol. 2.6 Chapter 2.6 中找到以下地图2(即使在前几代中也是如此,AFAIK):

内存映射

由于本段,这是相关的:

出于安全原因,处理器会将此 [High BIOS] 范围积极解码为 DMI。这种正解码确保任何重叠范围都将被忽略。这确保引导向量和 BIOS 在 PCH 之外执行。

因此 CPU 从 DMI 接口启动,因此 PCH(平台控制器集线器)处理请求。
请注意,即使在较旧的系统中,接近 4GiB 的窗口被减法解码到 DMI 接口(即仅在没有其他设备声明时才发送到 DMI 接口),引导几乎总是从 DMI 接口本身进行。
新的正解码行为是一种针对引导攻击的安全措施。

如果您查看相对现代的 PCH(即200 系列)的数据表,您会发现它支持 LPC 桥接器或 SPI 接口后面的闪存 ROM。

我们将仅限于后者。
在该芯片组中,SPI 桥接器是 PCI 设备 31,功能 15。
在其 PCI 配置空间中有标准寄存器和:

  • 一个 BAR(基地址寄存器)映射 MMIO 寄存器的 4 KiB 窗口以控制 SPI 接口本身。
  • BIOS解码使能寄存器,启用或禁用的特定窗口存储器访问的回收。
  • 一个控制寄存器,用于启用各种安全功能(包括启动是否关闭 SPI 或 LPC 接口)。

我们重点看第二点:

BIOS 解码使能寄存器

需要注意的两件事:首先,该寄存器启用或禁用从 CPU 向 SPI 发送内存访问(在 4MiB 以下 4GiB 和其他区域)。
第二个是默认值为 0ffcfh,这意味着默认情况下所有窗口都映射到 SPI
BIOS控制寄存器也选择SPI为默认启动界面,但这也与softstrap /引导针,IIRC配置。

最后但并非最不重要的是,当 PCH 看到对像 4GiB-10h 这样的地址的访问时,它无法将其作为它发送到闪存 ROM,因为它超出了闪存 ROM 本身的范围。
它必须首先解码它,减去一个偏移量。但是,此偏移量取决于 Flash ROM 的大小。

在 PCH 之前(我认为是在 ICH8 芯片组和一些非最新的 Atom 芯片组中),Flash ROM 是在没有描述符的情况下使用的。
芯片组简单地使用别名将 ROM从 4GiB映射到 4GiB-16MiB,这意味着地址4GiB - X将映射到Flash Size - (X % Flash size)
结果是,例如,2 MiB 闪存在 4 GiB 限制以下的 16MiB 窗口中出现了 8 次映射。
在这些芯片组中,有引导引脚来配置闪存大小。

今天,用于 PCH 的闪存 ROM使用描述符,其中闪存被划分为区域(BIOS、ME、GbE 等)。
只有 BIOS 区域被映射到 CPU 的地址空间中。有一个基于请求者的 id(由其 PCI 标识给出)的安全描述符系统。
有关此主题的介绍,请参阅或更好的以获得更完整的描述(有点过时但仍然相关)。
区域在这里是相关的,因为它们与它们的偏移量和大小一起列在闪存描述符中,因此 PCH 可以知道如何将 CPU 地址转换为闪存线性地址。

最后,SPI 接口的 MMIO 寄存器允许对 Flash ROM 进行原始访问。可以合成命令以向下发送 SPI 总线,从而可以重新编程闪存 ROM(例如)。
它们仍然受到应在数据表 IIRC 中列出的各种安全对策的约束。