U-Boot2018.11引导Nuttx7.26
- 目录
- [U-Boot]下载源码
- [U-Boot]配置源码
- [U-Boot]修改调试
- [U-Boot]部分源码分析
- [Nuttx]修改调试
目录
[U-Boot]下载源码
不墨迹了,直接发链接,对应版本下载就OK,我用的是2018.11
[U-Boot]配置源码
接下来就是解压出源代码,配置工程:
接下来就是配置工程了,配置的命令如下:
#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啦,就像这样
[U-Boot]修改调试
接下来进入调试环节,注意接下我们就导入到eclpse的环境中吧~
step1:创建一个工程
step2:配置调试器
设置工程路径
设置芯片信息
确保了这两步,基本就可以单步调试了
点击小甲壳虫
旁边的倒三角,在点击刚刚配置的调试工程,就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这个数据结构体展开的,上述代码注释已经解释了大致的功能,下面再贴一个详细点的:
接下来就是board_init_f()函数,这和里面主要是针对片上外设进行初始化,涉及到cpu、serial、log、systick等等:
图片中标红的函数是我们需要重点去关注的部分;
起初我在编译完成下载到板子上,发现终端没有任何输出,这里需要注意的是,在配置工程中,我们所选择的配置,(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-
编译生成二进制文件
烧录进去应该就能看到下面的画面:
接下来就可以试试"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
有疑问的同学可以留言!!!