移植u-boot到mini2440--SPL初探

  前面添加开发板的时候,在文件 arch/arm/Kconfig 添加:

config TARGET_MINI2440
        bool "Support mini2440"
        select CPU_ARM920T
        select SUPPORT_SPL

  所以如果选择mini2440 就会在菜单出现SPL支持,make menuconfig 看下:
移植u-boot到mini2440--SPL初探_第1张图片

  选择Enable SPL,退出然后编译尝试下,出现错误 undefined reference to board_init_f
移植u-boot到mini2440--SPL初探_第2张图片

  函数 board_init_f 在文件 arch/arm/lib/spl.c 有定义void __weak board_init_f(ulong dummy) 这里函数声明为weak类型的,说明我们可以定义自己的重名函数。事实上网上很多人都是这么做的,但是如果想用系统提供的 board_init_f ,该如何做?

  通过分析arm/arm/lib/Makefile 可知这个函数依赖于宏SPL_BUILD 首先在 mini2440.h 里面加入宏定义

#define CONFIG_SPL_BUILD

  编译还是有错:

drivers/mtd/onenand/onenand_spl.c: In function 'onenand_readw':
drivers/mtd/onenand/onenand_spl.c:34:15: error: 'CONFIG_SYS_ONENAND_BASE' undeclared (first use in this function)

  先随便在 mini2440.h 定义一个数值等编译通过了再修改成正确的

#define CONFIG_SYS_ONENAND_BASE 0x0

  编译,居然还有错!!! :

In file included from drivers/serial/serial.c:8:0:
drivers/serial/serial.c: In function 'serial_stub_putc':
include/common.h:872:19: error: expected identifier before 'do'
 #define putc(...) do { } while (0)

  看下 include/common.h:

/* stdout */
#if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SERIAL_SUPPORT)
#define putc(...) do { } while (0)
#define puts(...) do { } while (0)
#define printf(...) do { } while (0)
#define vprintf(...) do { } while (0)
#else
void    putc(const char c);
void    puts(const char *s);
int     printf(const char *fmt, ...)
                __attribute__ ((format (__printf__, 1, 2)));
int     vprintf(const char *fmt, va_list args);
#endif

  再看下 drivers/serial/serial.c:

static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
{
        struct serial_device *dev = sdev->priv;

        dev->putc(ch);
}

  common.h 的意思就是如果没有定义 SPL_SERIAL_SUPPORT 打印的系列函数就宏定义成空操作,但是在serial.c 中 dev->putc 经过编译预处理 也被替换,do 前面加上了 -> 肯定编译报错了。

怎么办?

  在 mini2440.h 里面加入宏定义 CONFIG_SPL_SERIAL_SUPPORT 试下:

drivers/serial/built-in.o: In function `s3serial1_putc':
/tmp/u-boot-2016.01/drivers/serial/serial_s3c24x0.c:209: multiple definition of `s3serial1_putc'
drivers/built-in.o:/tmp/u-boot-2016.01/drivers/serial/serial_s3c24x0.c:209: first defined here

  此时在链接阶段出现大量的serial 系列函数冲定义的错误,初步猜测是因为SPL 阶段的函数和u-boot阶段的函数符号重复导致,那么先不定义 CONFIG_SPL_SERIAL_SUPPORT 把 include/common.h 修改如下:

/* stdout */
#if 0   /*defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SERIAL_SUPPORT) */
#define putc(...) do { } while (0)
.... ....
#endif

  编译,依然有错:

arch/arm/lib/built-in.o: In function `_main':
/tmp/u-boot-2016.01/arch/arm/lib/crt0.S:86: undefined reference to `board_init_f_mem'
/tmp/u-boot-2016.01/arch/arm/lib/crt0.S:90: undefined reference to `board_init_f'

  函数 board_init_f_mem 主要是初始化 结构体 global_data ,这里可以修改common/Makefile :

# core
obj-y += init/
ifndef CONFIG_SPL_BUILD
obj-y += main.o
obj-y += exports.o
obj-y += hash.o
ifdef CONFIG_SYS_HUSH_PARSER
obj-y += cli_hush.o
endif

  但是 board_init_f 到现在依然还提示未定义 ,经过分析发现前面的宏定义CONFIG_SPL_BUILD 是在配置了SPL之后默认就有的,不需要手动加入,需要加入的是宏定义 #define CONFIG_SPL_FRAMEWORK ;编译,结果还是有错:

/tmp/u-boot-2016.01/arch/arm/lib/crt0.S:133: undefined reference to `spl_relocate_stack_gd'
/tmp/u-boot-2016.01/arch/arm/lib/crt0.S:166: undefined reference to `board_init_r'

  在 common/Makefile 加入一行:

ifdef CONFIG_SPL_BUILD
obj-y += spl/
obj-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o
obj-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o

  再次编译

common/built-in.o: In function `spl_init':
/tmp/u-boot-2016.01/common/spl/spl.c:157: undefined reference to `printf'
common/built-in.o: In function `board_boot_order':
/tmp/u-boot-2016.01/common/spl/spl.c:195: undefined reference to `spl_boot_device'
common/built-in.o: In function `board_init_r':
/tmp/u-boot-2016.01/common/spl/spl.c:347: undefined reference to `printf'
/tmp/u-boot-2016.01/common/spl/spl.c:380: undefined reference to `puts

  是不是上面的把宏定义 CONFIG_SPL_SERIAL_SUPPORT 去掉导致的? 但是如果加上宏定义就会导致好多函数重定义,如果不加在这里就会 函数未定义!!

  无奈,只好把上面的所有的未定义的全部注释掉,编译成功。

至此,SPL 初步编译通过。

  生成的 u-boot-spl.bin 烧写在 nandflash 的前4K,主要作用就是初始化内存,把 u-boot 从nandflash里面读到内存里面,然后跳转到u-boot。这里流程不复杂,主要用到两个文件 : s3c2410_nand.c s3c24x0 的nandflash驱动,和 nand_spl_simple.c

  把生成的u-boot 反汇编一下:

arm-linux-objdump -D -m arm  u-boot-spl > u-boot-spl.dis

  可以看出也是从_start开始执行,跳转到reset,然后就是 cpu_init_crit 注意这里要加入条件编译控制,因为在SPL阶段初始化内存了,在u-boot启动阶段就不用初始化了。

  然后就是_main函数,在这里调用了 board_init_f arch/arm/lib/spl.c 然后就调用 board_init_r common/spl/spl.c 注意这里的 board_init_r 跟u-boot里面调用的 还不是一个函数。
  这里调用了 spl_load_image -> spl_nand_load_image
-> nand_init drivers/mtd/nand/nand_spl_simple.c -> board_nand_init drivers/mtd/nand/s3c2410_nand.c

-> nand_spl_load_image drivers/mtd/nand/nand_spl_simple.c -> nand_read_page -> this->read_buf 函数指针指向 nand_read_buf drivers/mtd/nand/s3c2410_nand.c

-> spl_set_header_raw_uboot 在这里设置u-boot的入口点,等待跳转spl_image.entry_point = CONFIG_SYS_UBOOT_START

  函数都执行之后返回到 board_init_r ,调用 jump_to_image_no_args 进入 u-boot 入口点,开始执行u-boot:

        image_entry_noargs_t image_entry =
        (image_entry_noargs_t)(unsigned long)spl_image->entry_point;
        image_entry();

你可能感兴趣的:(编译,spl,ARM,u-boot)