赞
踩
本篇文章中,主要讨论SPL这个文件的作用及代码流程
uboot-spl 的全程叫做 uboot-second program loader (uboot 第二加载程序,第一加载程序是原厂的程序IBR)
1.初始化默认串口
2.设置GD结构体
3.拷贝主要uboot镜像到DDR处,然后跳转执行新的uboot
文件流如下:
#include <config.h>
.globl _start //定义一个全局变量 _start
.section ".vectors", "ax" //定义一个段叫.vectors
_start:
b reset //跳转到reset处,下面都不用看,我们去看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
.globl reset //定义一个全局变量reset reset: /* * set the cpu to SVC32 mode 这里是系统操作我们不用细看 */ mrs r0,cpsr bic r0,r0,#0x1f orr r0,r0,#0xd3 msr cpsr,r0 /* * we do sys-critical inits only at reboot, * not when booting from ram! */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit //这里要看,但是跟我们要表达的不一样,可以当额外知识补充,主要包括了cpu内部cache等操作 #endif bl _main //不想看上面的那个函数,我们就直接去看_main #ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu_init_crit: //看这里 /* * flush D cache before disabling it */ mov r0, #0 flush_dcache: mrc p15, 0, r15, c7, c10, 3 bne flush_dcache mcr p15, 0, r0, c8, c7, 0 /* invalidate TLB */ mcr p15, 0, r0, c7, c5, 0 /* invalidate I Cache */ /* * disable MMU and D cache * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00000300 /* clear bits 9:8 (---- --RS) */ bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */ #ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH orr r0, r0, #0x00002000 /* set bit 13 (--V- ----) */ #else bic r0, r0, #0x00002000 /* clear bit 13 (--V- ----) */ #endif orr r0, r0, #0x00000002 /* set bit 1 (A) Align */ #ifndef CONFIG_SYS_ICACHE_OFF orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */ #endif mcr p15, 0, r0, c1, c0, 0 #ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY /* * Go setup Memory and board specific bits prior to relocation. */ mov ip, lr /* perserve link reg across call */ bl lowlevel_init /* go setup pll,mux,memory 没啥用,不用管 */ mov lr, ip /* restore link 回到刚才进来的地方,也就是调用cpu_init_crit 的地方 */ #endif mov pc, lr /* back to my caller */ #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
/* 这里我只截取了最重要的部分 */ ENTRY(_main) #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) ldr sp, =(CONFIG_SPL_STACK) //设置堆栈为0xBC004000,这个是芯片内部16kbRAM的地址顶端 #else ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) #endif /* 设置堆栈指针8字节对齐*/ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ /* 下面这五步基本不用看,想看的话可以看common/init/board_init.c 最主要的工作还是设置GD这个结构体*/ mov r0, sp bl board_init_f_alloc_reserve mov sp, r0 /* set up gd here, outside any C code */ mov r9, r0 bl board_init_f_init_reserve /* 设置r0 为0 */ mov r0, #0 /* 调用board_init_f 这个函数,这个是重头戏 */ bl board_init_f
void board_init_f(unsigned long bootflag) { struct nand_chip *nand = &nand_chip[0]; struct mtd_info *mtd = nand_to_mtd(nand); int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; __attribute__((noreturn)) void (*uboot)(void); //定义一个void类型函数指针 /* 串口初始化 */ nuc980_serial_init(); printf("\n SPL load main U-Boot from SPI NAND Flash! (%s %s)\n",__DATE__,__TIME__); printf("nand_chip addr %08lx\n",nand); if (maxchips < 1) maxchips = 1; nuc980_spi_init(); mtd->writesize = 2048; //设置2k页面写 mtd->erasesize = 64 * (mtd->writesize); //设置 128K擦除大小 /* * Load U-Boot image from SPI NAND into RAM */ /* 从CONFIG_SYS_NAND_U_BOOT_OFFS处读取 CONFIG_SYS_NAND_U_BOOT_SIZE大小的数据,然后加载到DDR地址CONFIG_SYS_NAND_U_BOOT_DST处 ,如果想深究是怎么加载的,一定要进入代码中看一下,这边不进去看了 */ spinand_load(mtd, CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE, (uchar *)CONFIG_SYS_NAND_U_BOOT_DST); #ifdef CONFIG_NAND_ENV_DST spinand_load(mtd, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, (uchar *)CONFIG_NAND_ENV_DST); #ifdef CONFIG_ENV_OFFSET_REDUND spinand_load(mtd, CONFIG_ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); #endif #endif /* * Jump to U-Boot image */ /* CONFIG_SYS_NAND_U_BOOT_START 跟 CONFIG_SYS_NAND_U_BOOT_DST 是一样的*/ uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; (*uboot)(); //跳转到新的uboot去 }
文章只能帮你把事情理顺,没有办法把代码完完全全讲出来。所以,还是建议读者要对着代码来看这些东西,不然很难看懂。其次,如果你不知道这个宏定义有没有被选中,我建议是复制这个宏定义并查看spl/u-boot.cfg文件。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。