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

coreboot学习9:ramstage阶段之设备初始化流程

本文对ramstage阶段的设备初始化过程进行跟踪。设备初始化是在dev_initialize函数中完成的,代码如下:

void dev_initialize(void)
{
	struct bus *link;

	printk(BIOS_INFO, "Initializing devices...\n");

#if CONFIG_ARCH_X86
	/* Ensure EBDA is prepared before Option ROMs. */
	setup_default_ebda();
#endif

	/* First call the mainboard init. */
    // 先调用mainboard的init -- 注: 如没有定义,则使用弱链接,参考static.c
	init_dev(&dev_root);


	/* Now initialize everything. */
	for (link = dev_root.link_list; link; link = link->next)
    {
		init_link(link);
       }
    post_log_clear();

	printk(BIOS_INFO, "Devices initialized\n");
	show_all_devs(BIOS_SPEW, "After init.");
}

从该函数看出大概有几个步骤:
1、先调用init_dev初始化根设备dev_root。
2、遍历根设备下的所有设备,调用init_link。
3、最后将所有设备打印出来。
其中,init_dev调用调用具体设备的device_operations结构体指针函数init。当设备有link时,调用init_link函数,该函数再调用init_dev进行初始化,直到所有设备均遍历完毕。如果阅读过编译时生成的static.c文件,就会发现,有的设备link_list成员变量被赋值,有的设备则为NULL。这个文件实际上就是组成了目标板上的设备树。在ramstage阶段很多的操作,实际就是遍历这个设备树,找对应的设备类型,调用对应的操作函数。
下面跟踪一下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,
};

在调用init时,会调用到cpu_bus_init函数。该函数如下:

static void cpu_bus_init(device_t dev)
{
	initialize_cpus(dev->link_list);
}

而initialize_cpus会调用到cpu_initialize。该函数主要是读取CPU信息,如family、model、stepping,然后调用对应的驱动的init函数。文中使用qemu i440fx,因而最终会调用到qemu_cpu_init函数。
代码如下:

void cpu_initialize(unsigned int index)
{
	/* Because we busy wait at the printk spinlock.
	 * It is important to keep the number of printed messages
	 * from secondary cpus to a minimum, when debugging is
	 * disabled.
	 */
	struct device *cpu;
	struct cpu_info *info;
	struct cpuinfo_x86 c;

	info = cpu_info();

	printk(BIOS_INFO, "Initializing CPU #%d\n", index);

	cpu = info->cpu;
	if (!cpu) {
		die("CPU: missing cpu device structure");
	}

	if (cpu->initialized)
		return;

	post_log_path(cpu);

	/* Find what type of cpu we are dealing with */
	identify_cpu(cpu); // 获取cpu信息
	printk(BIOS_DEBUG, "CPU: vendor %s device 0x%x\n",
		cpu_vendor_name(cpu->vendor), cpu->device);

	get_fms(&c, cpu->device); // fms难道是family model stepping的意思?

	/* 打印CPU family、model,例如0x06_0x37表示atom e3000系列(e3800也在其中),参考IA32手册卷3第35章表格1 */
	printk(BIOS_DEBUG, "CPU: family 0x%02x, model 0x%02x, stepping 0x%02x\n",
		c.x86, c.x86_model, c.x86_mask);
    printk(BIOS_DEBUG, "DisplayFamily_DisplayModel: %02X_%02XH\n", c.x86, c.x86_model);
    // test
    msr_t platform_id = rdmsr(0x17);
    printk(BIOS_DEBUG, "platform_id: %x %x\n", platform_id.hi, platform_id.lo);

    // my test...
	char processor_name[49];
	/* Print processor name */
	fill_processor_name1(processor_name);
	// 打印CPU,如qemu会打印:QEMU Virtual CPU version 2.0.0
	printk(BIOS_INFO, "LLDEBUG CPU: %s.\n", processor_name);

	/* Lookup the cpu's operations */
	set_cpu_ops(cpu);

	if(!cpu->ops) {
		/* mask out the stepping and try again */
		cpu->device -= c.x86_mask;
		set_cpu_ops(cpu); // 设置操作函数
		cpu->device += c.x86_mask;
		if(!cpu->ops) die("Unknown cpu");
		printk(BIOS_DEBUG, "Using generic cpu ops (good)\n");
	}


	/* Initialize the cpu */
	if (cpu->ops && cpu->ops->init) {
		cpu->enabled = 1;
		cpu->initialized = 1; // 已经初始化好了
		cpu->ops->init(cpu); // 调用具体的init函数 如baytrail的为baytrail_init_cpus, qemu为qemu_cpu_init
	}
	post_log_clear();

	printk(BIOS_INFO, "CPU #%d initialized\n", index);
	return;
}

在前面学习CPUID指令时,实际上就是在这个函数中做试验的。

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

附上此过程的打印信息:

[LL DEBUG]: in bs_dev_init()...
Initializing devices...
Root Device init ...
POST: 0x75
CPU_CLUSTER: 0 init ...
Initializing CPU #0
CPU: vendor Intel device 0x663
CPU: family 0x06, model 0x06, stepping 0x03
DisplayFamily_DisplayModel: 06_06H
platform_id: 0 0
LLDEBUG CPU: QEMU Virtual CPU version 2.0.0.
Setting up local apic... apic_id: 0x00 done.
POST: 0x9b
CPU #0 initialized
POST: 0x75
POST: 0x75
POST: 0x75
PCI: 00:00.0 init ...
Assigning IRQ 10 to 0:1.3
Assigning IRQ 11 to 0:3.0
POST: 0x75
PCI: 00:01.0 init ...
RTC Init
POST: 0x75
PCI: 00:01.1 init ...
IDE: Primary IDE interface: on
IDE: Secondary IDE interface: on
IDE: Access to legacy IDE ports: off
POST: 0x75
POST: 0x75
PCI: 00:02.0 init ...
POST: 0x75
PCI: 00:03.0 init ...
Devices initialized
Show all devs... After init.
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
PCI: 00:02.0: enabled 1
PCI: 00:03.0: enabled 1

李迟 2016.4.4 周一 清明节

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

目前暂无评论

发表评论

*

快捷键:Ctrl+Enter