当前位置: 首页 > 嵌入式底层BIOS > 正文

coreboot学习7:ramstage阶段之设备枚举流程

本文主要针对ramstage阶段的设备枚举的过程进行分析。限于精力,就直接使用qemu-i440fx作为分析,baytrail就免了吧。在分析时,不一定会根据顺序,也不一定会详细到每个函数。如果要详细的信息,请查阅代码。也建议根据前文给出的主干流程图进行参照分析。
枚举的函数如下:

void dev_enumerate(void)
{
	struct device *root;

	printk(BIOS_INFO, "Enumerating buses...\n");

	root = &dev_root;

	show_all_devs(BIOS_SPEW, "Before device enumeration.");
	printk(BIOS_SPEW, "Compare with tree...\n");
	show_devs_tree(root, BIOS_SPEW, 0, 0);

	// 在enable_dev函数中赋值scan_bus的 比如baytrail和qemu i440fx
	if (root->chip_ops && root->chip_ops->enable_dev)
		root->chip_ops->enable_dev(root);

	if (!root->ops || !root->ops->scan_bus) {
		printk(BIOS_ERR, "dev_root missing scan_bus operation");
		return;
	}
	// 扫描总线 从root开始
	scan_bus(root);
	post_log_clear();
	printk(BIOS_INFO, "done\n");

}

从该函数中看出,主要有3个步骤:一是打印设备树;二是调用chip_ops的使能设备函数enable_dev;最后是调用scan_bus函数扫描总线。
阅读过前文的相信已经知道在i440fx中是没有芯片级别的初始化和使能函数的,为了做试验,在mainboard.c中做了空实现函数。但是,在北桥芯片northbridge.c文件中,同样有chip_operations结构体,同样有使能的函数:

struct chip_operations mainboard_emulation_qemu_i440fx_ops = {
	CHIP_NAME("QEMU Northbridge i440fx")
	.enable_dev = northbridge_enable,
};

northbridge_enable函数如下:

static void northbridge_enable(struct device *dev)
{
    ll_printk("in %s() dev type: %d...\n", __func__, dev->path.type);

	/* Set the operations if it is a special bus type */
	if (dev->path.type == DEVICE_PATH_DOMAIN) {
		dev->ops = &pci_domain_ops;
	}
	else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
		dev->ops = &cpu_bus_ops;
	}
}

其中pci域设备操作函数集结构体定义如下:

static struct device_operations pci_domain_ops = {
	.read_resources		= cpu_pci_domain_read_resources, // 读资源调用此函数
	.set_resources		= cpu_pci_domain_set_resources, // 设置资源调用此函数
	.enable_resources	= NULL,
	.init			= NULL,
	.scan_bus		= pci_domain_scan_bus, // 扫描总线
	.ops_pci_bus	= pci_bus_default_ops,
#if CONFIG_GENERATE_SMBIOS_TABLES
	.get_smbios_data	= qemu_get_smbios_data,
#endif
};

注意,如果要讲pci域,则需要涉及到存储器域、PCI总线域,还有南北桥方面的东西了。那不是当前笔者力之能及的事,建议看看PCI体系结构的书籍。(但谁又能确定未来的笔者不会被领导安排做PCI有关的事务呢?)

另外,cpu设备操作函数集定义如下:

// cpu初始化、总线扫描在这里定义
static struct device_operations cpu_bus_ops = {
	.read_resources   = DEVICE_NOOP,
	.set_resources    = DEVICE_NOOP,
	.enable_resources = DEVICE_NOOP,
	.init             = cpu_bus_init,
	.scan_bus         = cpu_bus_scan,
};

值得注意的是,pci_domain_ops和cpu_bus_ops同是device_operations变量,一个“设备类型”为DEVICE_PATH_DOMAIN,另一个为DEVICE_PATH_CPU_CLUSTER,它们分别对应PCI域和CPU设备,在接下来的文章中将会看到CPU初始化时,就会调用到cpu_bus_init函数。在coreboot中,很多操作实际上是遍历设备树,然后调用对应的device_operations指针,而设备树上不同的设备,使用枚举类型device_path_type来区分。
PCI的扫描比较复杂。总体而言,在扫描时遇到PCI桥时,再递归调用扫描函数。从而完成所有PCI设备的扫描工作。

根据代码整理的流程图如下:
(此处留空)

附上此过程的打印信息:

[LL DEBUG]: in bs_dev_enumerate()...
Enumerating buses...
Show all devs... Before device enumeration.
Root Device: enabled 1
CPU_CLUSTER: 0: enabled 1
APIC: 00: enabled 1
DOMAIN: 0000: enabled 1
PCI: 00:00.0: enabled 1
PCI: 00:01.0: enabled 1
PCI: 00:01.1: enabled 1
PCI: 00:01.3: enabled 1
Compare with tree...
Root Device: enabled 1
 CPU_CLUSTER: 0: enabled 1
  APIC: 00: enabled 1
 DOMAIN: 0000: enabled 1
  PCI: 00:00.0: enabled 1
  PCI: 00:01.0: enabled 1
  PCI: 00:01.1: enabled 1
  PCI: 00:01.3: enabled 1
[LL DEBUG]: in mainboard_i440fx_enable()...
Root Device scanning...
root_dev_scan_bus for Root Device
CPU_CLUSTER: 0 enabled
DOMAIN: 0000 enabled
CPU_CLUSTER: 0 scanning...
QEMU: firmware config interface detected
QEMU: max_cpus is 1
CPU: APIC: 00 enabled
scan_bus: scanning of bus CPU_CLUSTER: 0 took 0 usecs
DOMAIN: 0000 scanning...
PCI: pci_scan_bus for bus 00
POST: 0x24
PCI: 00:00.0 [8086/1237] ops
PCI: 00:00.0 [8086/1237] enabled
PCI: 00:01.0 [8086/7000] bus ops
PCI: 00:01.0 [8086/7000] enabled
PCI: 00:01.1 [8086/7010] ops
PCI: 00:01.1 [8086/7010] enabled
PCI: 00:01.3 [8086/7113] bus ops
PCI: 00:01.3 [8086/7113] enabled
PCI: 00:02.0 [1013/00b8] ops
PCI: 00:02.0 [1013/00b8] enabled
PCI: 00:03.0 [8086/100e] enabled
POST: 0x25
PCI: 00:01.0 scanning...
scan_lpc_bus for PCI: 00:01.0
scan_lpc_bus for PCI: 00:01.0 done
scan_bus: scanning of bus PCI: 00:01.0 took 0 usecs
PCI: 00:01.3 scanning...
scan_smbus for PCI: 00:01.3
scan_smbus for PCI: 00:01.3 done
scan_bus: scanning of bus PCI: 00:01.3 took 0 usecs
POST: 0x55
scan_bus: scanning of bus DOMAIN: 0000 took 0 usecs
root_dev_scan_bus for Root Device done
scan_bus: scanning of bus Root Device took 0 usecs
done

注:
由于coreboot方面资料较少,笔者第一次尝试分析代码,还有众多未能参透的地方,难免出错。任何问题,欢迎一起交流学习。
李迟 2016.4.3 周日 上午

本文固定链接: http://www.latelee.org/firmware-bios/coreboot-note-7-dev-enumerate.html

目前暂无评论

发表评论

*

快捷键:Ctrl+Enter