亚马逊网站联盟十个有创意的线上活动
1、初始Bootloader
Bootloader是启动计算机或嵌入式系统时执行的第一个程序,它主要负责初始化系统硬件,加载操作系统。U-Boot也是Bootloader的一种。它的作用如下:
(1)初始化硬件
(2)部署操作系统
(3)启动操作系统
(4)提供启动选项
(5)提供固件升级机制
2、U-Boot源码目录
目录名 | 作用 |
api | |
board | 开发板的相关定义和结构 |
common | 包含U-Boot用到的各种处理函数 |
cpu | 各种不同类型的处理器相关的代码 |
doc | U-Boot相关文档 |
drivers | 常用外部设备的驱动 |
fs | 文件系统(cramfs、ext2、fat、fdos、jffs2、reserfs) |
include | U-Boot用到的头文件 |
lib_arm | ARM体系结构有关的数据定义和操作 |
lib_generic | U-Boot通用的操作函数 |
libfdt | 设备树相关的 |
net | 常用的网络协议,包括:bootp、rarp、arp、tftp |
post | 上电自检相关 |
tools | 工具类相关的 |
3、U-Boot启动的第一阶段
U-Boot的工作流程分成stage1和stage2两个阶段。
3.1 头部16字节
SD卡/Nand等方式启动需要16字节的校验头,USB启动就不需要16字节的校验头,这里是先留出16字节的大小,用于后面计算校验时填充。
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED).word 0x2000.word 0x0.word 0x0.word 0x0
#endif
3.2 设置异常向量表
.globl _start
_start: b resetldr pc, _undefined_instructionldr pc, _software_interruptldr pc, _prefetch_abortldr pc, _data_abortldr pc, _not_usedldr pc, _irqldr 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 */
异常复位时跳转到reset
3.3 地址对齐
以当前地址开始,以16字节对齐
.global _end_vect
_end_vect:.balignl 16,0xdeadbeef
.balignl {alignment} {,fill} {,max}。;alignment为正整数,以alignment整数倍地址进行对齐,以当前地址为起始地址,进行字节填充,用fill进行填充
3.4 两个地址
/* 定义在Makefile,是uboot链接时的链接地址 */
_TEXT_BASE:.word TEXT_BASE/* uboot在DDR的物理地址 */
_TEXT_PHY_BASE:.word CFG_PHY_UBOOT_BASE
3.5 cpu设置为SVC模式
reset:/** set the cpu to SVC32 mode and IRQ & FIQ disable*/@;mrs r0,cpsr@;bic r0,r0,#0x1f@;orr r0,r0,#0xd3@;msr cpsr,r0msr cpsr_c, #0xd3 @ I & F disable, Mode: 0x13 - SVC
3.6 cpu_init_crit
(1)设置L1Cache、L2Cache、MMU
#ifndef CONFIG_EVT1
#if 0 bl v7_flush_dcache_all
#elsebl disable_l2cachemov r0, #0x0 @ mov r1, #0x0 @ i mov r3, #0x0mov r4, #0x0
lp1:mov r2, #0x0 @ j
lp2: mov r3, r1, LSL #29 @ r3 = r1(i) <<29mov r4, r2, LSL #6 @ r4 = r2(j) <<6orr r4, r4, #0x2 @ r3 = (i<<29)|(j<<6)|(1<<1)orr r3, r3, r4mov r0, r3 @ r0 = r3bl CoInvalidateDCacheIndexadd r2, #0x1 @ r2(j)++cmp r2, #1024 @ r2 < 1024bne lp2 @ jump to lp2add r1, #0x1 @ r1(i)++cmp r1, #8 @ r1(i) < 8bne lp1 @ jump to lp1bl set_l2cache_auxctrlbl enable_l2cache
#endif
#endifbl disable_l2cachebl set_l2cache_auxctrl_cyclebl enable_l2cache/** Invalidate L1 I/D*/mov r0, #0 @ set up for MCRmcr p15, 0, r0, c8, c7, 0 @ invalidate TLBsmcr p15, 0, r0, c7, c5, 0 @ invalidate icache/** disable MMU stuff and caches*/mrc p15, 0, r0, c1, c0, 0bic r0, r0, #0x00002000 @ clear bits 13 (--V-)bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)orr r0, r0, #0x00000002 @ set bit 1 (--A-) Alignorr r0, r0, #0x00000800 @ set bit 12 (Z---) BTBmcr p15, 0, r0, c1, c0, 0
(2)识别启动介质
/* Read booting information */
ldr r0, =PRO_ID_BASE
ldr r1, [r0,#OMR_OFFSET]
bic r2, r1, #0xffffffc1
(3)在sram中设置栈
ldr sp, =0xd0036000 /* end of sram dedicated to u-boot */
sub sp, sp, #12 /* set stack */
mov fp, #0/* 设置栈之后跳转到lowlevel_init */
bl lowlevel_init /* go setup pll,mux,memory */
3.7 lowlevel_init
(1)检查复位状态,cpu有多种复位状态,如冷上电、热启动、睡眠,冷上电时需要重新初始化DDR
(2)IO状态恢复:恢复睡眠前IO的值
(3)关看门狗
(4)SRAM和SROM初始化
(5)供电锁存
(6)判断代码运行位置,如果运行在RAM中,就不需要进行重定位
(7)初始化系统时钟
(8)初始化DDR
(9)初始化串口
(10)pop {pc}:函数调用返回
.globl lowlevel_init
lowlevel_init:push {lr}/* check reset status */ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)ldr r1, [r0]bic r1, r1, #0xfff6ffffcmp r1, #0x10000beq wakeup_reset_precmp r1, #0x80000beq wakeup_reset_from_didle/* IO Retention release */ldr r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)ldr r1, [r0]ldr r2, =IO_RET_RELorr r1, r1, r2str r1, [r0]/* Disable Watchdog */ldr r0, =ELFIN_WATCHDOG_BASE /* 0xE2700000 */mov r1, #0str r1, [r0]/* SRAM(2MB) init for SMDKC110 *//* GPJ1 SROM_ADDR_16to21 */ldr r0, =ELFIN_GPIO_BASEldr r1, [r0, #GPJ1CON_OFFSET]bic r1, r1, #0xFFFFFFldr r2, =0x444444orr r1, r1, r2str r1, [r0, #GPJ1CON_OFFSET]ldr r1, [r0, #GPJ1PUD_OFFSET]ldr r2, =0x3ffbic r1, r1, r2str r1, [r0, #GPJ1PUD_OFFSET]/* GPJ4 SROM_ADDR_16to21 */ldr r1, [r0, #GPJ4CON_OFFSET]bic r1, r1, #(0xf<<16)ldr r2, =(0x4<<16)orr r1, r1, r2str r1, [r0, #GPJ4CON_OFFSET]ldr r1, [r0, #GPJ4PUD_OFFSET]ldr r2, =(0x3<<8)bic r1, r1, r2str r1, [r0, #GPJ4PUD_OFFSET]/* CS0 - 16bit sram, enable nBE, Byte base address */ldr r0, =ELFIN_SROM_BASE /* 0xE8000000 */mov r1, #0x1str r1, [r0]/* PS_HOLD pin(GPH0_0) set to high */ldr r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)ldr r1, [r0]orr r1, r1, #0x300 orr r1, r1, #0x1 str r1, [r0]/* when we already run in ram, we don't need to relocate U-Boot.* and actually, memory controller must be configured before U-Boot* is running in ram.*/ldr r0, =0xff000fffbic 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 1f /* r0 == r1 then skip sdram init *//* init system clock */bl system_clock_init/* Memory initialize */bl mem_ctrl_asm_init1:/* for UART */bl uart_asm_initbl tzpc_init#if defined(CONFIG_ONENAND)bl onenandcon_init
#endif#if defined(CONFIG_NAND)/* simple init for NAND */bl nand_asm_init
#endif/* check reset status */ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)ldr r1, [r0]bic r1, r1, #0xfffeffffcmp r1, #0x10000beq wakeup_reset_pre/* ABB disable */ldr r0, =0xE010C300orr r1, r1, #(0x1<<23)str r1, [r0]/* Print 'K' */ldr r0, =ELFIN_UART_CONSOLE_BASEldr r1, =0x4b4b4b4bstr r1, [r0, #UTXH_OFFSET]pop {pc}
3.8 在DDR中设置栈
ldr r0, =0xE010E81C /* PS_HOLD_CONTROL register */
ldr r1, =0x00005301 /* PS_HOLD output high */
str r1, [r0]/* get ready to call C functions */
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
3.9 再次判断是否需要进行重定位
/* when we already run in ram, we don't need to relocate U-Boot.* and actually, memory controller must be configured before U-Boot* is running in ram.
*/
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 */
重定位代码
#if defined(CONFIG_EVT1)/* If BL1 was copied from SD/MMC CH2 */ldr r0, =0xD0037488ldr r1, [r0]ldr r2, =0xEB200000cmp r1, r2beq mmcsd_boot
#endifldr r0, =INF_REG_BASEldr r1, [r0, #INF_REG3_OFFSET]cmp r1, #BOOT_NAND /* 0x0 => boot device is nand */beq nand_bootcmp r1, #BOOT_ONENAND /* 0x1 => boot device is onenand */beq onenand_bootcmp r1, #BOOT_MMCSDbeq mmcsd_bootcmp r1, #BOOT_NORbeq nor_bootcmp r1, #BOOT_SEC_DEVbeq mmcsd_bootnand_boot:mov r0, #0x1000bl copy_from_nandb after_copyonenand_boot:bl onenand_bl2_copyb after_copymmcsd_boot:
#if DELETEldr sp, _TEXT_PHY_BASE sub sp, sp, #12mov fp, #0
#endifbl movi_bl2_copyb after_copynor_boot:bl read_hwordb after_copy
after_copy:#if defined(CONFIG_ENABLE_MMU)
enable_mmu:/* enable domain access */ldr r5, =0x0000ffffmcr p15, 0, r5, c3, c0, 0 @load domain access register/* Set the TTB register */ldr r0, _mmu_table_baseldr r1, =CFG_PHY_UBOOT_BASEldr r2, =0xfff00000bic r0, r0, r2orr r1, r0, r1mcr p15, 0, r1, c2, c0, 0/* Enable the MMU */
mmu_on:mrc p15, 0, r0, c1, c0, 0orr r0, r0, #1mcr p15, 0, r0, c1, c0, 0nopnopnopnop
#endif
3.10 再次在DDR中设置栈
skip_hw_init:/* Set up the stack */
stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#elseldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */sub r0, r0, #CFG_MALLOC_LEN /* malloc area */sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#if defined(CONFIG_USE_IRQ)sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endifsub sp, r0, #12 /* leave 3 words for abort-stack */#endif
3.11 清理bss段,并跳转到uboot启动第二阶段_start_armboot
clear_bss:ldr r0, _bss_start /* find start of bss segment */ldr r1, _bss_end /* stop here */mov r2, #0x00000000 /* clear */clbss_l:str r2, [r0] /* clear loop... */add r0, r0, #4cmp r0, r1ble clbss_lldr pc, _start_armboot