高级会员
- 积分
- 813
- 金钱
- 813
- 注册时间
- 2021-2-26
- 在线时间
- 117 小时
|
拿到一块新板子,或者新平台,势必要对他的启动过程以及分区表进行分析,才可以进行后续的修改以及开发。我这边是eMMC的板子,我们就来看eMMC的启动流程。
1. eMMC启动流程
参见IMX6ULL参考手册8.5.3.2 MMC and eMMC boot章节,简单的来说,上电的时候,ROM code会根据拨码开关去判定启动介质,当拨码开关打到eMMC的时候,会走eMMC启动流程。ROM code会朝eMMC芯片发送指令询问eMMC芯片是否指出boot mode,如果得到的回复是支持,那就会从eMMC的boot分区启动,如果得到的回复是不支持,那就会从eMMC的UDA启动,此时和正常的SD卡启动没区别。详细的过程,有兴趣的同学可以去看参考手册。
板子上所使用的eMMC是三星的 KLM8G1GETF,参见芯片手册可以知道,这是一颗eMMC 5.1规格的芯片,并且支持boot mode,芯片内部包含2个boot分区,boot1和boot2,每个boot分区4MB大小。就以这颗芯片还说,boot时会使用到他的boot分区。
2. 分区表
eMMC启动流程知道了个大概,那么如何知道分区表呢?一般SoC厂商都会提供空板子烧录code的工具,在这个工具在,会存在分区工具或者分区表的信息。IMX6ULL为例,我们可以从他的mfgtool中的ucl2.xml得到答案。文件路径在<mfgtool/Profiles/Linux/OS Firmware/ucl2.xml>
以下还是eMMC为例,参见注释:
- <LIST name="eMMC" desc="Choose eMMC as media">
- <!-- <font color="Red">====> 发送 uboot, kernel zImage, dtb and ramfs 到设备里,然后启动</font> -->
- <CMD state="BootStrap" type="boot" body="BootStrap" file ="firmware/u-boot-imx6ull-14x14-emmc.imx" ifdev="MX6ULL">Loading U-boot</CMD>
-
- <CMD state="BootStrap" type="load" file="firmware/zImage" address="0x80800000"
- loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6ULL">Loading Kernel.</CMD>
- <CMD state="BootStrap" type="load" file="firmware/fsl-image-mfgtool-initramfs-imx_mfgtools.cpio.gz.u-boot" address="0x83800000"
- loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6ULL">Loading Initramfs.</CMD>
- <CMD state="BootStrap" type="load" file="firmware/imx6ull-14x14-emmc.dtb" address="0x83000000"
- loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6ULL">Loading device tree.</CMD>
- <CMD state="BootStrap" type="jump" > Jumping to OS image. </CMD>
- <!-- create partition -->
- <!-- <font color="Red">====> 创建分区,可以看到使用的是mksdcard.sh脚本, 该脚本在 <mfgtool/Profiles/Linux/OS Firmware/mksdcard.sh.tar>, 稍后分析他</font> -->
- <CMD state="Updater" type="push" body="send" file="mksdcard.sh.tar">Sending partition shell</CMD>
- <CMD state="Updater" type="push" body="$ tar -xf $FILE "> Partitioning...</CMD>
- <CMD state="Updater" type="push" body="$ sh mksdcard.sh /dev/mmcblk1"> Partitioning...</CMD>
- <!-- burn uboot -->
- <!-- <font color="Red">====> 烧录bootloader(uboot.imx), 分以下几个步骤:
- 1. 清除uboot env, 总归8K,并且跳过了前面768 bytes, 这里是UDA区域,并不是boot1,boot2
- 2. 打开boot1区域的写入权限, 把uboot.imx写进去,并且跳过了前面1024 bytes(1K),最后关闭boot1区域的写入权限
- 3. 打开boot1分区的boot功能
- 可以看到,这里是以RAW data的形式写入的,并没有做任何分区格式化。</font> -->
- <CMD state="Updater" type="push" body="$ dd if=/dev/zero of=/dev/mmcblk1 bs=1k seek=768 conv=fsync count=8">clear u-boot env</CMD>
- <CMD state="Updater" type="push" body="$ echo 0 > /sys/block/mmcblk1boot0/force_ro">access boot partition 1</CMD>
- <CMD state="Updater" type="push" body="send" file="files/boot/u-boot-imx6ull-14x14-ddr%ddr%-emmc.imx" ifdev="MX6ULL">Sending u-boot.bin</CMD>
- <CMD state="Updater" type="push" body="$ dd if=$FILE of=/dev/mmcblk1boot0 bs=512 seek=2">write U-Boot to sd card</CMD>
- <CMD state="Updater" type="push" body="$ echo 1 > /sys/block/mmcblk1boot0/force_ro"> re-enable read-only access </CMD>
- <CMD state="Updater" type="push" body="$ mmc bootpart enable 1 1 /dev/mmcblk1">enable boot partion 1 to boot</CMD>
- <!-- format and mount boot partition -->
- <!-- <font color="Red">====> 烧录kernel和dtb,分以下几个步骤:
- 1. 等待/dev/mmcblk1p1就绪
- 2. 将/dev/mmcblk1p1格式化成FAT32
- 3. 挂载/dev/mmcblk1p1 到 /mnt/mmcblk1p1
- 4. 复制 zImage和dtbs 到 /mnt/mmcblk1p1
- 5. 同步写入,并且取消挂载
- 可以看到,boot分区,存放了kernel和dtb,该分区是FAT32格式。</font> -->
- <CMD state="Updater" type="push" body="$ while [ ! -e /dev/mmcblk1p1 ]; do sleep 1; echo "waiting..."; done ">Waiting for the partition ready</CMD>
- <CMD state="Updater" type="push" body="$ mkfs.vfat -F 32 /dev/mmcblk1p1">Formatting rootfs partition</CMD>
- <CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk1p1"/>
- <CMD state="Updater" type="push" body="$ mount -t vfat /dev/mmcblk1p1 /mnt/mmcblk1p1"/>
- <!-- burn zImage -->
- <CMD state="Updater" type="push" body="send" file="files/boot/zImage">Sending kernel zImage</CMD>
- <CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk1p1/zImage">write kernel image to sd card</CMD>
- <!-- burn dtb -->
- <CMD state="Updater" type="push" body="send" file="files/boot/imx6ull-alientek-emmc.dtb" ifdev="MX6ULL">Sending Device Tree file</CMD>
- <CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk1p1/imx6ull-alientek-emmc.dtb" ifdev="MX6ULL">write device tree to eMMC card</CMD>
-
- <CMD state="Updater" type="push" body="send" file="files/boot/imx6ull-14x14-emmc-4.3-800x480-c.dtb" ifdev="MX6ULL">Sending Device Tree file</CMD>
- <CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk1p1/imx6ull-14x14-emmc-4.3-800x480-c.dtb" ifdev="MX6ULL">write device tree to eMMC card</CMD>
- <CMD state="Updater" type="push" body="send" file="files/boot/imx6ull-14x14-emmc-7-800x480-c.dtb" ifdev="MX6ULL">Sending Device Tree file</CMD>
- <CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk1p1/imx6ull-14x14-emmc-7-800x480-c.dtb" ifdev="MX6ULL">write device tree to eMMC card</CMD>
- <CMD state="Updater" type="push" body="send" file="files/boot/imx6ull-14x14-emmc-7-1024x600-c.dtb" ifdev="MX6ULL">Sending Device Tree file</CMD>
- <CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk1p1/imx6ull-14x14-emmc-7-1024x600-c.dtb" ifdev="MX6ULL">write device tree to eMMC card</CMD>
- <CMD state="Updater" type="push" body="send" file="files/boot/imx6ull-14x14-emmc-10.1-1280x800-c.dtb" ifdev="MX6ULL">Sending Device Tree file</CMD>
- <CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk1p1/imx6ull-14x14-emmc-10.1-1280x800-c.dtb" ifdev="MX6ULL">write device tree to eMMC card</CMD>
-
- <CMD state="Updater" type="push" body="send" file="files/boot/imx6ull-14x14-emmc-hdmi.dtb" ifdev="MX6ULL">Sending Device Tree file</CMD>
- <CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk1p1/imx6ull-14x14-emmc-hdmi.dtb" ifdev="MX6ULL">write device tree to eMMC card</CMD>
-
- <CMD state="Updater" type="push" body="send" file="files/boot/imx6ull-14x14-emmc-vga.dtb" ifdev="MX6ULL">Sending Device Tree file</CMD>
- <CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk1p1/imx6ull-14x14-emmc-vga.dtb" ifdev="MX6ULL">write device tree to eMMC card</CMD>
-
- <CMD state="Updater" type="push" body="$ sleep 1">delay</CMD>
- <CMD state="Updater" type="push" body="$ sync">Sync...</CMD>
- <CMD state="Updater" type="push" body="$ umount /mnt/mmcblk1p1">Unmounting vfat partition</CMD>
- <!-- format and mount rootfs partition -->
- <!-- <font color="Red">====> 烧录根文件系统,这里和上面kernel,dtb一样,只不过分区格式换成了ext3/4</font> -->
- <CMD state="Updater" type="push" body="$ mkfs.ext3 -F -E nodiscard /dev/mmcblk1p2">Formatting rootfs partition</CMD>
- <CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk1p2"/>
- <CMD state="Updater" type="push" body="$ mount -t ext3 /dev/mmcblk1p2 /mnt/mmcblk1p2"/>
- <!-- burn rootfs -->
- <CMD state="Updater" type="push" body="pipe tar -jxv -C /mnt/mmcblk1p2" file="files/filesystem/rootfs.tar.bz2" ifdev="MX6ULL">Sending and writting rootfs</CMD>
- <CMD state="Updater" type="push" body="frf">Finishing rootfs write</CMD>
- <CMD state="Updater" type="push" body="send" file="files/modules/modules.tar.bz2" ifdev="MX6ULL">Sending Modules file</CMD>
- <CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk1p2/lib/modules">Mkdir -p /mnt/mmcblk1p2/lib/modules</CMD>
- <CMD state="Updater" type="push" body="$ tar jxf $FILE -C /mnt/mmcblk1p2/lib/modules/" ifdev="MX6ULL">tar Modules file</CMD>
- <CMD state="Updater" type="push" body="$ sleep 1">delay</CMD>
- <CMD state="Updater" type="push" body="$ sync">Sync...</CMD>
- <CMD state="Updater" type="push" body="$ umount /mnt/mmcblk1p2">Unmounting rootfs partition</CMD>
- <CMD state="Updater" type="push" body="$ echo Update Complete!">Done</CMD>
- </LIST>
复制代码
继续,我们来分析mksdcard.sh
- #!/bin/sh
- <font color="Red"># ====> 下面都是一些准备工作,可以略过</font>
- # partition size in MB
- BOOT_ROM_SIZE=10
- # wait for the SD/MMC device node ready
- while [ ! -e $1 ]
- do
- sleep 1
- echo “wait for $1 appear”
- done
- <font color="Red"># ====> 从这里开始,才是真正的分区动作</font>
- # call sfdisk to create partition table
- # destroy the partition table
- node=$1 <font color="Red"># ====> 以eMMC为例,这里是 /dev/mmcblk1</font>
- dd if=/dev/zero of=${node} bs=1024 count=1 <font color="Red"> # ====> 将eMMC的前面1K全部写0,实际上是清空分区表</font>
- # ====> <font color="Red">这里使用了sfdisk工具来进行分区</font>
- sfdisk --force ${node} << EOF
- ${BOOT_ROM_SIZE}M,128M,c <font color="Red"># 分区1, 从10M位置开始, 分区大小128M, 这里是一个W96 FAT32(LBA)分区</font>
- 138M,,83 <font color="Red"># 分区2, 从138M开始, 用完所剩余的容量, 这里是一个Linux分区, 83表示MBR下的Linux分区</font>
- write
- EOF
复制代码 可以看到,在分区的时候,跳过了头上10M的位置,这10M为不支持boot mode的芯片准备的。然后分了一个128M的FAT32分区,这个分区会被格式化长FAT32,存放kernel和dtb,一个剩余全部空间的Linux分区,这个linux分区,最终会被格式化成ext3/4,存放rootfs
3. 最终的分区表
|
|