uboot-spl.bin分析

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文件。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值