U-Boot2018.11引导Nuttx7.26

  • 目录
  • [U-Boot]下载源码
  • [U-Boot]配置源码
  • [U-Boot]修改调试
  • [U-Boot]部分源码分析
  • [Nuttx]修改调试


目录

[U-Boot]下载源码

不墨迹了,直接发链接,对应版本下载就OK,我用的是2018.11

bios里面的numa node是什么意思_#endif

[U-Boot]配置源码

接下来就是解压出源代码,配置工程:

bios里面的numa node是什么意思_uboot_02

接下来就是配置工程了,配置的命令如下:

#make mrproper
#make stm32f746-disco_defconfig
#make menuconfig
#make ARCH=arm CROSS_COMPILE=arm-none-eabi-

配置的时候最好去./u-boot2018.11/configs文件夹下看看有没有对应的开发板型号
另外需要更丰富的配置的时候就用make menuconfig去配置.
这里暂时就不需要了.
执行完了以后就会生产u-boot.bin啦,就像这样

bios里面的numa node是什么意思_#endif_03

[U-Boot]修改调试

接下来进入调试环节,注意接下我们就导入到eclpse的环境中吧~

step1:创建一个工程

bios里面的numa node是什么意思_uboot_04

step2:配置调试器

设置工程路径

bios里面的numa node是什么意思_#if_05

设置芯片信息

bios里面的numa node是什么意思_uboot_06


bios里面的numa node是什么意思_#endif_07


确保了这两步,基本就可以单步调试了

点击小甲壳虫

bios里面的numa node是什么意思_nuttx_08

旁边的倒三角,在点击刚刚配置的调试工程,就OK啦

[U-Boot]部分源码分析

文件一:crt0.S

/*
 * This file handles the target-independent stages of the U-Boot
 * start-up where a C runtime environment is needed. Its entry point
 * is _main and is branched into from the target's start.S file.
 *
 * _main execution sequence is:
 *
 * 1. Set up initial environment for calling board_init_f().
 *    This environment only provides a stack and a place to store
 *    the GD ('global data') structure, both located in some readily
 *    available RAM (SRAM, locked cache...). In this context, VARIABLE
 *    global data, initialized or not (BSS), are UNAVAILABLE; only
 *    CONSTANT initialized data are available. GD should be zeroed
 *    before board_init_f() is called.
 * 	  设置栈,然后预留一定的内存给gd_t结构体并清零,用来存放全局参数
 * 	  然后调用board_init_f()
 *
 * 2. Call board_init_f(). This function prepares the hardware for
 *    execution from system RAM (DRAM, DDR...) As system RAM may not
 *    be available yet, , board_init_f() must use the current GD to
 *    store any data which must be passed on to later stages. These
 *    data include the relocation destination, the future stack, and
 *    the future GD location.
 *	  board_init_f()这个函数的作用是初始化硬件使系统能在RAM中运行(DRAM\DDR)
 *	  使用这个函数的前提是:
 *    1.设置好gd_t结构体来存放"初始化"中各个参数(重定位地址,重定位栈地址...)
 *
 * 3. Set up intermediate environment where the stack and GD are the
 *    ones allocated by board_init_f() in system RAM, but BSS and
 *    initialized non-const data are still not available.
 *    board_init_f()在RAM分配的栈和gd_t由于bss段未分配好,所以暂时是不能使用的
 *
 * 4a.For U-Boot proper (not SPL), call relocate_code(). This function
 *    relocates U-Boot from its current location into the relocation
 *    destination computed by board_init_f().
 *
 * 4b.For SPL, board_init_f() just returns (to crt0). There is no
 *    code relocation in SPL.
 *
 * 5. Set up final environment for calling board_init_r(). This
 *    environment has BSS (initialized to 0), initialized non-const
 *    data (initialized to their intended value), and stack in system
 *    RAM (for SPL moving the stack and GD into RAM is optional - see
 *    CONFIG_SPL_STACK_R). GD has retained values set by board_init_f().
 *    重定位后,BSS和non-const data都被初始化了,在进入board_init_r函数之前应先设置最终的环境参数
 *
 * 6. For U-Boot proper (not SPL), some CPUs have some work left to do
 *    at this point regarding memory, so call c_runtime_cpu_setup.
 *
 * 7. Branch to board_init_r().
 *
 * For more information see 'Board Initialisation Flow in README.
 */

