[置顶] 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。。。。     




原文地址:https://www.cnblogs.com/javawebsoa/p/2992150.html