coreboot学习5:启动流程跟踪之ramstage阶段主干分析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/subfate/article/details/50908997

 ramstage阶段涉及比较多的操作,比如枚举板子上的外围设备,分配资源(PCI),使能设备。本文根据该阶段的主干函数流程做分析,细节方面不涉及。理顺这个主干,从全局上把控大致流程。

romstage阶段执行完毕,在arch_prog_run函数中,使用jmp指令跳转到ramstge的入口地址。代码如下:

__asm__ volatile (
#ifdef __x86_64__
"jmp  *%%rdi\n"
#else
"jmp  *%%edi\n"
#endif


:: "D"(prog_entry(prog))
);


之后就是ramstage阶段的运行了。主体代码在src\lib\hardwaremain.c中,主函数为main。该文件使用启动状态结构体(struct boot_state)定义了所有要执行的函数。定义如下:

struct boot_state {
	const char *name;
	boot_state_t id;
	u8 post_code;
	struct boot_phase phases[2];
	boot_state_t (*run_state)(void *arg);
	void *arg;
	int complete : 1;
#if CONFIG_HAVE_MONOTONIC_TIMER
	struct boot_state_times times;
#endif
};

#define BS_INIT(state_, run_func_)				\
	{							\
		.name = #state_,				\
		.id = state_,					\
		.post_code = POST_ ## state_,			\
		.phases = { { NULL, 0 }, { NULL, 0 } },		\
		.run_state = run_func_,				\
		.arg = NULL,					\
		.complete = 0,					\
	}
#define BS_INIT_ENTRY(state_, run_func_)	\
	[state_] = BS_INIT(state_, run_func_)

// 此结构体定义ramstage依次执行的函数
// 前一函数结束后会返回下一阶段要执行的函数id
static struct boot_state boot_states[] = {
	BS_INIT_ENTRY(BS_PRE_DEVICE, bs_pre_device),
	BS_INIT_ENTRY(BS_DEV_INIT_CHIPS, bs_dev_init_chips),
	BS_INIT_ENTRY(BS_DEV_ENUMERATE, bs_dev_enumerate),
	BS_INIT_ENTRY(BS_DEV_RESOURCES, bs_dev_resources),
	BS_INIT_ENTRY(BS_DEV_ENABLE, bs_dev_enable),
	BS_INIT_ENTRY(BS_DEV_INIT, bs_dev_init),
	BS_INIT_ENTRY(BS_POST_DEVICE, bs_post_device),
	BS_INIT_ENTRY(BS_OS_RESUME_CHECK, bs_os_resume_check),
	BS_INIT_ENTRY(BS_OS_RESUME, bs_os_resume),
	BS_INIT_ENTRY(BS_WRITE_TABLES, bs_write_tables),
	BS_INIT_ENTRY(BS_PAYLOAD_LOAD, bs_payload_load),
	BS_INIT_ENTRY(BS_PAYLOAD_BOOT, bs_payload_boot),
};

每个函数运行结束后,都会返回下一次要执行的函数ID,这样就可以顺序地执行每个小阶段的函数。其实现是在最关键的函数:bs_walk_state_machine():

