PCI ROM 如何被阴影化?

Pyj*_*ong 4 hardware boot bios pci-bus pci

在几个资源中我发现: ROM 映像必须复制到 RAM 到 000C0000h 到 000DFFFFh。如果类代码表明这是 VGA 设备 ROM,则必须将其代码复制到从位置 000C0000h 开始的内存中。

1:如果我有PCI饥饿河马卡,ROM大于128KB怎么办?

2:如果我有 ROM 64KB 的常规 PCI 设备,但我有 4 个怎么办?它们是否按顺序加载到该内存范围中?如果是这样(尽管我对此表示怀疑),在 init 和 boot 阶段之间如何保存代码映像?

3:如果 BIOS 决定不遵循规范并指定不同的内存位置,会发生什么情况?为什么使用这个范围很重要?

4:普通机箱与VGA接口到底有什么不同?难道仅仅是限制造成了差异吗?

Lew*_*sey 6

    \n
  1. 非 UEFI BIOS 选项 ROM 通常不会那么大并且有大小限制,但 UEFI 驱动程序可以更大,并且可以放置在 UEFI BIOS 中超过 1MiB,从而在 SEC 阶段切换出实模式。您可以禁用某些您不希望在下次启动时被隐藏到该空间的选项 ROM。

    \n
  2. \n
  3. 使用这个小范围是因为非 UEFI BIOS 在实模式下运行(中断表(IVT,而不是 IDT)从 0h 开始,作为对选项 ROM 的保证),因此只能访问前 1MiB 内存,并且需要内存用于其他用途(BIOS 数据、BIOS、BIOS 堆栈/堆和选项 ROM)。虽然,大多数 BIOS 最终使用虚拟 8086 的虚幻模式或保护模式,因此它们可以同时使用 IVT 和寻址 32 位,因此没有什么可以阻止 BIOS 隐藏 RAM 中其他位置的选项 ROM 以及 BIOS 扫描该区域(我读过,如果 BIOS 只有 64KiB,也可以使用 E0000\xe2\x80\x93EFFFF,但如果选项 ROM 本身寻找其他选项 ROM(例如 UNDI ROM 在 PxE NIC 上寻找 BC ROM),情况就会变得复杂。他们还使用PMM服务来分配 16/32 位堆地址。UEFI不再使用BIOS中断服务;它使用EFI功能。

    \n
  4. \n
  5. 板载显卡的选项 ROM 位于 BIOS 本身中,并且其地址是已知的。它通常被硬编码为移动到 C0000h(实模式分段表示法中的 C000:0000h),或者实际上是任何它想要的位置。BIOS 至少确保它是第一个被执行的选项 ROM,但如果它知道它已将其移动到 D0000h,那么它就知道将控制权传递到哪里。如果允许它位于可变地址而不是固定地址,那么如果其他 PCIe 卡首先被隐藏,它最终可能无法适应该范围。此外,它必须首先扫描 VGA BIOS 类代码,然后再次扫描范围或保留选项 ROM 所在位置的内部表,这比在空间和视频 BIOS 之间线性迭代的简单例程更加复杂。恰好首先被执行。因此它需要一个固定地址,如果它使用固定地址 D0000h 而不是 C0000h,并在其周围放置其他选项 ROM,则会出现空间的外部碎片。

    \n
  6. \n
\n

PAM 不再位于北桥(现代 Intel CPU 上不存在),它们用作 L3 缓存片中 SAD 配置的一部分,对地址进行解码并发送一个向内存控制器、DMI、PCIe 链路或处理器显卡发出请求。BIOS 可以设置 PAM,以便将特定范围的读取发送到 DMI,并将写入发送到内存控制器。这样,BIOS 就可以对其自身进行镜像,并且 PCI(e) XROMBAR 可以设置为它们将要镜像的相同地址。

\n

在我的系统上(Kaby Lake + C230 系列 PCH + UEFI 安全启动已禁用),C0000h\xe2\x80\x93DFFFFh 区域中有 3 个选项 ROM。

\n

显卡BIOS

\n
Option ROM Header: 0x000C0000\n55 AA 80 E9 91 F9 30 30 30 30 30 30 30 30 30 30 U.....0000000000\n30 30 A8 2F E9 B1 2E AF 40 00 90 0B             00./....@...    \n  Signature 0xAA55\n  Length    0x80 (65536 bytes)\n  Initialization entry  0x30F991E9 //software read this wrong it\'s actually 0xF991E9, which is a 16 bit relative jump 0xF991; -1647\n  Reserved  0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30 \n  Reserved  0x30 0xA8 0x2F 0xE9 0xB1 0x2E 0xAF \n  PCI Data Offset   0x0040 //offset is from start of OpROM header\n  Expansion Header Offset   0x0B90\n\nPCI Data Structure: 0x000C0040\n50 43 49 52 86 80 06 04 1C 00 1C 00 03 00 00 03 PCIR............\n80 00 00 00 00 80 80 00                         ........        \n  Signature PCIR\n  Vendor ID 0x8086 - Intel Corporation\n  Device ID 0x0406\n  Product Data  0x001C\n  Structure Length  0x001C\n  Structure Revision    0x03\n  Class Code    0x00 0x00 0x03\n  Image Length  0x0080\n  Revision Level    0x0000\n  Code Type 0x00\n  Indicator 0x80\n  Reserved  0x0080\n
Run Code Online (Sandbox Code Playgroud)\n

SATA 控制器(每个磁盘的 PnP 扩展接头)

\n
Option ROM Header: 0x000D0000\n55 AA 4D B8 00 01 CB 00 00 00 00 00 00 00 00 00 U.M.............\n00 00 00 00 00 00 00 15 A0 00 9A 01             ............    \n  Signature 0xAA55\n  Length    0x4D (39424 bytes)\n  Initialization entry  0xCB0100B8 //mov  ax, 0x100  retf \n  Reserved  0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \n  Reserved  0x00 0x00 0x00 0x00 0x00 0x00 0x15 \n  PCI Data Offset   0x00A0\n  Expansion Header Offset   0x019A\n\nPCI Data Structure: 0x000D00A0\n50 43 49 52 86 80 2A 28 1C 00 1C 00 03 00 04 01 PCIR..*(........\n4D 00 02 0F 00 80 4D 00                         M.....M.        \n  Signature PCIR\n  Vendor ID 0x8086 - Intel Corporation\n  Device ID 0x282A\n  Product Data  0x001C\n  Structure Length  0x001C\n  Structure Revision    0x03\n  Class Code    0x00 0x04 0x01\n  Image Length  0x004D\n  Revision Level    0x0F02\n  Code Type 0x00\n  Indicator 0x80\n  Reserved  0x004D\n\nPnP Expansion Header: 0x000D019A\n24 50 6E 50 01 02 BA 01 01 06 00 00 00 00 C2 00 $PnP............\nD4 00 00 04 01 C4 90 1A 00 00 00 00 00 00 00 00 ................\n  Signature $PnP\n  Revision  0x01\n  Length    0x02 (32 bytes)\n  Next Header   0x01BA\n  Reserved  0x01\n  Checksum  0x06\n  Device ID 0x00000000\n  Manufacturer  0x00C2 - Intel Corporation  //location 0xD00C2\n  Product Name  0x00D4 - SanDisk X400 M.2 2280 256GB //location 0xD00D4\n  Device Type Code  0x00 0x04 0x01\n  Device Indicators 0xC4\n  Boot Connection Vector    0x1A90\n  Disconnect Vector 0x0000\n  Bootstrap Entry Vector    0x0000\n  Reserved  0x0000\n  Resource info. vector 0x0000\n\nPnP Expansion Header: 0x000D01BA\n24 50 6E 50 01 02 00 00 02 9B 00 00 00 00 C2 00 $PnP............\nF5 00 00 04 01 C4 94 1A 00 00 00 00 00 00 00 00 ................\n  Signature $PnP\n  Revision  0x01\n  Length    0x02 (32 bytes)\n  Next Header   0x0000 //next PnP expansion header contains nothing useful\n  Reserved  0x02\n  Checksum  0x9B\n  Device ID 0x00000000\n  Manufacturer  0x00C2 - Intel Corporation\n  Product Name  0x00F5 - ST1000LM035-1RK172\n  Device Type Code  0x00 0x04 0x01\n  Device Indicators 0xC4\n  Boot Connection Vector    0x1A94\n  Disconnect Vector 0x0000\n  Bootstrap Entry Vector    0x0000\n  Reserved  0x0000\n  Resource info. vector 0x0000\n
Run Code Online (Sandbox Code Playgroud)\n

以太网控制器

\n
Option ROM Header: 0x000DA000\n55 AA 08 E8 76 10 CB 55 BC 01 00 00 00 00 00 00 U...v..U........\n00 00 00 00 00 00 20 00 40 00 60 00             ...... .@.`.    \n  Signature 0xAA55\n  Length    0x08 (4096 bytes)\n  Initialization entry  0xCB1076E8 //call then far return \n  Reserved  0x55 0xBC 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \n  Reserved  0x00 0x00 0x00 0x00 0x00 \n  PXEROMID Offset  0x0020 //RWEverything didn\'t pick it up as a separate field and made it part of the reserved section so I separated it.\n  PCI Data Offset   0x0040  \n  Expansion Header Offset   0x0060\n\nUNDI ROM ID Structure: 0x000DA020  //not recognised by RW Everything so I parsed it myself\n55 4E 44 49 16 08 00 00 01 02 32 0D 00 08 B0 C4  UNDI......2...\n80 46 50 43 49 52                                \xc2\xa6-\xc3\x87FPCIR\n  Signature  UNDI\n  StructLength  0x16\n  Checksum  0x08  \n  StructRev  0x00\n  UNDIRev 0x00 0x01 0x02\n  UNDI Loader Offset 0x0D32\n  StackSize 0x0800\n  DataSize 0xC4B0\n  CodeSize 0x4680\n  BusType PCIR\n\nPCI Data Structure: 0x000DA040\n50 43 49 52 EC 10 68 81 00 00 1C 00 03 00 00 02 PCIR..h.........\n08 00 01 02 00 80 08 00                         ........        \n  Signature PCIR\n  Vendor ID 0x10EC - Realtek Semiconductor\n  Device ID 0x8168\n  Product Data  0x0000\n  Structure Length  0x001C\n  Structure Revision    0x03\n  Class Code    0x00 0x00 0x02\n  Image Length  0x0008\n  Revision Level    0x0201\n  Code Type 0x00\n  Indicator 0x80\n  Reserved  0x0008\n\nPnP Expansion Header: 0x000DA060\n24 50 6E 50 01 02 00 00 00 D7 00 00 00 00 AF 00 $PnP............\n92 01 02 00 00 E4 00 00 00 00 C1 0B 00 00 00 00 ................\n  Signature $PnP\n  Revision  0x01\n  Length    0x02 (32 bytes)\n  Next Header   0x0000\n  Reserved  0x00\n  Checksum  0xD7\n  Device ID 0x00000000\n  Manufacturer  0x00AF - Intel Corporation\n  Product Name  0x0192 - Realtek PXE B02 D00\n  Device Type Code  0x02 0x00 0x00\n  Device Indicators 0xE4\n  Boot Connection Vector    0x0000\n  Disconnect Vector 0x0000\n  Bootstrap Entry Vector    0x0BC1 // will be at 0xDABC1\n  Reserved  0x0000\n  Resource info. vector 0x0000\n
Run Code Online (Sandbox Code Playgroud)\n

在另一台具有旧版 BIOS 的计算机上,仅 VGA 选项 ROM 出现在该区域的扫描中,位于 0xC0000。没有 EHCI,也没有 SATA。对我来说,这表明它嵌入在 BIOS 中,但只是 BIOS 代码的一部分,而不是作为选项 ROM(在 BBS 中称为 BAID);初始化控制器、扫描启动设备、在 IPL 表中输入其信息并挂钩 int 13h 以便 MBR/VBR 可以访问磁盘的代码在 BIOS 中进行了硬编码。另外,BCV 挂钩顺序优先级不再重要,因为现在它们都作为 BAID 输入到 IPL 表中,而不仅仅是磁盘 80h 可引导(通过读取 BDA 中的当前磁盘枚举号来填充,然后填写该磁盘)许多条目及其各自的详细信息是从 int 13h 调用获取的)。据推测,IPL 表包含要从中启动的磁盘编号,并将其传递给条目中的向量,该条目将是所有 BAID 共享的代码,该代码使用 int 13h 到 0x7c00 检查有效的 MBR 从磁盘加载第一个扇区,然后通过控制。然后,MBR 会将其自身从 0x7c00 移开,并将活动分区的第一个扇区(即 VBR)加载到 0x7c00 并将控制权传递给它,这将是 JMP 指令(如果是默认的 Windows 指令。如果是 GRUB,它将从扇区 1\xe2\x80\x9365 加载控制权并将其传递给 core.img)。然后,VBR 将使用 VBR 中 BPB 中的 HiddenSectors 值将 IPL 加载到磁盘上的扇区 1\xe2\x80\x9315 中,并将控制权传递给它。有关从此时开始 Windows 启动的更多详细信息,请参阅此处我的回答。

\n

SATA控制器上的初始化条目中的代码是远返回0x100的代码。这似乎是在初始化完成后由 BIOS 或选项 ROM 本身修改的,或者可能只是一个无用的东西,因为它是一个在 BIOS 中其他地方初始化的嵌入式设备。根据定义,初始化代码现在毫无用处,并且遵守 DDIM 的选项 ROM 可能会在初始化后从 RAM 中删除初始化代码并重新计算长度和校验和。视频BIOS甚至做了一些负面的相对跳跃。这表明 BIOS 将其视频 BIOS 隐藏到 C0000h 之前的位置,部分隐藏在 VGA VRAM 区域上,以便选项 ROM 标头出现在 C0000h 处。

\n

“长度”似乎描述了选项 ROM 初始化后遗留选项 ROM 影子 RAM 区域中所占用的空间量。

\n

以下是拆分 PXE 选项 ROM 的内存映射示例:

\n

在此输入图像描述

\n

BIOS 可能会一次加载并初始化一个 XROMBAR,而不是一次性设置所有 XROMBAR 以使其包含预初始化的长度。它无法覆盖/删除选项 ROM,因为选项 ROM 中与 IPL 代码分开的例程仍可能被 BCV 调用以与硬件交互。例如,在运行视频BIOS初始化代码之后,扫描PCI配置空间并且返回长度的第一个XROMBAR将被设置到视频BIOS的末尾。然后读取将定向到 DMI,写入将定向到内存。然后它将其映射到内存,将读取重定向到 RAM,并对初始化条目执行远程调用。然后,IPL 代码通过删除初始化代码来缩小自身。BIOS 检查选项 ROM 的新大小以及 PnP 扩展标头和寄存器 BEV/BCV。然后它将加载重定向回 DMI 并加载下一个 XROMBAR。BIOS 一次构建 BCV 表条目,然后按 BCV 优先级顺序执行 BCV。

\n

选项 ROM 可以将 BEV/BCV 移动到扩展内存中的 PMM 分配,在 BEV/BCV 偏移处留下跳转指令,但这会破坏 BCV/BEV 中跳转到选项 ROM 其余部分中函数的相对寻址。因此,它可以将其整个自身重新定位到 PMM 分配,并将大小减少到仅包含标头,但显然大多数选项 ROM 的情况并非如此。不过,BEV 确实重新定位了 UNDI 驱动程序。

\n