zoukankan      html  css  js  c++  java
  • [置顶] 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。。。。     




  • 相关阅读:
    最小生成树的解法
    51nod 1212 无向图最小生成树
    greater()和less()的使用
    51nod1183 编辑距离
    51nod 1181 质数中的质数(质数筛法)
    upper_bound和lower_bound的用法
    线段树最全模板
    bryce1010专题训练——线段树习题汇总
    51nod 1174 区间中最大的数
    51nod 1113 矩阵快速幂
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2992150.html
Copyright © 2011-2022 走看看