8. u-boot-2016.03移植之剪裁、修改默认参数、设置分区
从前面编译出来的u-boot.bin文件大小490多KB,其实其中有很多我们不用的代码,我们可以通过裁减uboot去掉我们没用的功能,以减少u-boot.bin文件的大小,同时也方便我们烧uboot。
8.1 修改include/configs/jz2440.h文件剪裁uboot
(1) 去掉usb支持,如下图所示:
(2) 去掉RTC支持,如下图所示:
(3) 去掉bootp选项,如下图所示:
(4) 去掉不需要的命令行配置,若下图所示:
(5) 去掉文件系统的支持,如下图所示:
(6) 在uboot顶层目录输入以下命令从新编译:
make distclean
make jz2440_defconfig
make
(7) 查看u-boot的大小,输入命令:ls u-boot.bin -l
,此时的uboot大小有490多KB减少到250多KB,如下图所示:
8.2 设置uboot分区
我们可以从uboot中输入help命令来查找uboot有哪些命令,在这些命令中我们可以找到定义分区相关的命令,如下图所示:
然后,我们可以尝试从uboot中输入mtdparts 命令观察有什么输出,输入命令后,uboot输出的结果如下图所示:
从uboot的顶层目录输入搜索命令:grep -nR "mtdids not defined, no default present"
,搜索结果如下图所示:
进入cmd/mtdparts.c文件中,发现mtdids not defined, no default present
在mtdparts_init函数中,该函数的部分代码如下:
int mtdparts_init(void)
{
/* get variables */
ids = getenv("mtdids");
parts = getenv("mtdparts");
current_partition = getenv("partition");
... ...
/* if mtdids varible is empty try to use defaults */
if (!ids) {
if (mtdids_default) {
debug("mtdids variable not defined, using default\n");
ids = mtdids_default;
setenv("mtdids", (char *)ids);
} else {
printf("mtdids not defined, no default present\n");
return 1;
}
}
... ...
}
输入mtdparts命令时,串口输出mtdids variable not defined, using default
,显然是ids = 0、mtdids_default = 0 执行了 else 分支语句。在该文件中有如下定义:
从上面source insight的代码截图可知,MTDIDS_DEFAULT
、MTDPARTS_DEFAULT
都是黑的,显然是没有定义。那么如定义呢?我们可以参考其他单板的定义。最后我们在include/configs/jz2440.h中中修改添加如下代码:
/*
*mtdparts
*/
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define MTDIDS_DEFAULT "nand0=jz2440-0" /* 表示哪一个设备 */
#define MTDPARTS_DEFAULT "mtdparts=jz2440-0:256k(u-boot)," \
"128k(params)," \
"2m(kernel)," \
"-(rootfs)" \
然后让uboot启动时自行设置分区,所以需要在uboot进入main_loop死循环之前执行mtdparts default命令。因此,在run_main_loop函数里添加代码:run_command("mtdparts default",0);
,如下图所示:
重新编译uboot,并烧写到开发板的NOR Flash,重启开发板从串口输入mtdparts命令,输出结果如下:
从上图可知,uboot把NAND Flash成功的分成了4个分区。
8.3 修改默认参数
上图显示:CRC的参数错误,使用默认的环境变量。那么我们就从这个问题引入,在uboot中搜索:using default environment
,在common/env_common.c中可找到它是在set_default_env函数里打印的,该函数的代码如下:
void set_default_env(const char *s)
{
int flags = 0;
if (sizeof(default_environment) > ENV_SIZE) {
puts("*** Error - default environment is too large\n\n");
return;
}
if (s) {
if (*s == '!') {
printf("*** Warning - %s, "
"using default environment\n\n",
s + 1);
} else {
flags = H_INTERACTIVE;
puts(s);
}
} else {
puts("Using default environment\n\n");
}
if (himport_r(&env_htab, (char *)default_environment,
sizeof(default_environment), '\0', flags, 0,
0, NULL) == 0)
error("Environment import failed: errno = %d\n", errno);
gd->flags |= GD_FLG_ENV_READY;
}
从上面的代码可以找到default_environment,它是一个全局字符数组,保存的是默认环境变量参数,该数组如下:
const uchar default_environment[] = {
#ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT
ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
#endif
#ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT
ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
#endif
#ifdef CONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
#ifdef CONFIG_BOOTCOMMAND
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
#endif
#ifdef CONFIG_RAMBOOTCOMMAND
"ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
#endif
#ifdef CONFIG_NFSBOOTCOMMAND
"nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
"bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
"baudrate=" __stringify(CONFIG_BAUDRATE) "\0"
#endif
#ifdef CONFIG_LOADS_ECHO
"loads_echo=" __stringify(CONFIG_LOADS_ECHO) "\0"
#endif
#ifdef CONFIG_ETHPRIME
"ethprime=" CONFIG_ETHPRIME "\0"
#endif
#ifdef CONFIG_IPADDR
"ipaddr=" __stringify(CONFIG_IPADDR) "\0"
#endif
#ifdef CONFIG_SERVERIP
"serverip=" __stringify(CONFIG_SERVERIP) "\0"
#endif
#ifdef CONFIG_SYS_AUTOLOAD
"autoload=" CONFIG_SYS_AUTOLOAD "\0"
#endif
#ifdef CONFIG_PREBOOT
"preboot=" CONFIG_PREBOOT "\0"
#endif
#ifdef CONFIG_ROOTPATH
"rootpath=" CONFIG_ROOTPATH "\0"
#endif
#ifdef CONFIG_GATEWAYIP
"gatewayip=" __stringify(CONFIG_GATEWAYIP) "\0"
#endif
#ifdef CONFIG_NETMASK
"netmask=" __stringify(CONFIG_NETMASK) "\0"
#endif
#ifdef CONFIG_HOSTNAME
"hostname=" __stringify(CONFIG_HOSTNAME) "\0"
#endif
#ifdef CONFIG_BOOTFILE
"bootfile=" CONFIG_BOOTFILE "\0"
#endif
#ifdef CONFIG_LOADADDR
"loadaddr=" __stringify(CONFIG_LOADADDR) "\0"
#endif
#ifdef CONFIG_CLOCKS_IN_MHZ
"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
"pcidelay=" __stringify(CONFIG_PCI_BOOTDELAY)"\0"
#endif
#ifdef CONFIG_ENV_VARS_UBOOT_CONFIG
"arch=" CONFIG_SYS_ARCH "\0"
"cpu=" CONFIG_SYS_CPU "\0"
"board=" CONFIG_SYS_BOARD "\0"
"board_name=" CONFIG_SYS_BOARD "\0"
#ifdef CONFIG_SYS_VENDOR
"vendor=" CONFIG_SYS_VENDOR "\0"
#endif
#ifdef CONFIG_SYS_SOC
"soc=" CONFIG_SYS_SOC "\0"
#endif
#endif
#ifdef CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
"\0"
#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
}
#endif
};
从上面的代码可知:① bootargs
是传给内核的启动参数,可以设置文件系统的相关分区等;② bootcmd
是uboot用来启动内核的参数;③ ipaddr
、serverip
、gatewayip
、netmask
分别是开发板的IP地址、服务器IP地址、网关、掩码;④ 忽然发现,上面默认的环境变量里竟然没有设置默认MAC地址的环境变量 ethaddr
,那么我们可以ipaddr
的设置添加ethaddr
环境变量,代码如下:
#ifdef CONFIG_ETHADDR
"ethaddr=" __stringify(CONFIG_ETHADDR) "\0"
#endif
我们只需要修改相关宏就可以修改默认环境变量参数了,总的修改如下:(在include/configs/jz2440.h修改)
#define CONFIG_BOOTARGS "console=ttySAC0 root=/dev/mtdblock3"
#define CONFIG_BOOTCOMMAND "nand read 30000000 kernel;bootm 30000000"
#define CONFIG_ETHADDR 00:0c:29:4d:e4:f4 /*定义MAC地址*/
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.0.200
#define CONFIG_SERVERIP 192.168.0.100
#define CONFIG_GATEWAYIP 192.168.0.1
重新编译,烧写启动新uboot时就会默认使用上面的环境变量,不需要每次启动都去修改变量了。启动开发板后,串口输入print
命令,串口的打印信息如下:
8.4 修改支持保存环境变量
之前我们设置好参数之后,每次都不敢save,就是怕破坏FLASH;在jz2440.h配置文件中,找到如下环境变量的相关定义,如下图所示:
那么我们重新定义这些宏,该怎么定义呢?在uboot命令行使用help命令查看save相关的信息,如下图所示:
然后我们在uboot源码中搜索字符串:grep -nR “saveenv”
找到了类似这样的语句:common/env_nand.c:181:int saveenv(void)
我们去common目录下看看Makefile,看看env_nand.c的编译依赖哪个宏?找到了下面这句:obj-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o
,说明编译env_nand.c依赖的是CONFIG_ENV_IS_IN_NAND这个宏的定义。
那么我们就定义这个宏CONFIG_ENV_IS_IN_NAND
,所以我们将上面环境变量的宏重新定义如下:
#define CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x00040000
#define CONFIG_ENV_SIZE 0x20000
#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
重新编译uboot,烧写到开发板,测试如下:
从上图可知,环境变量参数被保存到NAND Flash的第二个分区了。