QEMU 固件配置(fw_cfg)设备
客户机侧硬件接口
此硬件接口允许客户机取得各种数据项(数据块)。它们可以影响固件自身的配置方式, 也可以包含需要为客户机操作系统安装的表。例如:设备启动顺序、ACPI 和 SMBIOS 表、 虚拟机 UUID、SMP 和 NUMA 信息,以及用于直接启动(Linux)内核的 kernel/initrd 映像等。
选择器(控制)寄存器
只写
位置:取决于平台(IOport 或 MMIO)
宽度:16 位
字节序:小端(IOport)或大端(MMIO)
写入此寄存器可设置固件配置项的索引,随后通过数据寄存器访问该项。
设置选择器寄存器会将数据偏移置零。数据偏移决定通过数据寄存器访问哪些数据, 下文将进一步说明。
选择器寄存器的 Bit14 表示是否写入配置项。值为 0 表示仅读取此项,对数据端口的 所有写访问都被忽略。值为 1 表示可通过写数据寄存器覆盖该项的数据。换言之, 当选择器值位于 0x4000-0x7fff 或 0xc000-0xffff 时,启用配置写模式。
备注
从 QEMU v2.4 开始,不再支持写入 fw_cfg 数据寄存器,写操作将被忽略 (视为空操作)!
备注
从 QEMU v2.9 开始恢复写入支持,但只能通过 DMA 接口(见下文)。 此外,每个具体配置项是否可写独立控制,不受选择器键值中 Bit14 的影响。
选择器寄存器的 Bit15 表示配置项是否为架构专用。值为 0 表示通用配置项, 值为 1 表示特定架构专用的配置项。换言之,选择器值在 0x0000-0x7fff 之间时 访问通用配置项,在 0x8000-0xffff 之间时访问架构专用配置项。
数据寄存器
读/写(从 QEMU v2.4 开始忽略写入,但请参阅 DMA 接口)
位置:取决于平台(IOport[1] 或 MMIO)
宽度:8 位(IOport),8/16/32/64 位(MMIO)
字节序:保持字符串顺序
数据寄存器用于访问各个固件配置数据项的字节数组。具体配置项通过写选择器寄存器 选定,如上文所述。
写入选择器寄存器后,数据偏移最初置零。每次成功访问数据寄存器后,数据偏移按 相应访问宽度递增。
每个固件配置项都有对应的最大数据长度。数据偏移越过此最大长度末尾后, 所有读取均返回 0x00,所有写入均被忽略。
对数据寄存器执行 N 字节宽的读取,将按地址递增顺序,以子字符串形式返回选定 固件配置项的后续 N 个可用字节,与 memcpy() 类似。
寄存器位置
内存映射的 fw_cfg 设备采用以下标准寄存器布局:
基地址:数据寄存器(64 位)
基地址 + 8:选择器寄存器(16 位)
基地址 + 16:DMA 地址寄存器(64 位)
出于历史原因,一些架构或机器采用不同布局:
- x86, x86_64
选择器寄存器 IOport:0x510
数据寄存器 IOport: 0x511
DMA 地址 IOport: 0x514
- PA-RISC:
基地址:选择器寄存器(16 位)
基地址 + 4:数据寄存器(8 位)
- 32 位 SPARC、PPC
g3beige、mac99、prep: 基地址:选择器寄存器(16 位)
基地址 + 2:数据寄存器(8 位)
- 64 位 SPARC:
基地址:选择器寄存器(16 位)
基地址 + 1:数据寄存器(8 位)
- MIPS
loongson3-virt机器: 基地址:选择器寄存器(16 位)
基地址 + 8:数据寄存器(64 位)
ACPI 接口
fw_cfg 设备使用 ACPI ID QEMU0002 定义。由于预期通过 fw_cfg 设备本身将 ACPI 表
传递给客户机,客户机侧固件不能使用 ACPI 查找 fw_cfg。不过,固件设置好 ACPI 表并将
控制权交给客户机内核后,内核可以使用 fw_cfg ACPI 节点,更准确地统计正在使用的
IOport 或 MMIO 区域。
固件配置项
签名(键 0x0000,FW_CFG_SIGNATURE)
使用键 0x0000(FW_CFG_SIGNATURE)选择“签名”项,然后从数据寄存器读取四个字节,
即可验证 fw_cfg 选择器和数据寄存器是否存在。如果存在 fw_cfg 设备,读出的四个字节
将包含字符 QEMU。
如果 DMA 接口可用,读取 DMA 地址寄存器会返回 0x51454d5520434647
(大端格式的 QEMU CFG)。
修订版本/功能位图(键 0x0001,FW_CFG_ID)
该项是一个 32 位小端无符号整数,用于检查已启用的功能。
位 0:传统接口。始终置位。
位 1:DMA 接口。
文件目录(键 0x0019,FW_CFG_FILE_DIR)
存储于选择器键 0x0020 或更高值(FW_CFG_FILE_FIRST 或更高)下的固件配置项,
在目录结构中拥有对应条目,便于客户机侧固件识别并取得这些配置项。
此文件目录的格式(来自 QEMU 源码树的 fw_cfg.h)如下,并附有少量注释以便理解:
struct FWCfgFiles { /* the entire file directory fw_cfg item */
uint32_t count; /* number of entries, in big-endian format */
struct FWCfgFile f[]; /* array of file entries, see below */
};
struct FWCfgFile { /* an individual file entry, 64 bytes total */
uint32_t size; /* size of referenced fw_cfg item, big-endian */
uint16_t select; /* selector key of fw_cfg item, big-endian */
uint16_t reserved;
char name[56]; /* fw_cfg item name, NUL-terminated ascii */
};
其他所有数据项
选择器键及其对应配置项的用途、格式和可写性,请以 QEMU 源码中的最新权威列表为准。
范围
理论上,最多可有 0x4000 个通用固件配置项,以及 0x4000 个架构专用配置项。
选择器寄存器 |
范围用途 |
|---|---|
0x0000 - 0x3fff |
通用(0x0000 - 0x3fff,通常只读,在 QEMU v2.9+ 中可能通过 DMA 接口读写) |
0x4000 - 0x7fff |
通用(0x0000 - 0x3fff,可读写,在 QEMU v2.4+ 中忽略) |
0x8000 - 0xbfff |
架构专用(0x0000 - 0x3fff,通常只读,在 QEMU v2.9+ 中可能通过 DMA 接口读写) |
0xc000 - 0xffff |
架构专用(0x0000 - 0x3fff,可读写,在 v2.4+ 中忽略) |
实际允许的固件配置项数量取决于机器类型和版本。
客户机侧 DMA 接口
如果功能位图的位 1 置位,则存在 DMA 接口。它是对现有 fw_cfg 接口的补充,而非替代。 可以通过 64 位宽的地址寄存器使用此接口。
地址寄存器采用大端格式,启动时及操作完成后其值均为 0。写入低半部(偏移 4)会 触发操作。因此,32 位地址的操作只需写入一次即可触发;64 位地址的操作可通过一次 64 位写入,或从高半部(偏移 0)开始的两次 32 位写入触发。
应向该寄存器写入 RAM 中 FWCfgDmaAccess 结构的物理地址。
FWCfgDmaAccess 结构格式如下:
typedef struct FWCfgDmaAccess {
uint32_t control;
uint32_t length;
uint64_t address;
} FWCfgDmaAccess;
结构字段均采用大端格式,位于最低地址的字段为 control。
control 字段包含以下位:
位 0:错误
位 1:读取
位 2:跳过
位 3:选择。高 16 位为选定索引。
位 4:写入
触发操作时,如果 control 字段的位 3 置位,高 16 位会被解释为固件配置项的索引。
效果与写入选择器寄存器相同。
如果 control 字段的位 1 置位,则执行读取操作。将当前选择器与偏移处的
length 字节复制到 address 字段指定的 RAM 物理地址。
如果 control 字段的位 4 置位(且位 1 未置位),则执行写入操作。
将 address 字段指定的 RAM 物理地址处的 length 字节复制到当前选择器与偏移处。
QEMU 不允许写入起点或终点超出当前选择器对应配置项的末尾(即不能调整配置项大小)。
会被截断的写入将整体丢弃。对只读配置项的写入也会被拒绝。所有这些写入错误均会
将 control 字段的位 0(错误位)置位。
如果 control 字段的位 2 置位(且位 1 和位 4 均未置位),则执行跳过操作。
当前选择器的数据偏移前移 length 字节。
读取 control 字段以检查结果:
- 错误位置位
发生错误。
- 所有位均清零
传输成功完成。
- 其他情况
传输仍在进行中(目前实现并非异步,因此不会出现;将来可能出现)。
外部提供的配置项
从 v2.4 开始,可通过 QEMU 命令行插入“文件”fw_cfg 配置项,即选择器键高于
FW_CFG_FILE_FIRST、且在 fw_cfg 文件目录结构中有对应条目的配置项。
语法如下:
-fw_cfg [name=]<item_name>,file=<path>
或:
-fw_cfg [name=]<item_name>,string=<string>
从 v5.1 开始,QEMU 允许一些对象生成 fw_cfg 专用内容,再通过命令行中的 'gen_id' 选项将内容与一个“文件”项关联,语法如下:
-object <generator-type>,id=<generated_id>,[generator-specific-options] \
-fw_cfg [name=]<item_name>,gen_id=<generated_id>
更多文档请参阅 QEMU 手册页。
建议 item_name 仅使用普通 ASCII 字符。
以 opt/ 开头的配置项名称保留给用户。除非用户明确要求,否则 QEMU 绝不会
创建此类名称的条目。
为避免不同用户之间的名称冲突,强烈建议使用以 opt/RFQDN/ 开头的名称,
其中 RFQDN 为你所控制的完全限定域名的反向形式。例如,如果 SeaBIOS 要定义
额外名称,合适的前缀为 opt/org.seabios/。
出于历史原因,opt/ovmf/ 保留给 OVMF 固件。
前缀 opt/org.qemu/ 保留给 QEMU 本身。
使用不以 opt/ 开头的名称可能存在风险,且完全不受支持。尝试使用时 QEMU 会警告。
使用 'gen_id' 时允许名称不以 opt/ 开头(即不发出警告),但必须清楚了解其后果。
所有外部提供的 fw_cfg 配置项对客户机均为只读。