coreboot学习4:启动流程跟踪之romstage阶段

romstage是coreboot的第二个执行阶段。本文分别介绍基于qemu模拟环境的x86的跟踪,以及基于Intel baytrail平台的跟踪。
在romstage阶段,由于内存还未初始化好,所以使用cache作为内存,此项技术称为“cache as ram”,简称为“CAR”。网络上有较多文章涉及此方面,可以查阅以了解更多。

一、qemu-i440fx

cache_as_ram文件:src\mainboard\emulation\qemu-i440fx\cache_as_ram.inc

1、保存BIST

BIST值会作为romstage主函数的参数。

1
2
/* Save the BIST result. */
movl %eax, %ebp

2、设置CAR

(注:这段代码还不是太理解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cache_as_ram:
post_code(0x20)
/* Clear the cache memory region. This will also fill up the cache */
movl $CACHE_AS_RAM_BASE, %esi
movl %esi, %edi
movl $(CACHE_AS_RAM_SIZE >> 2), %ecx
// movl $0x23322332, %eax
xorl %eax, %eax
/* 使用 EAX 填写位于 ESI:EDI 的 ECX 个双字 */
/* 将CACHE_AS_RAM_BASE地址的大小为CACHE_AS_RAM_SIZE区域初始化为0 */
rep stosl

post_code(0x21)
/* Set up the stack pointer. */
movl $(CACHE_AS_RAM_SIZE + CACHE_AS_RAM_BASE - 4), %eax
movl %eax, %esp

3、恢复BIST值

1
2
3
4
5
6
/* Restore the BIST result. */
movl %ebp, %eax
movl %esp, %ebp
/* eax为BIST值,将其压栈,作为main的参数,然后调用main函数 */
pushl %eax
/*测试 pushl $0xdeadbeaf*/

4、调用romstage主函数

上段代码恢复BIST值到eax寄存器后,即将eax压入栈中,接着调用main函数,这个函数在romstage.c文件中定义。

1
2
3
4
5
before_romstage:
post_code(0x29)
/* 跳转到romstage的主函数 */
/* Call romstage.c main function. */
call main

5、跳转到ramstage阶段

在main函数返回后,调用copy_and_run函数,之后就到了ramstage阶段了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 /* 调用完main后,就到了copy_and_run,即ramstage阶段了 */
__main:
post_code(POST_PREPARE_RAMSTAGE)
cld /* Clear direction flag. */

movl $CONFIG_RAMTOP, %esp
movl %esp, %ebp
/* 此处为调试用
movl $9, %eax
pushl %eax
*/
/* 调用copy_and_run */
call copy_and_run

.Lhlt:
post_code(POST_DEAD_CODE)
hlt
jmp .Lhlt

至此,分析结束。

下面看看romstage的主函数。main函数 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// bist为blockboot传递的参数,intel在启动时会进行自检,正常情况下bist为0
// 在cache_as_ram.inc中会调用到此处的main
void main(unsigned long bist)
{
int cbmem_was_initted;

/* init_timer(); */
post_code(0x05);

console_init();

ll_printk("qemu-i440fx romstage --BIST: 0x%x\n", (unsigned int)bist);
/* Halt if there was a built in self test failure */
report_bist_failure(bist);

//print_pci_devices();
//dump_pci_devices();

cbmem_was_initted = !cbmem_recovery(0);

timestamp_init(timestamp_get());
timestamp_add_now(TS_START_ROMSTAGE);

}

很简单,调用console_init函数初始化终端,在该函数中会打印coreboot的版本号以及编译时间。如果传入的参数的bist值不为0,则出错,直接挂机。

注:ll_printk为代码使用的打印函数,本文中使用bist值(即cache_as_ram.inc的eax寄存器)以跟踪执行流程。
流程图示如下: romstage流程

二、baytrail-fsp

(李迟按:留空待写)

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

李迟 2016.3.15 周二 夜