NanoPC-T2 uboot分析(1)

在boards.cfg中,可以看到在该文件末尾定义Nanopi2/Nanopc开发板的一些属性

# Status, Arch, CPU:SPLCPU, SoC, Vendor, Board name, Target, Options, Maintainers

Active  arm         slsiap       s5p4418     s5p4418         nanopi2             s5p4418_nanopi2                       -

从该行可以看出来,该开发板使用的soc使用arm架构,但是使用的cpu是slsiap。众所周知,在arm架构中根本不存在这样的CPU,通过其他途径获知NanoPi2/NanoPC-T2使用的soc(s5p4418)采用的是armv7的指令集,而这里为什么又定义为slsiap呢?我觉得是或许是这个soc需要用到的代码跟其他armv7指令集的代码有些不同,为了不影响其他开发板的代码,设置cpu是slsiap,这样定位的启动代码目录应该是arch/arm/cpu/slsiap/,恰好该目录下也存在一个start.S汇编文件,但是打开start.S就立马傻眼了,因为里面啥代码都没有,这样的代码架构确实跟其他开发板的架构不同,真奇葩。

分析该目录下的u-boot.lds发现把SDIR/start.o (.text*)放置在了镜像的首要位置。继续分析SDIR是何许人也。

在arch/arm/slsiap目录下存在一个config.mk.找到了SDIR=arch/arm/cpu$(if $(CPU),/$(CPU),)$(if $(SOC),/$(SOC),)

分析一下的语法:$(if(CPU),/$(CPU))

虽然我以前也没有遇到过这样的语法,但是我猜是这样的定义:如果CPU有定义,那么该结果为定义CPU型号目录。

在NanoPi2/NanoPC-T2中,CPU为slsiap,SOC为s5p4418

SDIR最后结果应该是SDIR=arch/arm/cpu/slsiap/s5p4418/

在SDIR目录下,确定存在着另外一个stat.S文件。

现在分析一下start.S文件

在reset中首先调用了save_boot_params,但是看了下这个函数什么都没做,可以无视这个函数,接下来是让CPU进入管理模式,禁止IRQ和FIQ,这跟Exynos4412没有什么区别。

接下来是

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
bl cpu_init_crit
#endif

在include/configs/s5p4418_nanopi2.h中没有找到CONFIG_SKIP_LOWLEVEL_INIT这个宏定义,那么就会执行cpu_init_cp15和cpu_init_crit。

cpu_init_cp15貌似只要属于一种CPU都一样的,没啥差别,这就不讲了,其实我也不是太详细是怎么实现的,反正是设计到了一些特殊的寄存器了。

cpu_init_crit,该程序同样位于该start.S

在cpu_init_crit会调用lowlevel_init,lowlevel_init位于low_init.S文件中。

在lowlevel_init中,首先对SP寄存器进行赋值:ldr  sp, =CONFIG_SYS_INIT_SP_ADDR

然后是将栈指针SP减去GD_SIZE,GD_SIZE这块内存空间是用来保存global_data结构体的数据,并将这个结构体的地址保存在r9寄存器中。这是一个很重要的结构体。

紧接着是调用s_init,但是这个函数为空,不需要分析

返回到start.s,紧接着执行bl _main,注意_main不是C语言里的main,而是由汇编代码编写的一段代码,位于arch/arm/lib/crt0.s

在_main里又对SP寄存器进行赋值,调用board_init_f_mem(common/init/board_init.c))再次为global_data结构体预留空间,并对global_data空间清零。

为什么会执行两次设置SP寄存器、预留global_data结构体空间呢?这是由于在start.s里执行的有宏定义,有可能第一次没有执行,所以在_main里面为了安全再执行一次。


然后就是调用board_init_f函数进一步初始化,这个函数很重要。位于common/board_f.c。这个函数中主要是调用init_sequence_f数组中的函数指针初始化各个模块(包括串口初始化、global_data初始化、cpu初始化等),初始化完毕后返回_main中。


接下来进行代码重定位,搬到内存的指定位置。并设置中断向量。

bl c_runtime_cpu_setup是用来开启打开指令缓存和数据缓存。清bss段,调用board_init_r(common/board_r.c)函数。


在这个函数里,完全是在调用init_sequence_r数组里的函数指针,这个数组中最后一个是run_main_loop,这个函数是一个死循环,不会退出的,在这里相应命令行等操作


你可能感兴趣的:(NanoPC-T2)