/*
 * entry point of crt0 sequence
 */

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)   		/* 未定义SPL */
	ldr	r0, =(CONFIG_SPL_STACK)
#else
	ldr	r0, =(CONFIG_SYS_INIT_SP_ADDR)								/* 1.设置栈地址为0x20050000 */
#endif
	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
	mov	sp, r0
	bl	board_init_f_alloc_reserve									/* 2. 为gd_t结构体保留空间 */
	mov	sp, r0
	/* set up gd here, outside any C code */
	mov	r9, r0
	bl	board_init_f_init_reserve									/* 3. 初始化gd_t(清零),结构体中存放的是全局参数 */

	mov	r0, #0
	bl	board_init_f												/* 4. 进入board_init_f进行各种初始化,分配SDRAM内存空间,填充进gd_t结构体中 */

#if ! defined(CONFIG_SPL_BUILD)

/*
 * Set up intermediate environment (new sp and gd) and call
 * relocate_code(addr_moni). Trick here is that we'll return
 * 'here' but relocated.
 */

	ldr	r0, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */
	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
	mov	sp, r0
	ldr	r9, [r9, #GD_BD]		/* r9 = gd->bd */
	sub	r9, r9, #GD_SIZE		/* new GD is below bd */			/* 5. 将重定位后的GD地址放入r9中 */

	adr	lr, here
	ldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */
	add	lr, lr, r0
#if defined(CONFIG_CPU_V7M)
	orr	lr, #1				/* As required by Thumb-only */
#endif
	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
	b	relocate_code												/* 6. 重定位代码,地址是gd->relocaddr */
here:
/*
 * now relocate vectors
 */

	bl	relocate_vectors											/* 7.重定位中断向量表 */

/* Set up final (full) environment */

	bl	c_runtime_cpu_setup	/* we still call old routine here */
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
# ifdef CONFIG_SPL_BUILD
	/* Use a DRAM stack for the rest of SPL, if requested */
	bl	spl_relocate_stack_gd
	cmp	r0, #0
	movne	sp, r0
	movne	r9, r0
# endif
	ldr	r0, =__bss_start	/* this is auto-relocated! */

#ifdef CONFIG_USE_ARCH_MEMSET
	ldr	r3, =__bss_end		/* this is auto-relocated! */
	mov	r1, #0x00000000		/* prepare zero to clear BSS */

	subs	r2, r3, r0		/* r2 = memset len */
	bl	memset
#else
	ldr	r1, =__bss_end		/* this is auto-relocated! */
	mov	r2, #0x00000000		/* prepare zero to clear BSS */

clbss_l:cmp	r0, r1			/* while not at end of BSS */
	strlo	r2, [r0]		/* clear 32-bit BSS word */
	addlo	r0, r0, #4		/* move to next */
	blo	clbss_l
#endif

#if ! defined(CONFIG_SPL_BUILD)
	bl coloured_LED_init
	bl red_led_on
#endif
	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov     r0, r9                  /* gd_t */
	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
	/* call board_init_r */
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
	ldr	lr, =board_init_r	/* this is auto-relocated! */
	bx	lr
#else
	ldr	pc, =board_init_r	/* this is auto-relocated! */
#endif
	/* we should not return here. */
#endif

ENDPROC(_main)

然后就是重点了,修改u-boot.
首先直接编译出来的u-boot是没法用的:
直接给出修改点:
1…/u-boot-2018.11/board/st/stm32f746-disco/stm32f746-disco.c
我们使用了spl,所以这里需要执行宏里面的代码,不然程序就会执行不下去(具体的单步仿真一下就明白了)

int dram_init(void)
{
#ifdef CONFIG_SUPPORT_SPL /* #ifndef CONFIG_SUPPORT_SPL */
	int rv;
	struct udevice *dev;
	rv = uclass_get_device(UCLASS_RAM, 0, &dev);
	if (rv) {
		debug("DRAM init failed: %d\n", rv);
		return rv;
	}


#endif
	/* 获得 dram 的基地址和大小,保存到全局变量 gd 中 */
	return fdtdec_setup_mem_size_base();
}

这里还需要修改一个地方就是uboot里面的跳转代码了:
在./cmd/boot.c中

static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	ulong	addr, rc;
	int     rcode = 0;

	if (argc < 2)
		return CMD_RET_USAGE;

	addr = simple_strtoul(argv[1], NULL, 16);

   /*
	* must cleanup before jump
	* !!!这里也是需要注意,必须要加的,起初没加,导致跳转后会出现一些异常现象
	* 具体导致的原因是dcache和icache,这里可以深究一下。
	*/
	cleanup_before_linux();

	printf ("## Starting application at 0x%08lX ...\n", addr);

	/*
	 *  set msp and boot to applications
	 * 这里就是设置跳转的地址
	 * 然后执行跳转
	 * !!!uboot的原始代码go命令只是实现了命令的跳转,并没有实现”设置主堆栈和中断向量表“
	 * 所以要实现完整的跳转指令。
	 */
	const uint32_t *app_base = (const uint32_t *)addr;
	asm volatile(
		"msr msp, %0	\n"
		"bx	%1	\n"
		: : "r"(app_base[0]), "r"(app_base[1]) :);

	/*
	 * pass address parameter as argv[0] (aka command name),
	 * and all remaining args
	 */
	rc = do_go_exec ((void *)addr, argc - 1, argv + 1);
	if (rc != 0) rcode = 1;

	printf ("## Application terminated, rc = 0x%lX\n", rc);
	return rcode;
}

