嵌入式学习笔记---uboot(4)

总结于朱有鹏老师的嵌入式课程,感谢朱老师

文章目录

  • start.S
    • 头文件
    • 内容1
      • lowlevel_init.S
    • 内容2

start.S

uboot中因为有汇编阶段参与,因此不能直接找main.c。整个程序的入口取决于链接脚本中ENTRY声明的地方。ENTRY(_start)因此_start符号所在的文件就是整个程序的起始文件

头文件

#include                  //里面是#include 包括配置文件的宏
#include                 //包含了include/version_autogenerated.h,版本号信息
#if defined(CONFIG_ENABLE_MMU)
#include          //里面是include/asm-arm/proc-armv/domain.h
#endif
#include 

内容1

提前占位16字节保证正式的image的头部确实有16字节,SD卡启动/Nand启动等整个镜像开头需要16字节的校验头。

#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
	.word 0x2000                     //.word相当于c中的int
	.word 0x0
	.word 0x0
	.word 0x0
#endif

异常向量表

.globl _start
_start: b	reset                        //异常声明
	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 */
.global _end_vect
_end_vect:

	.balignl 16,0xdeadbeef          //当前地址对齐排布如果不对齐则自动向后走,向后走的那些内存要用0xdeadbeef来填充
	//对齐访问有时候是效率的要求,有时候是硬件的特殊要求。

其中复位异常处的代码

reset:
	/*
	 * set the cpu to SVC32 mode and IRQ & FIQ disable
	 */
	@;mrs	r0,cpsr
	@;bic	r0,r0,#0x1f
	@;orr	r0,r0,#0xd3
	@;msr	cpsr,r0
	msr	cpsr_c, #0xd3		@ 将CPU设置为禁止FIQ IRQ,ARM状态,SVC模式。
_TEXT_BASE:
	.word	TEXT_BASE          //Makefile时配置阶段的TEXT_BASE,是我们链接时指定的uboot的链接地址。(值就是c3e00000)
_TEXT_PHY_BASE:
	.word	CFG_PHY_UBOOT_BASE  //33e00000	uboot在DDR中的物理地址

如果用中断进行处理

#if defined(CONFIG_USE_IRQ)
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
	.word	0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
	.word 0x0badc0de
#endif
	bl	disable_l2cache                // 禁止L2 cache
	bl	set_l2cache_auxctrl_cycle      // l2 cache相关初始化
    bl	enable_l2cache                 // 使能l2 cache

刷新L1 cache的icache和dcache。

       /*
        * Invalidate L1 I/D
        */
        mov	r0, #0                  @ set up for MCR
        mcr	p15, 0, r0, c8, c7, 0   @ invalidate TLBs
        mcr	p15, 0, r0, c7, c5, 0   @ invalidate icache

关闭MMU

/*
        * disable MMU stuff and caches
        */
        mrc	p15, 0, r0, c1, c0, 0
        bic	r0, r0, #0x00002000     @ clear bits 13 (--V-)
        bic	r0, r0, #0x00000007     @ clear bits 2:0 (-CAM)
        orr	r0, r0, #0x00000002     @ set bit 1 (--A-) Align
        orr	r0, r0, #0x00000800     @ set bit 12 (Z---) BTB
        mcr 	p15, 0, r0, c1, c0, 0

