[置顶] 0K6410学习之初学Uboot_stage1

今天喝的水真多,如我所言,已经有3天没有看空间了,表现不错。确实,空间里面似乎没有什么值得我关注的了,呵呵。恩,刚刚粗略的将u-boot-2010.03的里面arm11的源代码看了一下,我用的是ARM11的板子,里面有一些是参考了arm9的分析资料,分析完后还是觉得有必要总结一下的,以防自己忘记,好的,说正题,stag1。

声明:里面有些东西可能是我误解了,仅供参考,欢迎大家一起交流。

一、          打开cpu/arm1176/start.S,这个文件是系统上电后执行的第一个代码,但是不是编译器执行的第一个代码,原因相信都明白。从START.S开始看,头文件,这个没什么好说的了,接着往下就是:

 

.globl _start							

_start:	b       reset


 

.globl定义一个全局变量,可以被其他文档引用。这个是整个uboot程序的入口,可在链接脚本board/s3c2410/u-boot.lds中找到,链接脚本中定义了这个程序的入口地址,这条指令的意思就是板子一上来就复位啦~~~

二、          该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~0x0000 0020,刚好8条指令

 

#ifndef CONFIG_NAND_SPL

	ldr	pc, _undefined_instruction

	ldr	pc, _software_interrupt

	ldr	pc, _prefetch_abort

	ldr	pc, _data_abort

	ldr	pc, _not_used

	ldr	pc, _irq

	ldr	pc, _fiq



_undefined_instruction:

	.word undefined_instruction

_software_interrupt:

	.word software_interrupt

_prefetch_abort:

	.word prefetch_abort

_data_abort:

	.word data_abort

_not_used:

	.word not_used

_irq:

	.word irq

_fiq:

	.word fiq

_pad:

	.word 0x12345678 /* now 16*4=64 */

#else

	. = _start + 64

#endif



.global _end_vect

_end_vect:

	.balignl 16,0xdeadbeef


 

其中.word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并用异常进行初始化。.long.int原理一样。.balign伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。.balign详细用法百度一下。

如果系统出现中断异常就会执行下列代码,代码还是位于start.s

 

/*

 * exception handlers

 */

	.align  5

undefined_instruction:

	get_bad_stack

	bad_save_user_regs

	bl 	do_undefined_instruction



	.align	5

software_interrupt:

	get_bad_stack

	bad_save_user_regs

	bl 	do_software_interrupt



	.align	5

prefetch_abort:

	get_bad_stack

	bad_save_user_regs

	bl 	do_prefetch_abort



	.align	5

data_abort:

	get_bad_stack

	bad_save_user_regs

	bl 	do_data_abort



	.align	5

not_used:

	get_bad_stack

	bad_save_user_regs

	bl 	do_not_used



#ifdef CONFIG_USE_IRQ



	.align	5

irq:

	get_irq_stack

	irq_save_user_regs

	bl 	do_irq

	irq_restore_user_regs



	.align	5

fiq:

	get_fiq_stack

	/* someone ought to write a more effiction fiq_save_user_regs */

	irq_save_user_regs

	bl 	do_fiq

	irq_restore_user_regs



#else



	.align	5

irq:

	get_bad_stack

	bad_save_user_regs

	bl 	do_irq



	.align	5

fiq:

	get_bad_stack

	bad_save_user_regs

	bl 	do_fiq



#endif

 

三、          接下来就是一些变量的声明,初始化。

 

1、TEXT_BASE在研发板相关的目录中的config.mk文档中定义, 他定义了代码在运行时所在的地址, 同时_TEXT_BASE中保存了这个地址。

_TEXT_BASE: 

.word TEXT_BASE 


2、下面代码声明_armboot_start并用_start 来进行初始化,在board/u-boot.lds中定义。

.globl _armboot_start 

_armboot_start: 

.word _start  


3、

1、以下代码声明_bss_start并用__bss_start来初始化,其中__bss_start定义在和板相关的u-boot.lds中,_bss_start中

1、_bss_start保存的是__bss_start这个标号所在的地址, 这里涉及到当前代码所在的地址不是编译时的地址的情况, 这里直接取得该标号对应的地址, 不受编译时

地址的影响.

 

.globl _bss_start 

_bss_start: 

.globl _bss_start 

_bss_start: 

.word __bss_start 


 

3_bss_end也是同样的道理.

.word __bss_start 

.	globl _bss_end 

_	bss_end: 

.word _end


1、OK,看复位函数,不,应该叫复位代码吧!

/*

 * the actual reset code

 */

reset:

	/*

	 * set the cpu to SVC32 mode

	 */

	mrs	r0, cpsr

	bic	r0, r0, #0x3f

	orr	r0, r0, #0xd3

	msr	cpsr, r0