static void bs_walk_state_machine(void)
{

	while (1) {
        static int cnt = 1;
        
		struct boot_state *state;
		boot_state_t next_id;

        // 拿到一个state
		state = &boot_states[current_phase.state_id];

		if (state->complete) {
			printk(BIOS_EMERG, "BS: %s state already executed.\n",
			       state->name);
			break;
		}

		if (IS_ENABLED(CONFIG_DEBUG_BOOT_STATE))
			printk(BIOS_DEBUG, "BS: Entering %s state.\n",
				state->name);

		bs_run_timers(0);

		bs_sample_time(state);

		bs_call_callbacks(state, current_phase.seq);
		/* Update the current sequence so that any calls to block the
		 * current state from the run_state() function will place a
		 * block on the correct phase. */
		current_phase.seq = BS_ON_EXIT;

		bs_sample_time(state);


        ll_printk("%s() state %d start==============================\n", __func__, state->id);
		post_code(state->post_code);

        // 真正调用boot_states定义好的函数
        // 函数返回后,得到下一次要执行的id
		next_id = state->run_state(state->arg);

		if (IS_ENABLED(CONFIG_DEBUG_BOOT_STATE))
			printk(BIOS_DEBUG, "BS: Exiting %s state.\n",
			state->name);

		bs_sample_time(state);

		bs_call_callbacks(state, current_phase.seq);

		if (IS_ENABLED(CONFIG_DEBUG_BOOT_STATE))
			printk(BIOS_DEBUG,
				"----------------------------------------\n");

		/* Update the current phase with new state id and sequence. */
		current_phase.state_id = next_id;
		current_phase.seq = BS_ON_ENTRY;

		bs_sample_time(state);

		bs_report_time(state);

		state->complete = 1;

        
	}
}

可以看到,首先从boot_states拿到一个结构体(根据current_phase结构,此时获取到的实际上是第一个要执行的,即BS_PRE_DEVICE的结构体),然后调用该结构的run_state函数指针(比如第一个状态即为bs_pre_device函数),该函数返回的是下一状态ID,赋值给next_id,再更改current_phase中的值。不断的循环,直到结束。——事实上,coreboot最终的状态将会是payload,而payload之后,就是操作系统了,这些不再是coreboot管控范围了。因此,这个函数虽然由while(1)不断循环执行,实质上到payload后即结束了。

关于启动的状态过程,在头文件src\include\bootstate.h的注释讲得十分清楚,摘录如下:

/*
 * The boot state machine provides a mechanism for calls to be made through-
 * out the main boot process. The boot process is separated into discrete
 * states. Upon a state's entry and exit and callbacks can be made. For
 * example:
 *
 *      Enter State
 *           +
 *           |
 *           V
 *   +-----------------+
 *   | Entry callbacks |
 *   +-----------------+
 *   | State Actions   |
 *   +-----------------+
 *   | Exit callbacks  |
 *   +-------+---------+
 *           |
 *           V
 *       Next State
 *
 * Below is the current flow from top to bottom:
 *
 *        start
 *          |
 *    BS_PRE_DEVICE
 *          |
 *    BS_DEV_INIT_CHIPS
 *          |
 *    BS_DEV_ENUMERATE
 *          |
 *    BS_DEV_RESOURCES
 *          |
 *    BS_DEV_ENABLE
 *          |
 *    BS_DEV_INIT
 *          |
 *    BS_POST_DEVICE
 *          |
 *    BS_OS_RESUME_CHECK -------- BS_OS_RESUME
 *          |                          |
 *    BS_WRITE_TABLES              os handoff
 *          |
 *    BS_PAYLOAD_LOAD
 *          |
 *    BS_PAYLOAD_BOOT
 *          |
 *      payload run
 *
 * Brief description of states:
 *   BS_PRE_DEVICE - before any device tree actions take place
 *   BS_DEV_INIT_CHIPS - init all chips in device tree
 *   BS_DEV_ENUMERATE - device tree probing
 *   BS_DEV_RESOURCES - device tree resource allocation and assignment
 *   BS_DEV_ENABLE - device tree enabling/disabling of devices
 *   BS_DEV_INIT - device tree device initialization
 *   BS_POST_DEVICE - all device tree actions performed
 *   BS_OS_RESUME_CHECK - check for OS resume
 *   BS_OS_RESUME - resume to OS
 *   BS_WRITE_TABLES - write coreboot tables
 *   BS_PAYLOAD_LOAD - Load payload into memory
 *   BS_PAYLOAD_BOOT - Boot to payload
 */

typedef enum {
	BS_PRE_DEVICE,
	BS_DEV_INIT_CHIPS,
	BS_DEV_ENUMERATE,
	BS_DEV_RESOURCES,
	BS_DEV_ENABLE,
	BS_DEV_INIT,
	BS_POST_DEVICE,
	BS_OS_RESUME_CHECK,
	BS_OS_RESUME,
	BS_WRITE_TABLES,
	BS_PAYLOAD_LOAD,
	BS_PAYLOAD_BOOT,
} boot_state_t;