识别并暂存启动介质选择,启动是由SoC的OM5:OM0这6个引脚的高低电平决定的

        /* Read booting information */
        ldr	r0, =PRO_ID_BASE
        ldr	r1, [r0,#OMR_OFFSET]
        bic	r2, r1, #0xffffffc1

/* NAND BOOT */
	cmp	r2, #0x0		@ 512B 4-cycle
	moveq	r3, #BOOT_NAND

	cmp	r2, #0x2		@ 2KB 5-cycle
	moveq	r3, #BOOT_NAND

	cmp	r2, #0x4		@ 4KB 5-cycle	8-bit ECC
	moveq	r3, #BOOT_NAND

	cmp	r2, #0x6		@ 4KB 5-cycle	16-bit ECC
	moveq	r3, #BOOT_NAND

	cmp	r2, #0x8		@ OneNAND Mux
	moveq	r3, #BOOT_ONENAND

	/* SD/MMC BOOT */
	cmp     r2, #0xc
	moveq   r3, #BOOT_MMCSD	//r3中赋值#BOOT_MMCSD(0x03)以后备用

	/* NOR BOOT */
	cmp     r2, #0x14
	moveq   r3, #BOOT_NOR	
	/* Uart BOOTONG failed */
	cmp     r2, #(0x1<<4)
	moveq   r3, #BOOT_SEC_DEV
	
	ldr	r0, =INF_REG_BASE
	str	r3, [r0, #INF_REG3_OFFSET]     //将#BOOT_MMCSD写入了INF_REG3寄存器中存储

	ldr	sp, =0xd0036000 /* end of sram dedicated to u-boot */                     
	sub	sp, sp, #12	/* set stack设置栈 */
	mov	fp, #0
	bl	lowlevel_init	/* go setup pll,mux,memory底层初始化 */

lowlevel_init.S

检查复位状态,直接冷上电、热启动、睡眠(低功耗)状态下的唤醒这些情况都属于复位

	ldr	r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
	ldr	r1, [r0]
	bic	r1, r1, #0xfff6ffff
	cmp	r1, #0x10000
	beq	wakeup_reset_pre
	cmp	r1, #0x80000
	beq	wakeup_reset_from_didle

IO状态恢复

	ldr	r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)
	ldr	r1, [r0]
	ldr	r2, =IO_RET_REL
	orr	r1, r1, r2
	str	r1, [r0]

关看门狗

	ldr	r0, =ELFIN_WATCHDOG_BASE	/* 0xE2700000 */
	mov	r1, #0
	str	r1, [r0]

供电锁存

	ldr	r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
	ldr	r1, [r0]
	orr	r1, r1, #0x300	
	orr	r1, r1, #0x1	
	str	r1, [r0]

判断当前代码执行位置,是否重定位

	ldr	r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
	ldr	r1, [r0]
	orr	r1, r1, #0x300	
	orr	r1, r1, #0x1	
	str	r1, [r0]

判定当前代码执行的位置在SRAM中还是在DDR中

	ldr	r0, =0xff000fff
	bic	r1, pc, r0		/* r0 <- current base addr of code */
	ldr	r2, _TEXT_BASE		/* r1 <- original base addr in ram */
	bic	r2, r2, r0		/* r0 <- current base addr of code */
	cmp     r1, r2        //相等则在DDR中
	beq     1f			/* r0 == r1 then skip sdram init   */
//如果当前代码是在SRAM中,说明冷启动,那么时钟和DDR都需要初始化.否则跳过
	/* init system clock */
	bl system_clock_init       //初始化时钟

	/* Memory initialize */
	bl mem_ctrl_asm_init       //初始化内存
	
1:                         //相等跳到这里
	/* for UART */
	bl uart_asm_init       //初始化串口

	bl tzpc_init           //

内容2

再次供电锁存,但其实前面已经执行过了,这里可能是保险

    ldr	r0, =0xE010E81C  /* PS_HOLD_CONTROL register */
	ldr	r1, =0x00005301	 /* PS_HOLD output high	*/
	str	r1, [r0]

因为上一次设置栈DDR尚未初始化,因此程序执行都是在SRAM中,所以在SRAM中分配了一部分内存作为栈。本次因为DDR已经被初始化了,因此要把栈挪移到DDR中,所以要重新设置栈,这是第二次设置

    ldr	sp, _TEXT_PHY_BASE	/* setup temp stack pointer */
	sub	sp, sp, #12
	mov	fp, #0			/* no previous frame, so fp=0 */

再次用相同的代码判断运行地址是在SRAM中还是DDR中,这次判断是为了决定是否进行uboot的relocate。

	ldr	r0, =0xff000fff
	bic	r1, pc, r0		/* r0 <- current base addr of code */
	ldr	r2, _TEXT_BASE		/* r1 <- original base addr in ram */
	bic	r2, r2, r0		/* r0 <- current base addr of code */
	cmp     r1, r2                  /* compare r0, r1                  */
	beq     after_copy		/* r0 == r1 then skip flash copy   */

D0037488这个内存地址在SRAM中,这个地址中的值是被硬件自动设置的。硬件根据我们实际电路中SD卡在哪个通道中,会将这个地址中的值设置为相应的数字。

#if defined(CONFIG_EVT1)
	/* If BL1 was copied from SD/MMC CH2 */
	ldr	r0, =0xD0037488
	ldr	r1, [r0]
	ldr	r2, =0xEB200000
	cmp	r1, r2
	beq     mmcsd_boot
#endif

INF_REG3寄存器中的#BOOT_MMCSD和#BOOT_MMCSD去比较确定是从MMCSD启动

ldr	r0, =INF_REG_BASE
	ldr	r1, [r0, #INF_REG3_OFFSET]
	cmp	r1, #BOOT_NAND		/* 0x0 => boot device is nand */
	beq	nand_boot
	cmp	r1, #BOOT_ONENAND	/* 0x1 => boot device is onenand */
	beq	onenand_boot
	cmp     r1, #BOOT_MMCSD
	beq     mmcsd_boot
	cmp     r1, #BOOT_NOR
	beq     nor_boot
	cmp     r1, #BOOT_SEC_DEV
	beq     mmcsd_boot

你可能感兴趣的:(嵌入式)