coreboot学习3:启动流程跟踪之bootblock阶段

coreboot的第一个启动阶段为bootblock。该阶段均使用汇编语言编写。下面根据执行文件顺序介绍。

一、reset16.inc

bootlbock的最开始执行的文件为src\cpu\x86\16bit\reset16.inc。该文件十分简单,如下:

	.section ".reset", "ax", %progbits
	.code16
.globl	_start
_start:
	.byte  0xe9
	.int   _start16bit - ( . + 2 )
	/* Note: The above jump is hand coded to work around bugs in binutils.
	 * 5 byte are used for a 3 byte instruction.  This works because x86
	 * is little endian and allows us to use supported 32bit relocations
	 * instead of the weird 16 bit relocations that binutils does not
	 * handle consistenly between versions because they are used so rarely.
	 */
	.previous
里面的_start16bit在entry16.inc中定义。

二、 entry16.inc

从文件src\cpu\x86\16bit\ entry16.inc名称上看出,该文件为16位的汇编代码,主要做一些初始工作,接着便进入到保护模式。

下面语句定义其为16位代码段。

.code16
.globl _start16bit
.type _start16bit, @function

1、关中断:

_start16bit:
	/* 关中断 */
	cli
2、保存BIST的值

	/* Save the BIST result */
	/* 保存eax的BIST(Built-In Self-Test)的值,上电或复位后,eax值为0表示所有的测试通过,参见intel开发文档3A 9.1.2 */
	movl	%eax, %ebp
3、将cr3清零

	/* cr3清零,使TLB无效(cache无效) — CR3:页目录基址的物理地址和PCD和PWT标志位(和CACHE有关) */
	xorl	%eax, %eax
	movl	%eax, %cr3    /* Invalidate TLB*/
4、
	movw	%cs, %ax
	shlw	$4, %ax
	movw	$nullidt_offset, %bx
	subw	%ax, %bx
	lidt	%cs:(%bx)
	movw	$gdtptr16_offset, %bx
	subw	%ax, %bx
	lgdtl	%cs:(%bx)
5、进入保护模式

主要是设置cr0寄存器,其中PE为1表示保护模式。

	/* 进入保护模式 PE为1 */
	movl	%cr0, %eax
	andl	$0x7FFAFFD1, %eax /* PG,AM,WP,NE,TS,EM,MP = 0 */
	orl	$0x60000001, %eax /* CD, NW, PE = 1 */
	movl	%eax, %cr0
6、恢复BIST值到eax寄存器

	/* 重新赋值BIST到eax */
	/* 测试用的 -- movl $0xab, %eax*/
	/* Restore BIST to %eax */
	movl	%ebp, %eax
7、跳转到保护模式

	/* Now that we are in protected mode jump to a 32 bit code segment. */
	ljmpl	$ROM_CODE_SEG, $__protected_start
之后便到entry32.inc文件。

三、entry32.inc

文件:src\cpu\x86\16bit\ entry32.inc。开始处的.code32定义其为32位代码段。

1、GDT表相关定义
GDT表中有三个表项:
第一个是GDT表项的基地址和大小作为limit。
第二个是基地址为0x00000000段界限为4GB的代码段。
第三个是与第二个相同地址的数据段。

	/* This is the GDT for the ROM stage part of coreboot. It
	 * is different from the RAM stage GDT which is defined in
	 * c_start.S
	 */

	.align	4
.globl gdtptr
gdt:
gdtptr:
	.word	gdt_end - gdt -1 /* compute the table limit */
	.long	gdt		 /* we know the offset */
	.word	0

	/* selgdt 0x08, flat code segment */
	.word	0xffff, 0x0000
	.byte	0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, So we get 4Gbytes for limit */

	/* selgdt 0x10,flat data segment */
	.word	0xffff, 0x0000
	.byte	0x00, 0x93, 0xcf, 0x00

	/* selgdt 0x18, flat code segment (64-bit) */
	.word   0xffff, 0x0000
	.byte   0x00, 0x9b, 0xaf, 0x00

gdt_end:
2、保存BIST值

	lgdt	%cs:gdtptr
	ljmp	$ROM_CODE_SEG, $__protected_start

__protected_start:
	/* Save the BIST value */
	movl	%eax, %ebp
3、把除了CS以外的数据段全部加载到第三个GDT表项上。

	movw	$ROM_DATA_SEG, %ax
	movw	%ax, %ds
	movw	%ax, %es
	movw	%ax, %ss
	movw	%ax, %fs
	movw	%ax, %gs
4、恢复BIST值

	/* Restore the BIST value to %eax */
	/* 恢复BIST值到eax,以qemu x86为例,在cache as ram阶段,会保存此值,而最后romstage入口函数参数即为BIST */
	/* 测试用的 -- movl $0xaa, %eax */
	movl	%ebp, %eax

以上是简单的代码注释。其中BIST贯穿着整个阶段,它是romstage入口函数的参数。BIST为英文“Built-In Self-Test”简称,在CPU上电或复位后,如果eax的值为0,则表示测试通过,参考intel软件开发人员文档3A 9.1.2。关于GDT表相关知识,可以参阅于渊编写的《Orange'S:一个操作系统的实现》。

另外:

在代码分析时,使用临时值赋给eax寄存器,作为跟踪的一个手段。

对于coreboot代码编译生成还未十分掌握、理解。

本文未对跳转到下一阶段romstage做分析。


注:

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

参考资料:

Intel 64 and IA-32 Architectures Software Developer’s Manual手册下载地址:
http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

coreboot仓库:https://github.com/coreboot/coreboot

http://blog.csdn.net/shuanghuo9/article/details/6574261

Orange'S:一个操作系统的实现:https://book.douban.com/subject/3735649/


李迟 2016.3.14 周一 晚

你可能感兴趣的:(微机/硬件底层/BIOS)