嵌入式Linux启动优化手记2 U…
既然不能使用新的U-boot,那就优化一点是一点,慢慢干吧。
1.去掉启动时的按键等待
U-boot 启动的时候出现一个 Hit any key to stop
autoboot 不爽,干吗要停上1秒?虽然可以通过设置参数bootdelay=0来关掉这个延时,但这样做了以后就再也进不去U-boot了,更烦。检查代码,发现是在main.c函数int
abortboot(int bootdelay)来干这个活的,好吧,改掉它
static __inline__ int
abortboot(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.智能读取OS
Image
U-boot 通过nand read 来读取OS
Image,通常为了避免麻烦,我们设置的读取长度要比实际OS长度长一些,多读的那部分纯粹是浪费CPU时间,能不能精确判断读取长度呢,当然可以,为了不影响系统的正常功能,扩展一个nand
read.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步代码。
最后,在函数int
nand_read_opts(nand_info_t *meminfo, const nand_read_options_t
*opts)中修改
代码,检测如果opts->is_os_img == 1
并且是第一次读取(2024B)之后,检查度取得结果是否是OS
Image,如果是更新需要读取的长度,否则,也不需要再往下读了,直接返回错误就可以了U-boot优化" TITLE="[转载]嵌入式Linux启动优化手记2 U-boot优化" />
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 KBn",
(unsigned int)mtdoffset, ossz,
ossz/1024);
}
else
{
printf("Invalid OS image at 0x%xn", (unsigned
int)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, 如果在 nand
read 时读到的内存位置恰好合适,就可以省掉这些毫秒数了,做法如下:
nand read.os 0x70007FC0
0x100000 0x500000
(其中 0x70007FC0 =
0x70008000 - sizeof(sizeof(image_header_t)))
然后在内存复制的地方(函数do_bootm中),加入修改,跳过内存复制
switch
(comp) {
case
IH_COMP_NONE:
if
(load_start == (ulong)os_hdr) {
printf
(" XIP %s ... ",
type_name);
} else
{
if
(load_start != os_data)//位置不匹配,依然移动,否则就跳过此部
{
printf
(" Loading %s ... ",
type_name);
memmove_wd
((void *)load_start, (void *)os_data, os_len,
CHUNKSZ);
puts("OKn");
}
}
load_end =
load_start + os_len;
对于我们的Kernel,修改后大小是1.4M,省去这个搬移过程,节省了大约800ms的时间
5.减少内存初始化的时间
在U-boot 初始化时,在
start_armboot 函数中,多次使用到了
memset函数,其中最耗时的是在mem_malloc_init函数中调用memset 初始化 512K内存的调用,检查U-boot
1.3.4对memset的实现,发现是最简单的字节复制,把它改为按32bits复制的方式,这些memset
调用所花费的时间立即从202ms减少到了45ms
修改方法,再 string.c
中,找到memset函数,修改其实现(代码是从U-boot 2011.12 中复制过来的U-boot优化" TITLE="[转载]嵌入式Linux启动优化手记2 U-boot优化" />)
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函数的最后一步return
this->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中添加对yaffs2
image的支持
说起来容易,真正做起来还是很麻烦的,总是不能把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 里面添加一个成员 int
skip_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, '.');
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.
opts.is_os_img = !strcmp(s,
".os");
opts.quiet
= quiet;
ret =
nand_read_opts(nand, &opts);
//printf("call nand_read_opts buffer %lu len %lu offset %d off, ret
%dn", addr, size, off, ret);
} else
{
nand_write_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer =
(u_char*) addr;
opts.length =
size;
opts.offset =
off;
if
(!strcmp(s, ".y"))
{
opts.pad =
0;
opts.writeoob =
1;
//opts.noecc
= 1;
opts.skip_first_block = 1;
opts.autoplace = 1;
}
else
{
opts.pad =
1;
}
opts.blockalign =
1;
opts.quiet
= quiet;
ret =
nand_write_opts(nand, &opts);
}
} else if (s
!= NULL && !strcmp(s, ".oob"))
{...}
在函数nand_write_opts中相应修改
int
nand_write_opts(nand_info_t *meminfo, const nand_write_options_t
*opts)
{
int yaffs_skip_first =
opts->skip_first_block;
...
while ((imglen > 0)
&& (mtdoffset <
meminfo->size)) {
...
while (blockstart != (mtdoffset &
(~erasesize_blockalign+1))) {
do {
...
} while
(offs < blockstart + erasesize_blockalign);
}
if (yaffs_skip_first)
{
yaffs_skip_first = 0;
mtdoffset +=
erasesize_blockalign;
continue;
}
readlen = meminfo->oobblock;
if
(opts->pad &&
(imglen < readlen))
...
}
...
}
8.
其它一些优化措施
经过这些折腾之后,整个系统的启动时间大大加快,然后优化Linux自身的一些启动瓶颈
Linux的启动参数优化:加上了
lpj=99072,节约了几十个毫秒,加上quiet,节约了大约1秒时间
修改内核编译选项,把不需要的内核模块干掉
最后,Linux自身的启动速度约为1.1秒,整个系统的启动速度大约4秒多一点,初步达到了优化目标,系统的主要延时发生在U-boot
1.3.4的FLASH读取上,FLASH读取速度大约只有600KB/S。尝试把Uboot
2011.12的FLASH驱动移植到U-boot
1.3.4上,花费了几天时间,终于可以编译成功了,可惜经常出一些莫名其妙的错误,太不稳定,只好放弃。
以我的能力,U-boot优化到这里就到头了,正准备结束工作时,发现了另外一条可以加速系统启动的方法
可以继续尝试,让我最终把系统的启动时间减少到了1.7秒。
请看下篇U-boot优化" TITLE="[转载]嵌入式Linux启动优化手记2 U-boot优化" />
嵌入式Linux启动优化手记2 U…的更多相关文章
- 嵌入式linux启动信息完全注释
嵌入式linux启动信息完全注释 from:http://www.embedlinux.cn/ShowPost.asp?ThreadID=377 摘要 我们在这里讨论的是对嵌入式linux系统的启动过 ...
- 嵌入式LINUX启动时间优化
1. 实践过程 我是对海思3559进行启动时间优化的.具体的操作可以参考<Hi3559V100/Hi3556V100 快速启动优化指南>.软件上启动时间的优化一般是从三方面进行的:ubbo ...
- 嵌入式Linux启动过程中的问题积累
嵌入式Linux启动过程中的问题积累 Dongas 07-12-19 1.Bad Magic Number ## Booting image at 33000000 ... Bad Magic Num ...
- 【转】嵌入式Linux启动配置文件及脚本
原文网址:http://blog.csdn.net/shuaishuai80/article/details/6202497 使用Busybox制作根文件系统时,/etc目录非常重要,它包含了嵌入式L ...
- 嵌入式Linux启动配置文件及脚本分…
使用Busybox制作根文件系统时,/etc目录非常重要,它包含了嵌入式Linux启动所需的配置文件及脚本.由于init进程,或者说linuxrc程序会解析inittab文件,因此就从/etc/ini ...
- 转:嵌入式linux启动时运行的inittab文件
嵌入式系统下的linux启动配置文件,不同与普通的PC linux启动配置,启动相关文件与文件的内容也要少得多.嵌入式系统下的linux启动过程一般是: 1 在bootloader中制定各种要 ...
- [转载]嵌入式linux启动时运行的inittab文件
源地址:https://www.cnblogs.com/yfz0/p/5853826.html 嵌入式系统下的linux启动配置文件,不同与普通的PC linux启动配置,启动相关文件与文件的内容也要 ...
- linux启动优化:mdev -s自从…
转载请说明出处:http://control.blog.sina.com.cn/admin/article/article_add.php 近期工作中遇到的问题如下: linux启动后加载根文件系统时 ...
- 基于bootsplash的嵌入式linux启动画面定制
来源: ChinaUnix博客 作者: ChinaUnix博客 发布时间:2007-01-01 16:29:00 摘 要:在基于linux的嵌入式仿真平台研发中,利用开源工具bootsplash能够定 ...
随机推荐
- ActionContext实现原理
StrutsPrepareAndExecuteFilter [http://www.tuicool.com/articles/NVNbYn] struts2 和 struts1 的一个重要区别就是它进 ...
- 安全清空废纸篓mac
在.bash_profile中加入: alias secureempty='sudo srm -rfvsz /Volumes/*/.Trashes/* ~/.Trash/*' 然后做终端输入:secu ...
- SDK中常用的工具
Android SDK包含了各种各样的定制工具,简介如下: 一.Android模拟器(Android Emulator )它是在你的计算机上运行的一个虚拟移动设备.你可以使用模拟器来在一个实际的And ...
- Django-进阶
分页 Django的分页器(paginator) view from django.shortcuts import render,HttpResponse # Create your views h ...
- Unity3D 自动寻路入门指南
所有用于成为NavMesh的网格都必须被指定为 Navigation Static . 方法如下,选中GameObject,然后在菜单栏的[Window]-[Navigation]-[Object]- ...
- WordPress 中文图片 上传 自动重命名
由于国人很少有在上传图片前将图片名重命名为英语的,所以自动重命名对于WP来说尤为重要,特别是LINUX的不支持中文名的. WordPress上传多媒体的代码都存放于\wp-admin\includes ...
- Dilworth 定理
主要是做个笔记 DAG 最长反链 = 最小链覆盖 反链:反链上任意两个点 $(u,v)$ ,$u$ 不能到 $v$,$v$ 也不能到 $u$ 最小链覆盖:选出若干可以相交的链,覆盖整张图,注意与“最小 ...
- Linux命令学习(20):traceroute命令
版权声明 更新:2017-06-13博主:LuckyAlan联系:liuwenvip163@163.com声明:吃水不忘挖井人,转载请注明出处! 1 文章介绍 本文介绍了Linux下面的mv命令. 2 ...
- java多线程 生产者消费者案例-虚假唤醒
package com.java.juc; public class TestProductAndConsumer { public static void main(String[] args) { ...
- CODE FESTIVAL 2017 qual A--C - Palindromic Matrix(模拟所有情况,注意细节)
个人心得:其实本来这题是有规律的不过当时已经将整个模拟过程都构思出来了,就打算试试,将每个字符和总和用优先队列 装起来,然后枚举每个点,同时进行位置标志,此时需要多少个点的时候拿出最大的和出来,若不满 ...