前言

一直很好奇嵌入式linux是的启动流程,以前是做芯片的,对单纯芯片的启动非常熟悉,现在的工作基本在user space,现在回过头来研究下底层的启动。

了解完整的linux启动过程,可以看看linux引导过程内幕,很详细。

另外一直以来对项目的基于squash文件系统的ota升级颗粒度过大颇有微词,看看能否有改进之处。

bin打包

  • bin打包时,指定了烧录的的地址分区

注意这些分区文件都是按squashfs or yaffs2文件系统制作好的,并且在制作bin之前进行压缩以节省空间。

../tools/bin/isp pack_image ../ISPBOOOT.BIN \
        xboot0         uboot0    \
        xboot1         0x0060000 \
        uboot1         0x0060000 \
        uboot2         0x0060000 \
        env            0x0020000 \
        env_redund     0x0020000 \
        ecos           0x0300000 \
        kernel         0x0260000 \
        rootfs         0x0600000 \
        pq             0x0020000 \
        tcon           0x0020000 \
        iop_car        0x0020000 \
        runtime_cfg    0x0020000 \
        version_info   0x0020000 \
        vendordata     0x0020000 \
        logo           0x0480000 \
        isp_logo       0x0500000 \
        kvdb           0x2000000 \
        system         0x3000000 \
        spsdk          0x1000000 \
        leavn          0x3000000 \
        nvm            0x8200000 \
        update         0xC800000 \
        vd_restore     0x0040000

uboot启动

略..

load kernel

略…

load rootfs

init进程

  • 这个分区值最终在启动后,在/proc/mtd里体现

  • init进程 /etc/inittab

init进程都是知道是程序的第1个启动程序,它将根据/etc/inittab文件来创建其他的子进程,比如调用脚本文件配置IP地址,挂载其他的文件系统,最后启动shell等。

  # Start an "respawn" shell on the serial port
  ttyS0::respawn:-/bin/sh
  #ttyS0::askfirst:-/bin/ash
  # Stuff to do when restarting the init process
  ::restart:/sbin/init
  # Stuff to do before rebooting
  ::ctrlaltdel:/sbin/reboot
  ::shutdown:/bin/umount -a -r
  ::shutdown:/sbin/swapoff -a

etc/init.d/rcS分析

该脚本是如何执行的还待分析,仅知道肯定是初始启动的脚本。

  • 启动脚本里 etc/init.d/rcS 挂载mtd的文件到工作目录

对应了前面的flash烧写的内容

system_mtdid=`cat /proc/mtd | grep system | sed "s/:.*//" | sed "s/mtd//"`
...
#/ota/system 是只读的, squashfs文件系统
mount -t squashfs  /dev/blockrom$system_mtdid /ota/system

  • 还有几个目录是按yaffs2文件系统挂载的,应该是可读写的
mount -t yaffs2 -o noatime /dev/mtdblock$nvm_mtdid /data
  • 如果检测到有更新,即存在reinstall_file文件,则执行更新

这里应该就是ota升级的诀窍

if [ -f /update/reinstall_file ];then
	cd /update
	rows=`ls -l *.squash |awk 'END{print NR}'`
	cols=`ls -l *.squash |awk 'END{print NF}'` #need to test!!!

	[ $rows -eq 0 -o $cols -eq 0 ] && echo "Not Found Any Squash File, Check Update Or Not!"
	for i in $(seq 1 $rows)
	do
        	FILENAME=`ls -l *.squash | sed -n "${i}p" | awk '{print $NF}'`
	        PARTITION=`echo $FILENAME | sed "s/\..*//"`
		MOUNTPOINT=$PARTITION

		if [ -f /ota/$MOUNTPOINT/install.sh ];then
			/ota/$MOUNTPOINT/install.sh
		fi
	done

	rm -f /update/reinstall_file
	cd -
fi
  • 执行应用层的启动脚本
/tdGUI/start.sh

start.sh

这个启动层脚本 初略看下把

  • 运行了某个install.sh脚本的某个命令

其核心效果就是创建从目录a到目录b的软链接。 前面提到文件挂载其实就是在目录b(/ota/leavn..),而软链接全部在/data/usr/下 方便统一管理。

do_merge_dir: link /data/usr/bin/AndroidPhone --> /ota/leavn/package/LeAVN/bin/AndroidPhone
  • 加载硬件厂家负责的驱动

有MCU,驱动屏的。

insmod /ota/spsdk/drivers/i2c-core.ko
insmod /ota/spsdk/drivers/i2c-gemini.ko
insmod /ota/spsdk/drivers/i2c-dev.ko
insmod /ota/spsdk/drivers/evdev.ko
insmod /ota/spsdk/drivers/gt9xx.ko

  • 运行了一个应用程序管理器,其实也就是把之前统一管理的app,按需求启动起来,

直接用service systemctrl不就好? 比如按顺序启动了这些程序

"aaa"
"bbb"
"ccc"
"ddd"
  • 启动udev

管理热拔插的

  • 初始化 bsp sdk.sh

主要工作即export各种库的路径,加载各种usb sd 声卡的驱动等等。

总结

大概的启动流程其实和标准linux并无二致。从中看出squash文件如果要修改颗粒度:

  • 思路1

传输原始文件,颗粒度小 但是要按实际的文件组织形式,再车机上打包squash、 问题在于车机打包,将会很慢很慢。

  • 思路2

在最开始分区的时候就细分?