总的来说,是围绕struct gd_t这个数据结构体展开的,上述代码注释已经解释了大致的功能,下面再贴一个详细点的:

bios里面的numa node是什么意思_#if_09


接下来就是board_init_f()函数,这和里面主要是针对片上外设进行初始化,涉及到cpu、serial、log、systick等等:

bios里面的numa node是什么意思_#endif_10


bios里面的numa node是什么意思_uboot_11


图片中标红的函数是我们需要重点去关注的部分;

起初我在编译完成下载到板子上,发现终端没有任何输出,这里需要注意的是,在配置工程中,我们所选择的配置,(make stm32f746-disco_defconfig)就是执行的这句话,会默认配置.config。

通过make menuconfig 在如下路径中会确定硬件配置,其中xxxx就是./arch/arm/dts目录下xxxx.dts文件,如果自己的硬件定义有变化,修改对应dts文件即可。

->Device Tree Control
(xxxx) Default Device Tree for DT control

到这里在次执行make ARCH=arm CROSS_COMPILE=arm-none-eabi-

编译生成二进制文件

烧录进去应该就能看到下面的画面:

bios里面的numa node是什么意思_uboot_12

接下来就可以试试"tftp pri"等等一系列指令了

[Nuttx]修改调试

关于nuttx的配置问题这里就不详细说了
假定是编译通过的版本
要想用u-boot引导nuttx 明白两点就好了
1.cortex-M的soc编译的二进制文件首地址存放的是堆栈的指针,其次存放的才是跳转指令
2.跳转前我们需要做的工作就是设置堆栈指针,然后调到app的位置去
在nuttx这边我们要做的工作就是修改链接脚本:

MEMORY
{
	itcm  (rwx) : ORIGIN = 0x00200000, LENGTH = 2048K
	flash (rx)  : ORIGIN = 0x08040000, LENGTH = 2048K-  256K //这里要修改代码在norflash上的偏移量,偏移多少至少大于uboot的bin大小
	dtcm  (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
	sram1 (rwx) : ORIGIN = 0x20020000, LENGTH = 368K
	sram2 (rwx) : ORIGIN = 0x2007c000, LENGTH = 16K
}

烧录的时候先烧录u-boot.bin 到0x08000000
然后在烧录nuttx的nuttx.bin 到0x08040000
上电后,进入到u-boot的界面里,然后输入 go 0x08040000

最终的效果:

U-Boot 2018.11 (Nov 22 2018 - 16:54:08 +0800)

Model: BOARD-F7
DRAM:  32 MiB
Flash: 1 MiB
MMC:   sdio@40012c00: 0
In:    serial
Out:   serial
Err:   serial
usr button is at LOW LEVEL
Net:   
Warning: ethernet@40028000 (eth0) using random MAC address - de:f0:bd:c5:06:1b
eth0: ethernet@40028000
Hit SPACE in 3 seconds to stop autoboot.
U-Boot> go 0x08040000
## Starting application at 0x08040000 ...
NuttShell (NSH) NuttX-7.26
nsh>

这里只是记录了一个大致的流程,u-boot的代码远没有我说的简单,具体可以参考网上其他的分析blog
有疑问的同学可以留言!!!