uboot-spl.bin
本篇文章中,主要讨论SPL这个文件的作用及代码流程
文章目录
前言
uboot-spl 的全程叫做 uboot-second program loader (uboot 第二加载程序,第一加载程序是原厂的程序IBR)
一、uboot-spl作用是什么?
1.初始化默认串口
2.设置GD结构体
3.拷贝主要uboot镜像到DDR处,然后跳转执行新的uboot
二、uboot-spl执行流程
1.文件流
文件流如下:
2.代码流
(1)vectors.S
#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
(2)start.S
.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 */
(3)crt0.S
/* 这里我只截取了最重要的部分 */
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
(3)spinand_boot.c
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文件。