在上一章使uboot支持網卡傳輸文件后,但是每次啟機時,環境變量都要變為默認值,需要重新設置ip,MAC地址才行,由於沒有配置mtdparts命令,啟動內核也不成功
所以本章主要學習:
- 1)修改環境變量默認值
- 2)裁剪uboot
- 3)分區,設置mtdparts命令
1.修改之前,先來理解下uboot的環境參數
首先,uboot會去校驗(CRC)存放環境變量的一段空間 ,若CRC有效則使用該空間里的環境變量,無效則用默認的環境變量.
而我們移植的uboot,由於一直沒有使用save,所以沒有讀不出CRC校驗,使用的默認環境變量,如下圖所示:

2.來修改uboot的默認環境變量
(PS:uboot此時的內存分區還沒修改,所以每次設置環境后,不能用save保存,怕破壞掉nand里面的內容)
2.1搜索using default environment,找到位於set_default_env()函數:

從上面代碼可以看到, default_environment這個變量,這是個全局字符數組,從字面上就可知道,這個是默認環境變量數組,里面保存了各個環境值
2.2進入default_environment[]看看

這個數組比較長,所以只剪切一部分,其中MK_STR()的作用就是將數值轉換為字符串
這些都是環境參數,比如"bootargs="(環境變量里最重要的一個),里面會保存文件系統位置,控制台console等等
我們以bootargs為例:
在default_environment[]數組里,若CONFIG_BOOTARGS宏有值,便會組成一串字符串"bootargs=... ..."
比如在以前的uboot里,可以看到:
bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0 //root:指定文件系統位置 //init:指定內核啟動后執行的第一個應用程序 //console:指定使用哪個終端,比如串口0,使用ttySAC0
其它宏也是這樣.比如我們熟悉的有:
- "bootcmd=", 用來啟動內核的命令
- "bootdelay=",uboot啟動的倒計時,默認值為5S,只有設置了bootcmd,該倒計時才有用
- "baudrate=",波特率,默認為115200
- "ethaddr=",網卡的MAC地址(也叫物理地址)
- "ipaddr=",ip地址
- "serverip=",使用tftp時的服務器地址
- "netmask=",掩碼, 默認值為255.255.255.0
- "mtdparts=",mtd分區表
2.3所以接下來,便修改smdk2440.h里面與環境相關的宏
設置默認環境變量宏(位於include/configs/smdk2440.h):
#define CONFIG_BOOTARGS "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0" //bootargs #define CONFIG_BOOTCOMMAND "nand read 0x30000000 0x60000 0x200000; bootm 0x30000000" //bootcmd #define CONFIG_BOOTDELAY 10 //uboot 倒計時 #define CONFIG_NETMASK 255.255.255.0 //掩碼 #define CONFIG_IPADDR 192.168.2.103 //本機IP #define CONFIG_SERVERIP 192.168.2.101 //電腦IP #define CONFIG_ETHADDR 08:00:3e:26:0a:5b //MAC地址
其中bootcmd是隨意寫的,因為此時的內核位置還不確定放在哪(后面配置mtdparts命令后,會在4.6小節修改)
由於nand中要划分bootload空間、環境變量空間、內核空間、系統空間
而uboot就有400多k,所以我們需要裁剪uboot,裁剪后再來划分內存分區
3.裁剪uboot
uboot很多文件都是基於Makefile,里面通過判斷宏來加載文件.而宏大部分都定義在include/configs/smdk2440.h
3.1進入smdk2440.h,把不需要的功能的宏去掉,比如usb,文件系統,rtc等
1)去掉usb支持
/************************************************************ // * USB support (currently only works with D-cache off) // ************************************************************/
//#define CONFIG_USB_OHCI //#define CONFIG_USB_KEYBOARD //#define CONFIG_USB_STORAGE //#define CONFIG_DOS_PARTITION
2)去掉rtc支持
/************************************************************ // * RTC // ************************************************************/ //#define CONFIG_RTC_S3C24X0
3)去掉BOOTP選項
/* // * BOOTP options // */ //#define CONFIG_BOOTP_BOOTFILESIZE //#define CONFIG_BOOTP_BOOTPATH //#define CONFIG_BOOTP_GATEWAY //#define CONFIG_BOOTP_HOSTNAME
4)去掉部分不需要的命令行配置
// #define CONFIG_CMD_DHCP //動態主機配置協議命令行 // #define CONFIG_CMD_USB //USB命令行
5)去掉文件系統
/* // * 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_RBTR
3.2 編譯
由於屏蔽的宏在其它文件也會用到,而make在之前用過,再次make只會編譯修改過的文件.
所以輸入:
make clean make s3c2440config make
make后,打印以下錯誤:
common/libcommon.o: In function `do_date': /work/system/u-boot-2012.04.01/common/cmd_date.c:60: undefined reference to `rtc_reset' /work/system/u-boot-2012.04.01/common/cmd_date.c:63: undefined reference to `rtc_get' /work/system/u-boot-2012.04.01/common/cmd_date.c:72: undefined reference to `rtc_set' /work/system/u-boot-2012.04.01/common/cmd_date.c:81: undefined reference to `rtc_get' make: *** [u-boot] 錯誤 1
上面的cmd_date.c文件以及出錯變量rtc_xxx,從字面上來看顯然是與RTC有關,我們直接屏蔽該文件
通過Makefile,找到需要屏蔽宏CONFIG_CMD_DATE(宏定義位於include/configs/smdk2440.h):
![]()
屏蔽后,make成功,可以看到uboot只有200kb了:

接下來,便開始分區,使我們的環境變量能保存在uboot指定位置里
4.設置分區
以前,我們每次啟動內核時,都會打印以下分區信息:
Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit": 0x00000000-0x00040000 : "bootloader" //存放uboot 0x00040000-0x00060000 : "params" //存放環境變量 0x00060000-0x00260000 : "kernel" //存放內核 0x00260000-0x10000000 : "root" //存放文件系統
所以,我們新的uboot,還是照着這個來分區
還記得之前,我們每次設置了環境變量,都不敢用save命令來保存.
4.1所以我們通過sava -help命令,看它位於哪個文件,找到save命令相關宏
如下圖所示:

4.2然后在si里搜索saveenv
搜索如下圖所示:

可以發現,在env_flash.c 和env_nand.c這兩個文件都有saveenv()函數.
顯然env_flash.c的作用是,通過save命令將環境變量保存在nor flash.
而env_nand.c,是將環境變量保存在nand flash里.
4.3接下來在common/Makefile搜索,看看這兩個文件依賴哪兩個宏
如下圖所示:
![]()
![]()
4.4然后在smdk2440.h搜索這兩個宏,看看板卡默認配置的是不是env_nand.c
如下圖所示:

可以看到,smdk2440.h是將環境變量保存在nor flash,由於2440在nand啟動下是無法支持nor,所以我們需要屏蔽這三處宏,重新設置宏
4.5設置save相關宏
在其它板卡里搜索CONFIG_ENV_IS_IN_NAND,看看別人是怎么通過宏配置save的,然后在env_nand.c文件里搜索宏,來看宏是怎么用的
最終宏修改為如下所示(位於include/configs/smdk2440.h):
//#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000) //#define CONFIG_ENV_IS_IN_FLASH //#define CONFIG_ENV_SIZE 0x10000 #define CONFIG_ENV_SIZE 0x20000 //環境變量空間大小 #define CONFIG_ENV_IS_IN_NAND #define CONFIG_ENV_OFFSET 0x40000 //位於0x40000~(0X40000+0x20000) #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE //環境變量的擦除范圍,要>=SIZE
上面的CONFIG_ENV_RANGE宏,其實不定義,內核也會自動定義(位於env_nand.c):

然后重新編譯新的uboot,就可以使用save命令保存環境變量了.
接着我們燒寫內核:
tftp 30000000 uImage nand erase 60000 200000 nand write 30000000 60000 200000 //保存在內核分區里 bootm 30000000 //啟動內核
從這里,看出燒個內核還需要記錄這些分區空間地址,非常麻煩
4.6 設置mtdparts命令(在舊版uboot里,是mtd命令)
其實,我們可以使用mtdparts命令,通過分區名字來代替這些地址,比如以前的uboot,直接輸入:
nand erase kernel //這個kernel名字就等於: 60000 200000 nand write 30000000 kernel //這個kernel名字就等於: 60000 200000
由於smdk2440板卡里沒有配置mtdparts命令,所以步驟如下所示:
1)搜索mtdparts,發現位於common/cmd_mtdparts.c
2) 在common/Makefile搜索,找到cmd_mtdparts.c文件依賴CONFIG_CMD_MTDPARTS宏

3)在其它板卡里搜索CONFIG_CMD_MTDPARTS,看看別人是怎么通過宏配置nand的,別人寫的配置如下所示:

- "-":表示剩余空間都是文件系統。
(PS:當執行mtdparts default命令時,uboot就會檢測是否有CONFIG_CMD_MTDPARTS宏,然后再根據上面的MTDPARTS_DEFAULT宏保存的mtd分區信息,來將nand和nor分區)
4)設置mtdparts相關宏
接下來,便復制上面的宏到smdk2440.h中,改為:
/*----------------------------------------------------------------------- * mtdparts */ #define CONFIG_CMD_MTDPARTS #define CONFIG_MTD_DEVICE #define MTDIDS_DEFAULT "nand0=smdk2440-0" #define MTDPARTS_DEFAULT "mtdparts=smdk2440-0:256k(u-boot)," \ "128k(params)," \ "2m(kernel)," \ "-(rootfs)" \
然后重新修改,之前設置的環境參數bootcmd(位於smdk2440.h):
將
#define CONFIG_BOOTCOMMAND "nand read 0x30000000 0x60000 0x200000; bootm 0x30000000" //bootcmd
改為:
#define CONFIG_BOOTCOMMAND "nand read 0x30000000 kernel; bootm 0x30000000" //bootcmd
5)修改好后,我們還需要在board_init_r()函數里的for(;;)前面添加(位於arch/arm/lib/board.c):
run_command("mtdparts default", 0); //添加此處代碼 for (;;) { main_loop(); }
這樣uboot每次啟動時,都會執行一次mtdparts default命令,使它根據默認參數來自動分區.
mtdparts命令就此設置好了
接下來,便重新燒寫uboot,來測試
5.測試mtdparts分區
輸入mtdparts,查看默認分區名稱:

如上圖所示,接下來我們便可以直接使用kernel名字來擦除kernel分區,並燒寫內核了
步驟如下:
tftp 30000000 uImage nand erase.part kernel //等於nand erase 200000 60000 nand write 30000000 kernel //從sdram拷貝到nand
接下來,下章來使uboot支持yaffs及制作補丁