总体流程图如下:



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


李迟 2016.3.16 周三 夜

展开阅读全文

c++学习阶段分析

03-28

[align=center]C++学习阶段分析[/align]rn 今天终于看完了给自己列过的c++书单,有一种如释重负的感觉。同时也让我认识到了c++的博大精深。以前用VC编程,写窗体程序以为自己对c++就很熟悉了,现在想想当初的天真真是惭愧。下面我结合自己学习c++的过程,谈谈对c++语法学习的感悟。rn一、 C++广为人知的一半rn面向对象是C++广为人知的一半,但如何学好它,却不是一件容易的事。rn 1、入门阶段rn 抽象,继承,多态是很多刚开始学习c++的人对c++的认识。对于抽象,继承,比较容易了解。而多态,则让很多人认为神秘莫测。我想每一个学习c++的人都会在开始时对c++的多态有这么一种神秘感。rn 看看这个阶段的书籍,找一本市面上讲C++语法的书籍,同时附上C++创始人Bjarne Stroustrup执笔的鸿篇巨制:《The C++ Programming Language》。之所以要从一本容易的C++语法书开始,是为了保持我们的信心。有了一定的基础后,不要一叶障目不见泰山,我们该去看看C++创始人Bjarne Stroustrup执笔的鸿篇巨制:《The C++ Programming Language》。这本书对C++的所有语法进行了系统的介绍,高屋建瓴的介绍了C++语言,这也是为啥不一开始就看这本书原因。牛人的书意境是很深的,要有一定的功底才可以看的懂。好了,看了这本书后,我相信你不会和我再犯同样的错误了:学了一本C++的语法书,懂了抽象、继承,多态还蒙着半层面纱就敢说自己熟悉C++了。因为你知道c++除了抽象,继承,多态这些面向对象的性质之外,还有就是和面向对象相对的泛型编程:C++模板编程。好了,我们暂且不要好高骛远,先把这些基本的搞定再说。rn 2、熟悉阶段rn 我们入门了。如果你想有所作为,那你就不要停下脚步。古语日:“书读百遍,其义自现”。但在程序设计的世界里,书是要读的,但仅仅读书是不行的。我们还需要实践,对,写程序。有了对抽象,继承,多态的认识,我们就可以用面向对象的思想进行编程了。当然了,面向对象的思想不是容易掌握的,我们要在写程序的过程中不断的体会,琢磨。当你写程序到一定的数量的时候,你会发现自己犯过很多错,有一种将这种错误分门别类的想法。恭喜你,你升级了。rn 3、提升阶段rn不烦你将自己犯过的错误分门别类了。因为前人已经进行了总结。这时你就奇怪了,既然有前人总结的经验,你为啥不在我犯错之前告诉我呢。很抱歉,不是我不愿意,因为在你犯错之前如果我禁止你这样,禁止你那样,你会觉得自己无所适从,不知道该如何去写程序了。同时你也不会明白为啥不能那样做。好了,有了犯错的经验,我们可以去看前人总结的犯错宝典了。第一本书: 《effective c++》,前人总结的50条c++编程法则,没编过程序的人不要去看。第二本书:《c++编程思想:第一卷》从思想上指导我们进行c++编程,为我们后期的学习做准备。rn4、揭开C++多态的神秘面纱rn总结了错误的法则,有了编程思想的指导,你是不是想试试你的功底了。是的,我们该检验我们的思想是否到家了。如何办:做项目。好的,那就做吧。当你做项目的时候,你学会了用虚函数,学会了C++的多态,但是你想了解这多态到底是如何实现的,它神秘的面纱后面到底是啥。这个时候,它可以满足你的要求:《深度探索c++对象模型》,它从编译器的角度,讲叙了C++多态的底层机制。当然它还包含其它精彩的内容,是不是等不及了,那就去读它吧。rnrnrn二、C++被人忽视的一半rn也许揭开c++的神秘面纱之后,你会认为自己已经了解了C++的所有语法了。我想在入门阶段读过《The C++ Programming Language》的人,他们很清楚自己现在还只是站在C++圣殿的半山腰上,前面还有更高的意境等待着我们的思考。革命尚未成功,同志仍需努力。rn1、泛型编程入门:rn也许你会说,泛型编程离我太远,我没用到。呵呵,这就是你不知情了吧。要知道,C++中我们使用的很多库,都是由泛型编程来实现的。我们编程用到的IOSTREAM,就是一例。当然了,最有名的要数我们的STL标准模板库了,你要知道C++98标准可是因为它推迟了几年才出台的,要不可能就叫C++94标准了。从这里可以看出C++泛型编程的重要性了吧。好了,下面开始好书推荐:《c++ templates》,绝对是将C++泛型编程的语法讲的最清楚的一本书,不过不适合初学者,但到现在我也没有找到一本更合适的入门书籍,那就从它开始吧。rn2、泛型编程进阶:rn 开始了,我们要走出泛型编程的第一步。是不是我们该动手开始写泛型程序了,且慢,不要着急,我们先看看前辈们的作品。用一下STL标准模板库,没用过别告诉我你用C++写过项目。先推荐几本好书:《c++标准程序库》,模板编程的最成功作品。去看看这本书吧,里面有很多实例,可以边看边写程序。《SGI STL源码剖析》,向专家取经,学习内存管理,算法,数据结构泛型编程的技法。rn 3、泛型编程提高:rn 有了前面的基础,我们在来看看泛型编程的进一步发展。《泛型思想》,一探泛型编程的宏观和微观。《多型与虚拟》,泛型和面向对象的完美结合。rn 三、C++的统一rn 好了,经过上面的两个阶段,我们基本学完了c++的语法。下面我们来看看,通过c++可以实现啥。rn com一个更好的c++。rn 你想进一步提升自己的实力吗,你想成为c++的精通者吗。那就学com吧。也学你认为com过时了,没用了。告诉你,那是浮躁的人说的话。有一句话讲的经典,流行不是用来追的,而是用来等的。还告诉你,windows系列操作系统,com无所不在。微软的技术具有传承型,由VC到.net,他们之间有联系,当然更有进步。由com,dcom到com+,他们是一脉相承的。VC中就不说了。.net框架中其逻辑层就包含有.net中的企业服务(com+)。好了,下面我们看看com的学习过程把。rn1、Com入门:rnCom是一种思想,不是一种编程语言,在这里谈论它是因为我们要用C++将这种思想实现。在实现的过程中,我们可以从二进制级别来研究C++对象在内存中的布局。好书推荐:rn看过《深度探索c++对象模型》的同志,恭喜你,可以直接看有关C++进行com编程的书籍了。否则,回去看过《深度探索c++对象模型》再来。《Inside com》,一本讲叙com基本原理的书,配有丰富的实例,很不错。《Essential COM》以C++为引子,从本质上解析com的实现,迄今为止,将com解析的最透彻的一本书。rn 2、实战com:rn 《深入解析ATL》,将C++泛型编程和面向对象编程结合的典范,简化了我们用C++开发COM的流程。rnrn 经过三个阶段的学习,我们对C++有了充分的了解。下面我们就享受它给我们带来的乐趣。COME ON , ENJOY IT.rnrnrnrn rn附书单:rn《The C++ Programming Language》rn《c++编程思想:第一卷》rn《c++编程思想:第二卷》rn《c++标准程序库》rn《effective c++》rn《more effective c++》rn《STL源码剖析》rn《c++ templates》rn《泛型思想》rn《多型与虚拟》rn《Inside com》rn《Essential COM》rn《深度探索c++对象模型》rn《深入解析ATL》rn《深入浅出MFC》rnrn 论坛

没有更多推荐了,返回首页