规范解读
看完了代码才发现有这个规范文档。不过也好,正好印证一下我对代码的理解。
按照我的理解,讲清楚两个东西就可以理解这个规范:
接口
数据结构
接口
在文档的开头就描述了两个东西:
Selector (Control) Register
Data Register
说白了就是有两个寄存器/通道,分别对应了控制面和数据面。
扯多了,直白的解释就是:
用户使用时,先通过Selector Register选定需要访问的单元,再通过Data Register来获取实际的数据。
好了,接口这部分其实就这么些,没多大花头。
在规范中还定义了这两个接口的地址。
=== x86, x86_64 Register Locations ===
Selector Register IOport: 0x510
Data Register IOport: 0x511
DMA Address IOport: 0x514
=== ARM Register Locations ===
Selector Register address: Base + 8 (2 bytes)
Data Register address: Base + 0 (8 bytes)
DMA Address address: Base + 16 (8 bytes)
我猜大家到这里一定感觉啥都不知道,不着急,等看到数据结构就清楚了。
数据结构
好了,这里要上一个巨大的数据结构了。嗯,其实呢和某些结构相比也不算大,主要是这里面有数组,所以显得大了。
FWCfgIoState
+------------------------------------------+
|machine_ready |
| notify | = fw_cfg_machine_ready
+------------------------------------------+
|dma_iomem |
| (MemoryRegion) |
| +--------------------------------------+
| |addr | = FW_CFG_IO_BASE + 4(0x514)
| |name | = "fwcfg.dma"
| |ops | fw_cfg_dma_mem_ops
| |opaque | FWCfgState itself
| |size | = 8
+---+--------------------------------------+
|comb_iomem |
| (MemoryRegion) |
| +--------------------------------------+
| |addr | = FW_CFG_IO_BASE(0x510)
| |name | = "fwcfg"
| |ops | fw_cfg_comb_mem_ops
| |opaque | FWCfgState itself
| |size | = 0x02
+---+--------------------------------------+
|cur_entry | fw_cfg_select(key)
|cur_offset |
| (uint) |
+------------------------------------------+
|file_slots |
| (uint16) |
+------------------------------------------+
|files |
| (FWCfgFiles) |
| +--------------------------------------+
| |count |
| | (uint32_t) |
| +--------------------------------------+
| |f[] | etc/acpi/tables etc/table-loader
| | (FWCfgFile) | ------------------------------------------------------------------------------------------->+------------------------------+----------------------->+------------------------------+
| | +----------------------------------+ |name | |name |
| | |name | | (char [FW_CFG_MAX_FILE_PATH])| | (char [FW_CFG_MAX_FILE_PATH])|
| | | (char [FW_CFG_MAX_FILE_PATH]) | |size | |size |
| | |size | |select | |select |
| | |select | |reserved | |reserved |
| | |reserved | +------------------------------+ +------------------------------+
+---+---+----------------------------------+ ^ ^
|entry_order | [FW_CFG_FILE_FIRST + file_slots] | |
| (int*) | | |
+------------------------------------------+ | |
|entries[0] | [FW_CFG_FILE_FIRST + file_slots] | |
| (FWCfgEntry*) | | |
| | | |
| | v v
| | [FW_CFG_SIGNATURE] [FW_CFG_FILE_DIR] [FW_CFG_FILE_FIRST+1] [FW_CFG_FILE_FIRST+2]
| | +-------------------+ +-----------------+ +------------------+ +------------------+
| | |data | = "QEMU" |data | = s->files |data | = AcpiBuildTables.table_data |data | = AcpiBuildTables.linker->cmd_blob
| | | (uint8_t *) | | (uint8_t *) | | (uint8_t *) | | (uint8_t *) |
| | |len | = 4 |len | = size of s->files |len | = sizeof (table_data) |len | = sizeof (cmd_blob)
| | | (uint32_t) | . . . | (uint32_t) | | (uint32_t) | | (uint32_t) |
| | |callback_opaque | = NULL |callback_opaque | = NULL |callback_opaque | = AcpiBuildState |callback_opaque | = AcpiBuildState
| | | (void*) | | (void*) | | (void*) | | (void*) |
| | |select_cb | = NULL |select_cb | = NULL |select_cb | = acpi_build_update |select_cb | = acpi_build_update
| | |write_cb | = NULL |write_cb | = NULL |write_cb | = NULL |write_cb | = NULL
| | +-------------------+ +-----------------+ +------------------+ +------------------+
| |
| | [FW_CFG_SIGNATURE...FW_CFG_FILE_DIR] static key [FW_CFG_FILE_FIRST... ] related to f[]
| |
| |
+------------------------------------------+
|entries[1] | [FW_CFG_FILE_FIRST + file_slots]
| (FWCfgEntry*) |
| +--------------------------------------+
| |data |
| | (uint8_t *) |
| |callback_opaque |
| | (void*) |
| |select_cb |
| |write_cb |
+---+--------------------------------------+
让偶来稍做解释,估计你可以看懂一些:
comb_iomem: 这个就是规范中定义的接口。看这个地址FW_CFG_IO_BASE就是0x510
entries: 这是整个数据的核心。fw_cfg用编号(key)作为关键字访问各种配置。而每个配置都有一个FWCfgEntry数据结构表示,并保存在entries数组上。
files: fw_cfg的配置可以是简单的数据类型,如int, double。也可以是一个文件。所以在entries上可以看到分成了两端。从FW_CFG_FILE_FIRST开始保存的是文件信息。而且都有一个对应的FWCfgFile记录文件信息,并保存在files数组上。
cur_entry/offset: 因为接口简单,在每次访问配置之前先要指定访问的是哪个entry,且每次读写的位移取决于上一次的操作。所以这两个分别保存了当前的entry和偏移。
好了,其实展开就这么点内容了。除了长得丑,别的也没啥了。
相关代码
大的概念讲完了,还是要落到实际代码。
先看看这个高级货在哪里创建的。
pc_memory_init
bochs_bios_init
fw_cfg_init_io_dma
qdev_create(NULL, TYPE_FW_CFG_IO);
qdev_init_nofail(dev);
fw_cfg_io_realize
fw_cfg_common_realize
rom_set_fw();
创建完了之后,分别有两大类添加配置的方式:
fw_cfg_add_bytes()
fw_cfg_add_file_callback()
前者就是添加普通配置的,而后者就是添加带有文件的配置的。
Last updated