项目场景:
在眺望电子TW-IMX6DL-EVM开发板上优化linux系统启动时间。
编译环境及开发包: 主机:ubuntu18.04
交叉编译器:arm-linux-gnueabihf-gcc
QT5.12.8:qt-everywhere-opensource-src-5.12.8
开发板:TW-IMX6DL-EVM
Linux:Linux-4.1.15
注意:本文章的所有命令涉及到的路径均为眺望电子官方环境路径,需根据自身实际环境改变。本文所演示的平台来自于眺望电子 iMX6 ARM嵌入式平台,这是一个基于NXP iMX6 ARM处理器,支持单核/双核Cortex-A9的核心板。
解决方案:
NXP i.MX6系列平台可以通过修改u-boot默认配置、裁剪内核以及修改文件系统三个方面来优化启动时间。
1.u-boot优化
u-boot主要可以通过以下几个方案进行优化:
- 去掉不必要的串口信息;
- 去掉启动延迟时间;
- 去掉不必要的驱动;
- 去掉用不到的命令。
1.1串口信息修改
u-boot启动通常会打印以下消息:
U-Boot 2014.04-gdec7a05-dirty (Mar 16 2020 - 10:34:39)
CPU: Freescale i.MX6DL rev1.3 at 792 MHz
CPU: Temperature 33 C, calibration data: 0x59751969
Reset cause: POR
Board: MX6-SabreSD
I2C: ready
DRAM: 2 GiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2
No panel detected: default to Hannstar-XGA
Display: Hannstar-XGA (1024x768)
In: serial
Out: serial
Err: serial
Found PFUZE100 deviceid=10,revid=11
mmc2(part 0) is current device
Net: FEC [PRIME]
Warning: failed to set MAC address
Card did not respond to voltage select!
mmc1(part 0) is current device
Card did not respond to voltage select!
** Bad device mmc 1 **
Card did not respond to voltage select!
** Bad device mmc 1 **
Normal Boot
Saving Environment to MMC...
Writing to MMC(2)... done
Have env flag, ignore inner env
Hit any key to stop autoboot: 0
mmc2(part 0) is current device
reading boot.scr
** Unable to read file boot.scr **
reading zImage
6709816 bytes read in 172 ms (37.2 MiB/s)
Booting from mmc ...
reading imx6dl-sabresd.dtb
44928 bytes read in 18 ms (2.4 MiB/s)
Kernel image @ 0x12000000 [ 0x000000 - 0x666238 ]
##Flattened Device Tree blob at 18000000
Booting using the fdt blob at 0x18000000
Using Device Tree in place at 18000000, end 1800df6b
switch to ldo_bypass mode!
Starting kernel ...
可以通过在include/configs/mx6sabre_common.h文件中添加以下选项来屏蔽打印信息:
#define CONFIG_EXTRA_ENV_SETTINGS "silent=1\0"
#define CONFIG_SILENT_CONSOLE 1
1.2启动延迟时间修改
默认出厂固件会有1秒钟的延迟,可以通过修改include/configs/mx6sabre_common.h文件来取消延迟。
#define CONFIG_BOOTDELAY 0
#define CONFIG_ZERO_BOOTDELAY_CHECK
1.3去掉不必要的驱动
可以根据实际情况去掉不必要的驱动来优化启动时间,例如SPI、USB、HDMI等。去掉SPI驱动可以修改include/configs/mx6sabre_common.h文件:
#if defined(CONFIG_ENV_IS_IN_MMC)
#define CONFIG_ENV_OFFSET (8 * 64 * 1024)
#elif defined(CONFIG_ENV_IS_IN_SPI_FLASH)
#define CONFIG_ENV_OFFSET (768 * 1024)
#define CONFIG_ENV_SECT_SIZE (64 * 1024)
//#define CONFIG_ENV_SPI_BUS CONFIG_SF_DEFAULT_BUS
//#define CONFIG_ENV_SPI_CS CONFIG_SF_DEFAULT_CS
//#define CONFIG_ENV_SPI_MODE CONFIG_SF_DEFAULT_MODE
//#define CONFIG_ENV_SPI_MAX_HZ CONFIG_SF_DEFAULT_SPEED
#elif defined(CONFIG_ENV_IS_IN_FLASH)
如果无需使用网络,也可以去掉相关驱动,同样是修改include/configs/mx6sabre_common.h
文件:
//#define CONFIG_FEC_MXC
//#define CONFIG_MII
//#define IMX_FEC_BASE ENET_BASE_ADDR
//#define CONFIG_FEC_XCV_TYPE RGMII
//#define CONFIG_ETHPRIME "FEC"
//#define CONFIG_FEC_MXC_PHYADDR 1
//#define CONFIG_PHYLIB
//#define CONFIG_PHY_ATHEROS
同样可以选择去掉USB的驱动,修改如下:
#if 0
/* USB Configs */
#define CONFIG_CMD_USB
#define CONFIG_USB_EHCI
#define CONFIG_USB_EHCI_MX6
#define CONFIG_USB_STORAGE
#define CONFIG_EHCI_HCD_INIT_AFTER_RESET
#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_ETHER_ASIX
#define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW)
#define CONFIG_MXC_USB_FLAGS 0
#define CONFIG_USB_MAX_CONTROLLER_COUNT 1 /* Enabled USB controller number */
#endif
1.4去掉用不到的命令
在配置文件include/configs/mx6sabre_common.h文件中可以去掉用不到的命令,这里以去掉网络相关的命令为例。
//#define CONFIG_CMD_PING
//#define CONFIG_CMD_DHCP
//#define CONFIG_CMD_MII
//#define CONFIG_CMD_NET
2.内核修改
内核层面主要通过裁剪内核来实现启动时间优化,为了减少启动时间,可以在arch/arm/configs/imx_v7_defconfig文件中去掉caam(i.MX6硬件加密加速模块)模块的支持:
#CONFIG_CRYPTO_ANSI_CPRNG is not set
#CONFIG_CRYPTO_DEV_FSL_CAAM=y
#CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y
#CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=y
#CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y
根据实际情况去掉其它用不到的驱动模块,例如A9平台默认没有使用flash,可以去掉该驱动模块的支持:
#CONFIG_MTD=y
对于需用到的模块,可以可以编译成KO文件,等待系统启动后再加载,或者在需调用时再加载。
另外对于初始化中小于10 ms的sleep,可由msleep改为mdelay,因为msleep会让出CPU的占用,而A9上CPU调度频率是100hz,也就是最快调度一次也要大于10ms,所以用mdelay会更快些。
内核启动过程中同样会在串口打印相关信息,所以关闭打印时间以及将printk的打印级别调高,减少打印的信息也可以在一定程度上对启动时间进行优化:
#CONFIG_PRINTK_TIME=n
#define DEFAULT_CONSOLE_LOGLEVEL 4
3.文件系统修改
文件系统占用启动时间较多的地方主要有:
- 拷贝文件系统到内存;
- udev或者mdev等自动创建设备节点;
- 系统自启动服务;
- 相关的自启程序。
相对应的优化方法有:
- 裁剪文件系统
- 用mknod创建设备节点
- 关闭不使用的服务
- 取消不必要的自启程序
3.1裁剪文件系统
需根据自身需求进行裁剪,去掉文件系统中不必要的库文件、logo图片、测试程序等,在虚拟机上先对文件系统进行解包,裁剪完成后再进行打包,对应的命令为:
tar zxvf rootfs.tar.gz –C ./ /* 解包 * /
tar zcvf rootfs.tar.gz ./rootfs /* 打包 * /
3.2用mknod创建设备节点
创建设备节点一般有两种方法,第一种是自动创建,利用udev(mdev)来实现设备文件的自动创建,这种比较占用启动时间。第二种是使用mknod手动创建,可以减少启动时间,使用cat /proc/devices查看申请到的设备名,设备号,然后使用以下命令创建设备节点:
mknod filename type major minor
3.3关闭不使用的服务
系统默认会自启很多种服务,结合自身需求取消用不到的服务同样可以优化启动时间。这里以取消几种服务为例:
rm /etc/init.d/oprofileui-server /* 系统性能 * /
rm /etc/init.d/bootlogd /* 日志 * /
rm /etc/init.d/ofono /* 电话 * /
rm /etc/init.d/neard
3.4取消不需要的自启程序
init进程会调用/etc/rcS.d目录下Sxxxx之类的脚本文件(S是开头,然后是数字,之后是名称)从而实现开机自启程序的目的。可以将不需要的脚本文件直接删掉,也可以节省不少启动时间。