原文鏈接: https://blog.csdn.net/linux_0416/article/details/79637110
1.去掉啓動時的按鍵等待
U-boot 啓動的時候出現一個 Hit any key to stopautoboot 不爽,幹嗎要停上1秒?雖然可以通過設置參數bootdelay=0來關掉這個延時,但這樣做了以後就再也進不去U-boot了,更煩。檢查代碼,發現是在main.c函數intabortboot(int bootdelay)來幹這個活的,好吧,改掉它
static __inline__ intabortboot(int bootdelay)
{
int abort = 0;
char inputkey;
if(tstc())
{
inputkey =getc();
abort = (inputkey == 'u');
}
#ifdef CONFIG_SILENT_CONSOLE
if (abort)
gd->flags&= ~GD_FLG_SILENT;
#endif
return abort;
}
這樣,就不需要等待了,如果想進入U-boot,就在上電的時候按住u吧,把它改成一個固定的鍵而不是任意鍵,因爲串口線很容易受到干擾,如果是任意鍵的話,運行時即使不想進去有時也會進入U-boot的命令行。
2.去掉網卡的初始化
每次上電,U-boot都會初始化網卡,其實這根本不需要,把配置文件中
#define CONFIG_MII 1
去掉,啓動時就不會初始化了,需要使用TFTP時,它會自動初始化,又節省了3.4秒的啓動時間。
3.智能讀取OSImage
U-boot 通過nand read 來讀取OSImage,通常爲了避免麻煩,我們設置的讀取長度要比實際OS長度長一些,多讀的那部分純粹是浪費CPU時間,能不能精確判斷讀取長度呢,當然可以,爲了不影響系統的正常功能,擴展一個nandread.os 指令來讀取,修改方法如下:
在 nand_read_options_t裏面添加一個成員 int is_os_img
在函數 int do_nand(cmd_tbl_t* cmdtp, int flag, int argc, char *argv[])
修改讀操作的判斷語句,添加 !strcmp(s,".os"),然後設置opts.is_os_img = !strcmp(s, ".os");大概修改後結果參考第7步代碼。
最後,在函數intnand_read_opts(nand_info_t *meminfo, const nand_read_options_t*opts)中修改
代碼,檢測如果opts->is_os_img == 1並且是第一次讀取(2024B)之後,檢查度取得結果是否是OSImage,如果是更新需要讀取的長度,否則,也不需要再往下讀了,直接返回錯誤就可以了
image_header_t *hdr = (image_header_t*)buffer;
if(image_check_magic(hdr) &&image_check_hcrc (hdr))
{
size_t ossz= uimage_to_cpu(hdr->ih_size);//+image_get_header_size();
imglen =ossz + + image_get_header_size();
printf("##Find valid OS image, at 0x%x, Size: %d Bytes = %d KB\n",
(unsigned int)mtdoffset, ossz,ossz/1024);
}
else
{
printf("Invalid OS image at 0x%x\n", (unsignedint)mtdoffset);
return -1;
}
4.去掉OS Image內存複製過程
使用 nand read 讀取OS Image後,U-boot 使用 bootm 指令來啓動Linux,檢查其實現代碼
int do_bootm (cmd_tbl_t*cmdtp, int flag, int argc, char *argv[])
發現他會把已經讀取到內存中的OS Image在複製到一個指定的位置,OS Image 中的頭部參數,這個值一般是固定的,本系統使用的是 0x70008000, 如果在 nandread 時讀到的內存位置恰好合適,就可以省掉這些毫秒數了,做法如下:
nand read.os 0x70007FC0 0x100000 0x500000
(其中 0x70007FC0 =0x70008000 - sizeof(sizeof(image_header_t)))
然後在內存複製的地方(函數do_bootm中),加入修改,跳過內存複製
switch(comp) {
caseIH_COMP_NONE:
if(load_start == (ulong)os_hdr) {
printf(" XIP %s ... ",type_name);
}else{
//add=====start
if(load_start != os_data)//位置不匹配,依然移動,否則就跳過此部
{
printf(" Loading %s ... ",type_name);
memmove_wd((void *)load_start, (void *)os_data, os_len,CHUNKSZ);
puts("OK\n");
}
//add=====end
}
load_end =load_start + os_len;
對於我們的Kernel,修改後大小是1.4M,省去這個搬移過程,節省了大約800ms的時間
5.減少內存初始化的時間
在U-boot 初始化時,在start_armboot 函數中,多次使用到了memset函數,其中最耗時的是在mem_malloc_init函數中調用memset 初始化 512K內存的調用,檢查U-boot1.3.4對memset的實現,發現是最簡單的字節複製,把它改爲按32bits複製的方式,這些memset調用所花費的時間立即從202ms減少到了45ms
修改方法,再 string.c中,找到memset函數,修改其實現(代碼是從U-boot 2011.12 中複製過來的)
void * memset(void *s,int c,size_t count)
{
unsigned long *sl = (unsigned long *) s;
unsigned long cl = 0;
char *s8;
int i;
if ( ((ulong)s& (sizeof(*sl) - 1)) == 0) {
for (i = 0; i <sizeof(*sl); i++) {
cl<<= 8;
cl |= c & 0xff;
}
while (count>= sizeof(*sl)) {
*sl++ = cl;
count -= sizeof(*sl);
}
}
s8 = (char *)sl;
while (count--)
*s8++ = c;
return s;
}
6.減少NAND初始化時間
每次 U-boot啓動,發現NAND初始化需要大約3秒的時間,仔細追蹤發現,在nand_base.c文件中nand_scan函數的最後一步returnthis->scan_bbt(mtd);最花費時間,這個scan_bbt掃描整個NAND並檢查壞塊,重建壞塊表,在啓動過程中,這個耗時的操作毫無意義,去掉這一步,讓nand_scan函數直接返回0就可以了。
7.添加Yaffs2支持
從網上各位前輩的論述中,都發現YAFFS比JFFS2要快,也決定測試一下,從YAFFS網站下載最新的代碼,按照說明加入到Linux中,重新編譯內核,讓內核支持YAFFS2(按照默認的選項就可以了),弄一個空的分區,格式化成YAFFS2格式,感覺的確比較快,把ROOTFS複製到這個分區,然後修改Linux啓動參數讓它把YAFFS2分區當作根分區啓動,發現果然快了不少,初始化和掛載根分區僅需要370ms,比JFFS2的速度快多了,決定就採用YAFFS2作爲根文件系統了。自己在u-boot中添加對yaffs2image的支持
說起來容易,真正做起來還是很麻煩的,總是不能把yaffs2的image燒寫成功,不知道是Image不正確還是Uboot沒改對,折騰了幾天也沒搞定,最後終於發現了一個第三方的工具 http://code.google.com/p/yaffs2utils/
下載,編譯,製作Image,驗證,OK,把新工具生成的IMAGE與YAFFS2自帶的工具對照,發現YAFFS2自帶的工具生成的IMAGE不正確,暈死。
重新修改UBoot,改了很少一部份代碼,就可以了。
依然是在函數do_nand中修改,添加一個擴展nand write.y 指令來寫入Image:
按照慣例,YAFFS2的第一個塊不使用,留給文件系統自己使用,在 nand_write_options_t 裏面添加一個成員 intskip_first_block;
在函數 int do_nand(cmd_tbl_t* cmdtp, int flag, int argc, char *argv[])
修改讀寫操作的判斷語句,添加 !strcmp(s,".y"),然後設置opts.is_os_img = !strcmp(s, ".os");大概修改後結果如下(紅色部分)
s = strchr(cmd, '.');
//add -------|| !strcmp(s, ".os") || !strcmp(s,".y")
if (s !=NULL && (!strcmp(s, ".jffs2") ||!strcmp(s, ".e") || !strcmp(s, ".i") || !strcmp(s, ".os") || !strcmp(s,".y"))) {
if (read){
nand_read_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer =(u_char*) addr;
opts.length =size;
opts.offset =off;
opts.readoob= 0;//remove this function.
//add ====start
opts.is_os_img = !strcmp(s,".os");
//add ===end
opts.quiet = quiet;
ret =nand_read_opts(nand, &opts);
//printf("call nand_read_opts buffer %lu len %lu offset %d off, ret%d\n", addr, size, off, ret);
} else{
nand_write_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer =(u_char*) addr;
opts.length =size;