Linux 嵌入式启动以及优化(Z)
生活随笔
收集整理的這篇文章主要介紹了
Linux 嵌入式启动以及优化(Z)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Original address:?http://blog.21ic.com/user1/5593/archives/2010/67071.html
以前寫了一篇Linux PC啟動過程的日記,最近項目中,想優化一下啟動過程,減少啟動時間.因此研究了我們項目的啟動全過程.第一步: BootLoader -- U boot1 在cpu/arm926ejs/start.s中a) b reset ; //jump to resetb) set cpsr ;svc mode ,disable I,F interruptc)調用lowlevel_init? (在board\xxxx\lowlevel_init.S中將調用 __platform_cmu_init (設置cpu時鐘,啟動那些模塊等)??__platform_mpmc_init (mpmc初始化,配置SDRAM時序)__platform_static_memory_init__platform_static_uart_init__platform_mpmc_cleard) 用LDMIA,STMIA命令 copy uboot 到內存中e) ldr pc ,_start_armboot執行start_armboot2 start_armboot 在 lib-arm中a)根據init_sequence 執行初始化序列包括:cpu_initboard_init中斷初始化initialize environmentinitialze baudrate settingsserial communications setup打印uboot 版本display_dram_config (打印DRAM大小)而在board_init中將打印公司名稱 ,前后還加了delaytimer 初始化dw_init --- I2C 設置驗證時鐘來源 (來自wifi還是DECT)LCD初始化鍵盤初始化Flash 初始化? (空函數)網卡初始化?? (其中有個udelay(1000) 1ms的delay )b)??NOR FLASH 初始化display_flash_config (打印Flash大小)c) nand 初始化 (將scan整個nand chip,建立 bbt table)d)? env_relocate 環境變量重新定位到內存中e) 得到IP 地址和網卡 MAC地址f)? devices_initg) 中斷enable然后:??? start_armboot --> main_loop3 main_loop在 common/main.c中getenv("bootdelay")--> 循環 readlinerun_command
第二步: Kernela) Kernel自解壓 arch\arm\boot\compressed\head.S中調用decompress_kernel(misc.c),完了打印出"done,booting the kernel"然后根據arch_id = 多少,打印出 arch_idb) 在arch\arm\kernel\head.S中check cpu 以及 machine IDbuild the initial 頁表_switch_data (arm\kernel\head_common.s中) 將process id存入process_id變量中start_kernel
c) start_kernel1) 打印Linux version information2) call setup_arch,(它將打印cpu特定的信息,machinelook_machine_type ->arm\tools\mach_typeslook_processor_type --> .proc.info.init. -->arm\mm\proc_arm926.S在 /arm\mach_xx\xx.c中,有MACHINE_START(....)3) 打印commnad_line4) 初始化
vfs_caches_init虛擬文件系統VFS初始化,主要初始化dentry等,它將調用 mnt_init. 而mnt_init將調用init_rootfs,注冊rootfs文件系統,init_mount_tree()創建rootfs文件系統,會把rootfs掛載到/目錄.
5) rest_init啟動init kernel thread在init 線程中:1)populate_rootfs()函數負責加載initramfs.我們的系統沒有定義CONFIG_BLK_DEV_INITRD,因此populate_rootfs什么也沒做
2) do_basic_setup-->driver_init()->platform_bus_init()->...初始化platform bus(虛擬總線)這樣以后設備向內核注冊的時候platform_device_register()->platform_device_add()->...內核把設備掛在虛擬的platform bus下,
驅 動注冊的時候 platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev() 對每個掛在虛擬的platform bus的設備作 __driver_attach()->driver_probe_device()->drv->bus->match()==platform_match()-& gt;比較strncmp(pdev->name, drv->name, BUS_ID_SIZE),如果相符就調用platform_drv_probe()->driver->probe(),如果probe成 功則綁定該設備到該驅動.好象聲卡怎么先注冊驅動,再注冊設備呢?反了?-->do_initcalls而do_initcalls將調用__initcall_start到__initcall_end中的所有函數__initcall_start和__initcall_end定義在arch/arm/kernel/vmlinux.lds.S中它是這樣定義的:__initcall_start = .;
???*(.initcall1.init)
???*(.initcall2.init)
???*(.initcall3.init)
???*(.initcall4.init)
???*(.initcall5.init)
???*(.initcall6.init)
???*(.initcall7.init)
??__initcall_end = .;而在include/linux/init.h中#define core_initcall(fn)??__define_initcall("1",fn)
#define postcore_initcall(fn)??__define_initcall("2",fn)
#define arch_initcall(fn)??__define_initcall("3",fn)
#define subsys_initcall(fn)??__define_initcall("4",fn)
#define fs_initcall(fn)???__define_initcall("5",fn)
#define device_initcall(fn)??__define_initcall("6",fn)
#define late_initcall(fn)??__define_initcall("7",fn)其中#define __define_initcall(level,fn) \
?static initcall_t __initcall_##fn __attribute_used__ \
?__attribute__((__section__(".initcall" level ".init"))) = fn這說明core_initcall宏的作用是將函數指針(注意不是函數體本身)將放在.initcall1.init section 中,而device_initcall宏將函數指針將放在.initcall6.init section 中.函數本身用_init標識,在include/linux/init.h中#define __init??__attribute__ ((__section__ (".init.text")))這些_init函數將放在.init.text這個區段內.函數的擺放順序是和鏈接的順序有關的,是不確定的。因此函數的調用順序是:core_initcallpostcore_initcall 如amba_initarch_init???????? 如subsys_initcall??fs_initcalldevice_initcall ---> module_initlate_initcall先調用core_initcall區段中的函數,最后調用late_initcall中的函數,而對于上述7個區段中每個區段中的函數指針,由于其擺放順序和鏈接的順序有關的,是不確定的,因此其調用順序也是不確定的.
3) rootfs 加載prepare_namespace 掛載真正的根文件系統,在do_mounts.c中:static int __init root_dev_setup(char *line)
{
?strlcpy(saved_root_name, line, sizeof(saved_root_name));
?return 1;
}__setup("root=", root_dev_setup);也就是說:在bootargs中root=/dev/nfs rw 或者root=/dev/mtdblock4等將傳入saved_root_name.void __init prepare_namespace(void)
{
?int is_floppy;mount_devfs();if (root_delay) {
??printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
???????? root_delay);
??ssleep(root_delay);
?}md_run_setup();if (saved_root_name[0]) {
??root_device_name = saved_root_name;?//保存在root_device_name中
??ROOT_DEV = name_to_dev_t(root_device_name);//在root_dev.h中定義了Root_NFS,Root_RAM0等結點號
??if (strncmp(root_device_name, "/dev/", 5) == 0)
???root_device_name += 5;
?}is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;if (initrd_load())
??goto out;if (is_floppy && rd_doload && rd_load_disk(0))
??ROOT_DEV = Root_RAM0;mount_root();?????????????????????//加載rootfs
out:
?umount_devfs("/dev");
?sys_mount(".", "/", NULL, MS_MOVE, NULL);
?sys_chroot(".");
?security_sb_post_mountroot();
?mount_devfs_fs ();
}
4)yaffs2_read_super被調用來建立文件系統,它scan所有的block
5) free_initmem釋放init 內存6)打開/dev/console失敗則會打印:printk(KERN_WARNING "Warning: unable to open an initial console.\n");
7) 判斷是否有execute_command,這個參數是在uboot參數的bootargs中init=xxx ,如果定義了的話 則執行?run_init_process(execute_command).可以通過這種方法實現自己的init process,或者可以init=/linuxrc?,這樣執行linuxrc
8) 如果沒有execute_command,init kernel線程缺省的也是最后的步驟是:run_init_process("/sbin/init");
?run_init_process("/etc/init");
?run_init_process("/bin/init");
?run_init_process("/bin/sh");
如果/sbin/init沒有,則執行/etc/init.?/etc/init沒有則執行/bin/init ,如果這四者都沒有,則Linux打印panic("No init found.? Try passing init= option to kernel.");
第三步: Init Processrun_init_process也就是調用execve,這樣就啟動了init process上面的/sbin/init,/etc/init,/bin/init,/bin/sh這四者都指向busybox ,但對于/bin/sh則只是打開shell,然后等待用戶命令.而對于/sbin/init ,將分析/etc/inittab.在/etc/inittab中,1) id:5:initdefault:??????? 缺省的runlevel x2) si::sysinit:/etc/init.d/rcS
?????? 執行 rcS腳本
?3) l5:5:wait:/etc/init.d/rc 5
4)S:2345:respawn:/sbin/getty 38400 ttyDW0
getty 提示用戶輸入username ,然后調用login,login的參數為username ,登錄后啟動了shell
?如果修改為 /bin/sh 則直接啟動shell,此時你可以輸入命令 比如ls
在/etc/init.d/rcS中?
?? a) mount proc 文件系統
? b) /etc/default/rcS (設置一些參數)
?c)exec /etc/init.d/rc S?
???? 執行 /etc/init.d/rc S -->這樣將執行/etc/rcS.d中以S開頭的腳本??
???? S00psplash.sh??????????????? psplash?
??? S02banner.sh????????????????? make node /dev/tty
?? S03sysfs.sh??????????????????? mount sysfs?
??? S03udev?????????????????????? 啟動udev
?? S06alignment.sh??????????????為什么為3?
? S10checkroot.sh?????????????? 讀取fatab ,mount 這些文件系統
? S20modutils.sh??????????????? 加載module?
?S35mountall.sh????????????????? 不做什么事情
S37populate-volatile.sh
S38devpts.sh?????????????????????mount devpts File System
S39hostname.sh????????????????? set hostname to /etc/hostname
S40networking?????????????????? ifup -a to up the lo interface
S45mountnfs.sh????????????????? read /etc/fstab to?whether ?NFS existsand then mount the NFS
S55bootmisc.sh?????????????????? 調用/etc/init.d/hwclock.sh去設置時間,日期等
S60ldconfig.sh?????????????????? ldconfig建立庫的路徑
?l5:5:wait:/etc/init.d/rc 5將執行 /etc/rc5.d/ 依次為:
S00qpe??????????????????????????????? 啟動qpe
S02dbus-1????????????????????????? D_BUS? dameon?
S10dropbear????????????????????? SSH service
S20cron???????????????????????????? 自動執行指定任務的程序 cron , in etc/crontab , ntpd will run to get the NTP time
S20ntpd????????????????????????????? Not used ,? should delete
S20syslog????????????????????????? run /sbin/klogd
S39wifiinit.sh???????????????? wifi init and calibration?
S70regaccess????????????????? mknod regaccess.ko
S99rmnologin.sh????????????? do nothing since DELAYLOGIN = no in /etc/default/rcS
整個系統啟動后 ,將有 25 個進程 :其中12個內核的進程 ,13個用戶進程
? 1 root?????? 1488 S?? init [5]???
??? 2 root??????????? SWN [ksoftirqd/0]
??? 3 root??????????? SW< [events/0]
??? 4 root??????????? SW< [khelper]
??? 5 root??????????? SW< [kthread]
?? 12 root??????????? SW< [kblockd/0]
?? 13 root??????????? SW< [kseriod]
?? 41 root??????????? SW? [pdflush]
?? 42 root??????????? SW? [pdflush]
?? 43 root??????????? SW? [kswapd0]
?? 44 root??????????? SW< [aio/0]
? 152 root??????????? SW? [mtdblockd]
? 208 root?????? 1700 S < /sbin/udevd -d?
? 343 root????? 36104 S?? qpe?
? 357 messagebus?? 2080 S?? /usr/bin/dbus-daemon --system?
? 361 root?????? 2072 S?? /usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host
? 364 root?????? 1656 S?? /usr/sbin/cron?
? 369 root?????? 2712 S?? /sbin/klogd -n?
? 394 root?????? 2884 S?? -sh?
? 400 root????? 20396 S?? /opt/Qtopia/bin/MainMenu -noshow?
? 401 root????? 19196 S?? /opt/Qtopia/bin/Settings -noshow?
? 402 root????? 20504 S?? /opt/Qtopia/bin/Organizer -noshow?
? 403 root????? 20068 S?? /opt/Qtopia/bin/Photo -noshow?
? 404 root????? 34488 S N /opt/Qtopia/bin/quicklauncher?
? 411 root????? 34488 S N /opt/Qtopia/bin/quicklauncher?
優化:uboot :1)?setenv bootcmd1 "nand read.jffs2 0x62000000 kernel 0x180000 ; bootm 62000000"
這樣 load內核的時候 從以前0x300000的3M->1.5M 省1S
2)setenv bootdelay 1 從2變為0 加上CONFIG_ZERO_BOOTDELAY_CHECK?
3) quiet=1
bootargs=root=/dev/mtdblock4 rootfstype=yaffs2 console=ttyDW0 mem=64M mtdparts=dwnand:3m(kernel),3m(splash),64m(rootfs),-(userdata);dwflash.0:384k(u-boot),128k(u-boot_env) quiet
加上quiet 省不到1S4)啟動的時候不掃描整個芯片的壞塊,因為uboot只會用到kernel和splash區,只需要檢驗這兩個區的壞塊。
? 可以省不到 0.2s ,沒什么明顯的改進?
5) 將環境變量verify 設置為n ,這樣load kernel 后,不會去計算校驗 kernel image的checksum?
6)開始打印公司 這些可以去掉 ,在這里還有delay ,以及其他的一些不必要的打印 ,一起去掉
7)修改memcpy函數 在./lib_generic/string.c下:
/* Nonzero if either X or Y is not aligned on a "long" boundary.? */
#define UNALIGNED(X, Y) \
? (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
/* How many bytes are copied each iteration of the 4X unrolled loop.? */
#define BIGBLOCKSIZE??? (sizeof (long) << 2)
/* How many bytes are copied each iteration of the word copy loop.? */
#define LITTLEBLOCKSIZE (sizeof (long))
/* Threshhold for punting to the byte copier.? */
#define TOO_SMALL(LEN)? ((LEN) < BIGBLOCKSIZE)
void * memcpy(void * dst0,const void *src0,size_t len0)
{
? char *dst = dst0;
? const char *src = src0;
? long *aligned_dst;
? const? long *aligned_src;
? int?? len =? len0;
? /* If the size is small, or either SRC or DST is unaligned,
???? then punt into the byte copy loop.? This should be rare.? */
? if (!TOO_SMALL(len) && !UNALIGNED (src, dst))
??? {
????? aligned_dst = (long*)dst;
????? aligned_src = (long*)src;
????? /* Copy 4X long words at a time if possible.? */
????? while (len >= BIGBLOCKSIZE)
??????? {
????????? *aligned_dst++ = *aligned_src++;
????????? *aligned_dst++ = *aligned_src++;
????????? *aligned_dst++ = *aligned_src++;
????????? *aligned_dst++ = *aligned_src++;
????????? len -= BIGBLOCKSIZE;
??????? }
????? /* Copy one long word at a time if possible.? */
????? while (len >= LITTLEBLOCKSIZE)
??????? {
????????? *aligned_dst++ = *aligned_src++;
????????? len -= LITTLEBLOCKSIZE;
??????? }
?????? /* Pick up any residual with a byte copier.? */
????? dst = (char*)aligned_dst;
????? src = (char*)aligned_src;
??? }
? while (len--)
??? *dst++ = *src++;
? return dst0;
}
(在linux 中,arm 的memcpy 有優化的版本 , 在/arch/arm/lib/memcpy.S中)
下面2個建議,沒試過:8)在環境變量區的末尾, 存有CRC,啟動的時候會校驗CRC ,去掉可以省一些時間9)把一些驅動的初始化在正常啟動的時候不執行,當用戶按了鍵,進入uboot命令模式的時候執行
10) 修改SDRAM控制器時序
Kernel :
啟動時間 有兩種方法 :
1 在u-boot的 bootargs 中加上參數 time?
2 在內核的 kernel hacking 中 選擇 PRINTK_TIME
方法2的好處是可以得到內核在解析command_line 前所有信息的時間,而之前會有:打印linux 版本信息,CPU D cache , I cache 等等 。。。
啟動完后 用 :
dmesg -s 131072 > ktime
然后用 :
/usr/src/linux-x.xx.xx/s/show_delta ktime > dtime
這樣得到啟動內核時間的報告?
1)修改Nand驅動 提高讀速度2)從 JFFS2 換成 yaffs
3)kernel變為非壓縮的image ,但這樣的話內核變大了,從NAND中搬運內核的時間將變長 ,所以需要測試是否
?? 使得時間變短
建議:
4)把delay的 calibration 去掉?
?
上面改動后 基本上8s從開機到 Freeing init memory?
Application :
1 udev 啟動 很花時間
2 安排好啟動順序。
以前寫了一篇Linux PC啟動過程的日記,最近項目中,想優化一下啟動過程,減少啟動時間.因此研究了我們項目的啟動全過程.第一步: BootLoader -- U boot1 在cpu/arm926ejs/start.s中a) b reset ; //jump to resetb) set cpsr ;svc mode ,disable I,F interruptc)調用lowlevel_init? (在board\xxxx\lowlevel_init.S中將調用 __platform_cmu_init (設置cpu時鐘,啟動那些模塊等)??__platform_mpmc_init (mpmc初始化,配置SDRAM時序)__platform_static_memory_init__platform_static_uart_init__platform_mpmc_cleard) 用LDMIA,STMIA命令 copy uboot 到內存中e) ldr pc ,_start_armboot執行start_armboot2 start_armboot 在 lib-arm中a)根據init_sequence 執行初始化序列包括:cpu_initboard_init中斷初始化initialize environmentinitialze baudrate settingsserial communications setup打印uboot 版本display_dram_config (打印DRAM大小)而在board_init中將打印公司名稱 ,前后還加了delaytimer 初始化dw_init --- I2C 設置驗證時鐘來源 (來自wifi還是DECT)LCD初始化鍵盤初始化Flash 初始化? (空函數)網卡初始化?? (其中有個udelay(1000) 1ms的delay )b)??NOR FLASH 初始化display_flash_config (打印Flash大小)c) nand 初始化 (將scan整個nand chip,建立 bbt table)d)? env_relocate 環境變量重新定位到內存中e) 得到IP 地址和網卡 MAC地址f)? devices_initg) 中斷enable然后:??? start_armboot --> main_loop3 main_loop在 common/main.c中getenv("bootdelay")--> 循環 readlinerun_command
第二步: Kernela) Kernel自解壓 arch\arm\boot\compressed\head.S中調用decompress_kernel(misc.c),完了打印出"done,booting the kernel"然后根據arch_id = 多少,打印出 arch_idb) 在arch\arm\kernel\head.S中check cpu 以及 machine IDbuild the initial 頁表_switch_data (arm\kernel\head_common.s中) 將process id存入process_id變量中start_kernel
c) start_kernel1) 打印Linux version information2) call setup_arch,(它將打印cpu特定的信息,machinelook_machine_type ->arm\tools\mach_typeslook_processor_type --> .proc.info.init. -->arm\mm\proc_arm926.S在 /arm\mach_xx\xx.c中,有MACHINE_START(....)3) 打印commnad_line4) 初始化
vfs_caches_init虛擬文件系統VFS初始化,主要初始化dentry等,它將調用 mnt_init. 而mnt_init將調用init_rootfs,注冊rootfs文件系統,init_mount_tree()創建rootfs文件系統,會把rootfs掛載到/目錄.
5) rest_init啟動init kernel thread在init 線程中:1)populate_rootfs()函數負責加載initramfs.我們的系統沒有定義CONFIG_BLK_DEV_INITRD,因此populate_rootfs什么也沒做
2) do_basic_setup-->driver_init()->platform_bus_init()->...初始化platform bus(虛擬總線)這樣以后設備向內核注冊的時候platform_device_register()->platform_device_add()->...內核把設備掛在虛擬的platform bus下,
驅 動注冊的時候 platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev() 對每個掛在虛擬的platform bus的設備作 __driver_attach()->driver_probe_device()->drv->bus->match()==platform_match()-& gt;比較strncmp(pdev->name, drv->name, BUS_ID_SIZE),如果相符就調用platform_drv_probe()->driver->probe(),如果probe成 功則綁定該設備到該驅動.好象聲卡怎么先注冊驅動,再注冊設備呢?反了?-->do_initcalls而do_initcalls將調用__initcall_start到__initcall_end中的所有函數__initcall_start和__initcall_end定義在arch/arm/kernel/vmlinux.lds.S中它是這樣定義的:__initcall_start = .;
???*(.initcall1.init)
???*(.initcall2.init)
???*(.initcall3.init)
???*(.initcall4.init)
???*(.initcall5.init)
???*(.initcall6.init)
???*(.initcall7.init)
??__initcall_end = .;而在include/linux/init.h中#define core_initcall(fn)??__define_initcall("1",fn)
#define postcore_initcall(fn)??__define_initcall("2",fn)
#define arch_initcall(fn)??__define_initcall("3",fn)
#define subsys_initcall(fn)??__define_initcall("4",fn)
#define fs_initcall(fn)???__define_initcall("5",fn)
#define device_initcall(fn)??__define_initcall("6",fn)
#define late_initcall(fn)??__define_initcall("7",fn)其中#define __define_initcall(level,fn) \
?static initcall_t __initcall_##fn __attribute_used__ \
?__attribute__((__section__(".initcall" level ".init"))) = fn這說明core_initcall宏的作用是將函數指針(注意不是函數體本身)將放在.initcall1.init section 中,而device_initcall宏將函數指針將放在.initcall6.init section 中.函數本身用_init標識,在include/linux/init.h中#define __init??__attribute__ ((__section__ (".init.text")))這些_init函數將放在.init.text這個區段內.函數的擺放順序是和鏈接的順序有關的,是不確定的。因此函數的調用順序是:core_initcallpostcore_initcall 如amba_initarch_init???????? 如subsys_initcall??fs_initcalldevice_initcall ---> module_initlate_initcall先調用core_initcall區段中的函數,最后調用late_initcall中的函數,而對于上述7個區段中每個區段中的函數指針,由于其擺放順序和鏈接的順序有關的,是不確定的,因此其調用順序也是不確定的.
3) rootfs 加載prepare_namespace 掛載真正的根文件系統,在do_mounts.c中:static int __init root_dev_setup(char *line)
{
?strlcpy(saved_root_name, line, sizeof(saved_root_name));
?return 1;
}__setup("root=", root_dev_setup);也就是說:在bootargs中root=/dev/nfs rw 或者root=/dev/mtdblock4等將傳入saved_root_name.void __init prepare_namespace(void)
{
?int is_floppy;mount_devfs();if (root_delay) {
??printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
???????? root_delay);
??ssleep(root_delay);
?}md_run_setup();if (saved_root_name[0]) {
??root_device_name = saved_root_name;?//保存在root_device_name中
??ROOT_DEV = name_to_dev_t(root_device_name);//在root_dev.h中定義了Root_NFS,Root_RAM0等結點號
??if (strncmp(root_device_name, "/dev/", 5) == 0)
???root_device_name += 5;
?}is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;if (initrd_load())
??goto out;if (is_floppy && rd_doload && rd_load_disk(0))
??ROOT_DEV = Root_RAM0;mount_root();?????????????????????//加載rootfs
out:
?umount_devfs("/dev");
?sys_mount(".", "/", NULL, MS_MOVE, NULL);
?sys_chroot(".");
?security_sb_post_mountroot();
?mount_devfs_fs ();
}
4)yaffs2_read_super被調用來建立文件系統,它scan所有的block
5) free_initmem釋放init 內存6)打開/dev/console失敗則會打印:printk(KERN_WARNING "Warning: unable to open an initial console.\n");
7) 判斷是否有execute_command,這個參數是在uboot參數的bootargs中init=xxx ,如果定義了的話 則執行?run_init_process(execute_command).可以通過這種方法實現自己的init process,或者可以init=/linuxrc?,這樣執行linuxrc
8) 如果沒有execute_command,init kernel線程缺省的也是最后的步驟是:run_init_process("/sbin/init");
?run_init_process("/etc/init");
?run_init_process("/bin/init");
?run_init_process("/bin/sh");
如果/sbin/init沒有,則執行/etc/init.?/etc/init沒有則執行/bin/init ,如果這四者都沒有,則Linux打印panic("No init found.? Try passing init= option to kernel.");
第三步: Init Processrun_init_process也就是調用execve,這樣就啟動了init process上面的/sbin/init,/etc/init,/bin/init,/bin/sh這四者都指向busybox ,但對于/bin/sh則只是打開shell,然后等待用戶命令.而對于/sbin/init ,將分析/etc/inittab.在/etc/inittab中,1) id:5:initdefault:??????? 缺省的runlevel x2) si::sysinit:/etc/init.d/rcS
?????? 執行 rcS腳本
?3) l5:5:wait:/etc/init.d/rc 5
4)S:2345:respawn:/sbin/getty 38400 ttyDW0
getty 提示用戶輸入username ,然后調用login,login的參數為username ,登錄后啟動了shell
?如果修改為 /bin/sh 則直接啟動shell,此時你可以輸入命令 比如ls
在/etc/init.d/rcS中?
?? a) mount proc 文件系統
? b) /etc/default/rcS (設置一些參數)
?c)exec /etc/init.d/rc S?
???? 執行 /etc/init.d/rc S -->這樣將執行/etc/rcS.d中以S開頭的腳本??
???? S00psplash.sh??????????????? psplash?
??? S02banner.sh????????????????? make node /dev/tty
?? S03sysfs.sh??????????????????? mount sysfs?
??? S03udev?????????????????????? 啟動udev
?? S06alignment.sh??????????????為什么為3?
? S10checkroot.sh?????????????? 讀取fatab ,mount 這些文件系統
? S20modutils.sh??????????????? 加載module?
?S35mountall.sh????????????????? 不做什么事情
S37populate-volatile.sh
S38devpts.sh?????????????????????mount devpts File System
S39hostname.sh????????????????? set hostname to /etc/hostname
S40networking?????????????????? ifup -a to up the lo interface
S45mountnfs.sh????????????????? read /etc/fstab to?whether ?NFS existsand then mount the NFS
S55bootmisc.sh?????????????????? 調用/etc/init.d/hwclock.sh去設置時間,日期等
S60ldconfig.sh?????????????????? ldconfig建立庫的路徑
?l5:5:wait:/etc/init.d/rc 5將執行 /etc/rc5.d/ 依次為:
S00qpe??????????????????????????????? 啟動qpe
S02dbus-1????????????????????????? D_BUS? dameon?
S10dropbear????????????????????? SSH service
S20cron???????????????????????????? 自動執行指定任務的程序 cron , in etc/crontab , ntpd will run to get the NTP time
S20ntpd????????????????????????????? Not used ,? should delete
S20syslog????????????????????????? run /sbin/klogd
S39wifiinit.sh???????????????? wifi init and calibration?
S70regaccess????????????????? mknod regaccess.ko
S99rmnologin.sh????????????? do nothing since DELAYLOGIN = no in /etc/default/rcS
整個系統啟動后 ,將有 25 個進程 :其中12個內核的進程 ,13個用戶進程
? 1 root?????? 1488 S?? init [5]???
??? 2 root??????????? SWN [ksoftirqd/0]
??? 3 root??????????? SW< [events/0]
??? 4 root??????????? SW< [khelper]
??? 5 root??????????? SW< [kthread]
?? 12 root??????????? SW< [kblockd/0]
?? 13 root??????????? SW< [kseriod]
?? 41 root??????????? SW? [pdflush]
?? 42 root??????????? SW? [pdflush]
?? 43 root??????????? SW? [kswapd0]
?? 44 root??????????? SW< [aio/0]
? 152 root??????????? SW? [mtdblockd]
? 208 root?????? 1700 S < /sbin/udevd -d?
? 343 root????? 36104 S?? qpe?
? 357 messagebus?? 2080 S?? /usr/bin/dbus-daemon --system?
? 361 root?????? 2072 S?? /usr/sbin/dropbear -r /etc/dropbear/dropbear_rsa_host
? 364 root?????? 1656 S?? /usr/sbin/cron?
? 369 root?????? 2712 S?? /sbin/klogd -n?
? 394 root?????? 2884 S?? -sh?
? 400 root????? 20396 S?? /opt/Qtopia/bin/MainMenu -noshow?
? 401 root????? 19196 S?? /opt/Qtopia/bin/Settings -noshow?
? 402 root????? 20504 S?? /opt/Qtopia/bin/Organizer -noshow?
? 403 root????? 20068 S?? /opt/Qtopia/bin/Photo -noshow?
? 404 root????? 34488 S N /opt/Qtopia/bin/quicklauncher?
? 411 root????? 34488 S N /opt/Qtopia/bin/quicklauncher?
優化:uboot :1)?setenv bootcmd1 "nand read.jffs2 0x62000000 kernel 0x180000 ; bootm 62000000"
這樣 load內核的時候 從以前0x300000的3M->1.5M 省1S
2)setenv bootdelay 1 從2變為0 加上CONFIG_ZERO_BOOTDELAY_CHECK?
3) quiet=1
bootargs=root=/dev/mtdblock4 rootfstype=yaffs2 console=ttyDW0 mem=64M mtdparts=dwnand:3m(kernel),3m(splash),64m(rootfs),-(userdata);dwflash.0:384k(u-boot),128k(u-boot_env) quiet
加上quiet 省不到1S4)啟動的時候不掃描整個芯片的壞塊,因為uboot只會用到kernel和splash區,只需要檢驗這兩個區的壞塊。
? 可以省不到 0.2s ,沒什么明顯的改進?
5) 將環境變量verify 設置為n ,這樣load kernel 后,不會去計算校驗 kernel image的checksum?
6)開始打印公司 這些可以去掉 ,在這里還有delay ,以及其他的一些不必要的打印 ,一起去掉
7)修改memcpy函數 在./lib_generic/string.c下:
/* Nonzero if either X or Y is not aligned on a "long" boundary.? */
#define UNALIGNED(X, Y) \
? (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
/* How many bytes are copied each iteration of the 4X unrolled loop.? */
#define BIGBLOCKSIZE??? (sizeof (long) << 2)
/* How many bytes are copied each iteration of the word copy loop.? */
#define LITTLEBLOCKSIZE (sizeof (long))
/* Threshhold for punting to the byte copier.? */
#define TOO_SMALL(LEN)? ((LEN) < BIGBLOCKSIZE)
void * memcpy(void * dst0,const void *src0,size_t len0)
{
? char *dst = dst0;
? const char *src = src0;
? long *aligned_dst;
? const? long *aligned_src;
? int?? len =? len0;
? /* If the size is small, or either SRC or DST is unaligned,
???? then punt into the byte copy loop.? This should be rare.? */
? if (!TOO_SMALL(len) && !UNALIGNED (src, dst))
??? {
????? aligned_dst = (long*)dst;
????? aligned_src = (long*)src;
????? /* Copy 4X long words at a time if possible.? */
????? while (len >= BIGBLOCKSIZE)
??????? {
????????? *aligned_dst++ = *aligned_src++;
????????? *aligned_dst++ = *aligned_src++;
????????? *aligned_dst++ = *aligned_src++;
????????? *aligned_dst++ = *aligned_src++;
????????? len -= BIGBLOCKSIZE;
??????? }
????? /* Copy one long word at a time if possible.? */
????? while (len >= LITTLEBLOCKSIZE)
??????? {
????????? *aligned_dst++ = *aligned_src++;
????????? len -= LITTLEBLOCKSIZE;
??????? }
?????? /* Pick up any residual with a byte copier.? */
????? dst = (char*)aligned_dst;
????? src = (char*)aligned_src;
??? }
? while (len--)
??? *dst++ = *src++;
? return dst0;
}
(在linux 中,arm 的memcpy 有優化的版本 , 在/arch/arm/lib/memcpy.S中)
下面2個建議,沒試過:8)在環境變量區的末尾, 存有CRC,啟動的時候會校驗CRC ,去掉可以省一些時間9)把一些驅動的初始化在正常啟動的時候不執行,當用戶按了鍵,進入uboot命令模式的時候執行
10) 修改SDRAM控制器時序
Kernel :
啟動時間 有兩種方法 :
1 在u-boot的 bootargs 中加上參數 time?
2 在內核的 kernel hacking 中 選擇 PRINTK_TIME
方法2的好處是可以得到內核在解析command_line 前所有信息的時間,而之前會有:打印linux 版本信息,CPU D cache , I cache 等等 。。。
啟動完后 用 :
dmesg -s 131072 > ktime
然后用 :
/usr/src/linux-x.xx.xx/s/show_delta ktime > dtime
這樣得到啟動內核時間的報告?
1)修改Nand驅動 提高讀速度2)從 JFFS2 換成 yaffs
3)kernel變為非壓縮的image ,但這樣的話內核變大了,從NAND中搬運內核的時間將變長 ,所以需要測試是否
?? 使得時間變短
建議:
4)把delay的 calibration 去掉?
?
上面改動后 基本上8s從開機到 Freeing init memory?
Application :
1 udev 啟動 很花時間
2 安排好啟動順序。
總結
以上是生活随笔為你收集整理的Linux 嵌入式启动以及优化(Z)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 买基金如何避免老鼠仓
- 下一篇: (原创)eCos驱动分析 之 ISR是如