内核默认分布空间
boot params kernel root
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"
默认参数设置
const uchar default_environment[] = {
#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=" MK_STR(CONFIG_BOOTDELAY) "\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
"baudrate=" MK_STR(CONFIG_BAUDRATE) "\0"
所以我们需要对一些参数进行设置,不再试默认参数,这样启动uboot时不会再报
*** Warning - bad CRC, using default environment
但是我们需要做的就是两步。一个就是设置环境变量的参数,第二就是保存环境变量
#define CONFIG_BOOTARGS "console=ttySAC0 root=/dev/mtdblock3" //设置控制台和root分区
#define CONFIG_BOOTCOMMAND "nand read 30000000 0xabc 0x200000;bootm 30000000" //设置内核的读取地址
第二步保存环境变量时,我们需要规定环境变量的保存地址,在内核参数中我们可以看到 0x00040000-0x00060000 : "params",但是我们现在的uboot太大,所以需要进行如下步骤
裁剪uboot,修改大小
查看头文件,看那些内容不需要,直接屏蔽
//#define CONFIG_USB_OHCI
//#define CONFIG_USB_KEYBOARD
//#define CONFIG_USB_STORAGE
//#define CONFIG_DOS_PARTITION
//#define CONFIG_RTC_S3C24X0
//#define CONFIG_BOOTP_BOOTFILESIZE
//#define CONFIG_BOOTP_BOOTPATH
//#define CONFIG_BOOTP_GATEWAY
//#define CONFIG_BOOTP_HOSTNAME
//#define CONFIG_CMD_DATE
//#define CONFIG_CMD_DHCP 动态获得ip
//#define CONFIG_CMD_USB
#if 0
/*
* File system
*/
#define CONFIG_CMD_FAT
#define CONFIG_CMD_EXT2
#define CONFIG_CMD_UBI
#define CONFIG_CMD_UBIFS
#define CONFIG_CMD_MTDPARTS
#define CONFIG_MTD_DEVICE
#define CONFIG_MTD_PARTITIONS
//#define CONFIG_YAFFS2
#define CONFIG_RBTREE
#endif
make distclean完重新对程序进行编译
重新设置环境变量的储存地址
根据saveenv命令,搜索可以知道 saveenv函数存在于common/env_nand.c下
查看common/makefile , 需要打开宏定开关,编译程序
COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o
查看env_nand.c下的saveenv函数可以知道还有几个宏需要定义
#define CONFIG_ENV_OFFSET 0x00040000 //环境变量保存的偏移地址
#define CONFIG_ENV_SIZE 0x20000 //环境变量的储存大小
#define CONFIG_ENV_RANGE 0x20000 //环境变量的储存范围
到这里就可以下载程序进行测试了 smdk2440.h
用上一节配置好的uboot的网卡进行烧写,然后复制到nor上进行测试(或者直接下配置好的uboot,然后用usb命令下载)
set ipaddr 192.168.2.5 设置单板ip
set serverip 192.168.2.2 设置服务器ip
set ethaddr 00:0c:29:6c:b9:36 设置网卡mac
tftp 30000000 uboot.bin 下载内核进行测试
protect off all
erase 0 3ffff //由于重新更改了uboot的大小
cp.b 30000000 0 40000
然后uboot启动后执行save命令后重启,就不会再有默认参数的报错
U-Boot 2012.04.01 (Sep 25 2019 - 19:43:19)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
Flash: 2 MiB
NAND: 256 MiB
In: serial
Out: serial
Err: serial
Net: dm9000
Hit any key to stop autoboot: 0
至此uboot的基本功能已经全部移植完了,有点细节问题就是当我们现在下载内核时,必须输入像nand erase 60000 200000这样的命令,输入地址太麻烦,可以在uboot中设置变量来代替这些地址
首先查看分区大小 mtdparts命令,但是现在还没有定义这个命令,搜索可以知道该命令实现在comomn/cmd_mtdparts.c 中,查看makefile,可以知道需要定义CONFIG_CMD_MTDPARTS宏,才能编译该文件,在头文件中加入该定义
COBJS-$(CONFIG_CMD_MTDPARTS) += cmd_mtdparts.o
然后查看mtdparts函数的是如何实现分区划分的,搜索mtdparts_init函数可以看出没有人在调用这个函数,所以我们需要自己手动调用这个函数,在borad.c的调用这个函数
mtdparts_init(); //分区显示初始化
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop();
}
然后分析 mtdparts_init()函数,搜索CONFIG_CMD_MTDPARTS,查看别的单板是怎么设置mtdparts的参数的,然后根据自己的单板修改参数
#define CONFIG_CMD_MTDPARTS
#define MTDIDS_DEFAULT "nand0=samsungJZ2440" /*表示的是哪一个设备*/
#define MTDPARTS_DEFAULT "mtdparts=samsungJZ2440:256K(uboot)," \ //分区参数 注意nand0和mtdparts的第一个参数要一样
"128K(params)," \
"2M(kernel)," \
"-(root)"
编译完成下载后,需要先手动输入mtdparts default,然后再测试命令是否正常
SMDK2410 # mtdparts
device nand0 , # parts = 4
#: name size offset mask_flags
0: uboot 0x00040000 0x00000000 0
1: params 0x00020000 0x00040000 0
2: kernel 0x00200000 0x00060000 0
3: root 0x0fda0000 0x00260000 0
active partition: nand0,0 - (uboot) 0x00040000 @ 0x00000000
defaults:
mtdids : nand0=jz2440-0
mtdparts: mtdparts=jz2440-0:256K(uboot),128K(params),2M(kernel),-(root)
这个时候如果不想自己手动输入mtdparts default命令,可以在程序中直接执行完mtdparts default命令 ,这个时候可以不再调用mtdparts_init()
run_command("mtdparts default",0);
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop();
}
这个时候我们就可以利用这些参数直接烧写内核等
nand erase.part kernel //擦除内核区域
nand write 30000000 kernel //将内核写到kernel分区
set bootcmd 'nand read 30000000 kernel;bootm 30000000 ' //读出内核启动