/*  首先将cpu设置为我们熟悉的管理模式(通过设置cpsr的低5位为10011实现)。同时禁止IRQ、FIQ。即cpsr的第七第六位设置为11,这个在我之前的中断那一博文上面就有说明的。

1、关闭Cache和MMU,为什么?据说:如果只按复位键,而不关掉板子重新上电,就会造成cache中可能残留之前对cache操作的数据。我们称之为“脏数据”,它会映像我们的调试结果,造成假象。(有机会试试)

当然,在这里无效cache和MMU肯定还有别的原因。比如在初始化阶段,

可以认为我们只有一个任务在跑,没有必要,也不允许使用地址变换。因此最好应该无效掉MMU。(参考ARM79的说法)

#ifndef CONFIG_NAND_SPL

	/*

	 * flush v4 I/D caches

	 */

	mov	r0, #0

	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */

	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */



	/*

	 * disable MMU stuff and caches

	 */

	mrc	p15, 0, r0, c1, c0, 0

	bic	r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)

	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)

	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align

	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache

	/* Prepare to disable the MMU */

#if 0

	adr	r1, mmu_disable_phys

	/* We presume we're within the first 1024 bytes */

	and	r1, r1, #0x3fc

	ldr	r2, _TEXT_PHY_BASE

	ldr	r3, =0xfff00000

	and	r2, r2, r3

	orr	r2, r2, r1

	b	mmu_disable



	.align 5

	/* Run in a single cache-line */

mmu_disable:

	mcr	p15, 0, r0, c1, c0, 0

	nop

	nop

	mov	pc, r2

#endif

#endif


1、调用lowlevel_init底层初始化函数。初始化PLL,初始化mux,memory关闭看门狗。(应该对照芯片手册仔细分析的)。

 

2、复制完代码后,就使能MMU

#ifdef CONFIG_ENABLE_MMU

enable_mmu:

	/* enable domain access */

	ldr	r5, =0x0000ffff

	mcr	p15, 0, r5, c3, c0, 0	/* load domain access register */



	/* Set the TTB register */

	ldr	r0, _mmu_table_base

	ldr	r1, =CONFIG_SYS_PHY_UBOOT_BASE

	ldr	r2, =0xfff00000

	bic	r0, r0, r2

	orr	r1, r0, r1

	mcr	p15, 0, r1, c2, c0, 0



	/* Enable the MMU */

	mrc	p15, 0, r0, c1, c0, 0

	orr	r0, r0, #1		/* Set CR_M to enable MMU */



	/* Prepare to enable the MMU */

	adr	r1, skip_hw_init

	and	r1, r1, #0x3fc

	ldr	r2, _TEXT_BASE

	ldr	r3, =0xfff00000

	and	r2, r2, r3

	orr	r2, r2, r1

	b	mmu_enable



	.align 5

	/* Run in a single cache-line */

mmu_enable:



	mcr	p15, 0, r0, c1, c0, 0

	nop

	nop

	mov	pc, r2

#endif


1、清除堆,设置栈,为什么?调用C函数。

skip_hw_init:

	/* Set up the stack*/

stack_setup:

	ldr	r0, =CONFIG_SYS_UBOOT_BASE	/* base of copy in DRAM	*/

	sub	r0, r0, #CONFIG_SYS_MALLOC_LEN	/* malloc area*/

	sub	r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo*/

	sub	sp, r0, #12		/* leave 3 words for abort-stack*/

clear_bss:

	ldr	r0, _bss_start		/* find start of bss segment*/

	ldr	r1, _bss_end		/* stop here*/

	mov 	r2, #0			/* clear*/

clbss_l:

	str	r2, [r0]		/* clear loop... */

	add	r0, r0, #4

	cmp	r0, r1

	ble	clbss_l


1、CPU初始化完毕之后,能看到这么一段代码。

#ifndef CONFIG_NAND_SPL

	ldr	pc, _start_armboot



_start_armboot:

	.word start_armboot

#else

	b	nand_boot

/*	.word nand_boot*/

#endif



#ifdef CONFIG_ENABLE_MMU

_mmu_table_base:

	.word mmu_table

#endif



#ifndef CONFIG_NAND_SPL 


显然,我们这里并没有复制代码,所以直接进入到C函数,_start_armboot。

调用第一个C函数啦,开始进入c的世界,uboot启动stage 2!

跳转到start_armboot函数入口,_start_armboot字保存函数入口指针

start_armboot函数在lib_arm/board.c中实现

 

总结完stage1,就差不多要睡觉了。待续stage2。。。。     

 




你可能感兴趣的:(Boot)