当前位置:   article > 正文

uboot-spl.bin分析

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(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 */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

(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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

(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去
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

总结`

文章只能帮你把事情理顺,没有办法把代码完完全全讲出来。所以,还是建议读者要对着代码来看这些东西,不然很难看懂。其次,如果你不知道这个宏定义有没有被选中,我建议是复制这个宏定义并查看spl/u-boot.cfg文件。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/130034
推荐阅读
相关标签
  

闽ICP备14008679号