正点原子 i.MX6ULL 从 SD 卡启动 Linux 实战笔记

为什么先做这个

我想把 openEuler Embedded 移植到手上的正点原子阿尔法开发板(i.MX6ULL,eMMC 版本)。
但问题来了——这块板子还在跑我的毕设,eMMC 里的系统和代码不能随便动。

所以我选了一条更保险的路:eMMC 原样保留,专门做一张 SD 启动卡,从 SD 卡独立启动 Linux

这样做的好处很直接:

  • 毕设环境不受影响
  • 随时切回 eMMC 继续干活
  • 先完整跑通启动链,后面移植 openEuler 才有底气

这次要打通什么

目标很明确:从 SD 卡启动一个能进 shell 的最小 Linux 系统

也就是下面这条链:

ROM → U-Boot → zImage → dtb → rootfs → shell

不要求跑 openEuler,先验证板子能从 SD 卡独立启动,后面再逐步替换组件。

开发板和资料

  • 板子:正点原子阿尔法,i.MX6ULL,eMMC 版
  • 资料包里可用的文件(注意是分组件提供,不是整盘镜像):
01、u-boot镜像/emmc/u-boot.imx
02、kernel镜像/zImage
02、kernel镜像/imx6ull-alientek-emmc.dtb
03、文件系统/02、busybox-1.29.0根文件系统/rootfs.tar.bz2

因为是分组件,所以不能直接 dd 一个 .img 完事,得手工做 SD 卡。

启动模式拨码

正点原子给的拨码定义:

  • SD 卡启动:1000 0010
  • eMMC 启动:1010 0110

(ON = 1,OFF = 0)

做实验前先把拨码切到 SD 启动模式,做完实验切回来就能回毕设环境。

制作 SD 启动卡(在 Ubuntu 主机上)

1. 确认 SD 卡设备名

插卡后:

lsblk

我这边识别到的是 /dev/sdb
注意:后面所有操作都是针对整张卡 /dev/sdb,不是 /dev/sdb1

2. 卸载自动挂载的分区

sudo umount /dev/sdb1

3. 清盘 + 重新分区

sudo wipefs -a /dev/sdb
sudo parted -s /dev/sdb mklabel msdos
sudo parted -s /dev/sdb mkpart primary fat32 8MiB 128MiB
sudo parted -s /dev/sdb set 1 boot on
sudo parted -s /dev/sdb mkpart primary ext4 128MiB 100%
sudo partprobe /dev/sdb

分区规划:

  • sdb1:FAT32,放 kernel 和 dtb
  • sdb2:ext4,放 rootfs

4. 格式化

sudo mkfs.vfat -F 32 -n BOOT /dev/sdb1
sudo mkfs.ext4 -F -L rootfs /dev/sdb2

再确认一下分区结果:

lsblk

我这里是:

sdb      8:16   1   7.3G  0 disk
├─sdb1   8:17   1   120M  0 part
└─sdb2   8:18   1   7.2G  0 part

5. 写入 U-Boot

这一步很关键:u-boot.imx 不是拷贝到某个分区,而是直接写到 SD 卡前部的固定偏移,SoC 上电时才会加载。

sudo dd if="./01、u-boot镜像/emmc/u-boot.imx" of=/dev/sdb bs=1K seek=1 conv=fsync
sync

6. 挂载两个分区,拷贝文件

mkdir -p ~/sdboot ~/sdroot
sudo mount /dev/sdb1 ~/sdboot
sudo mount /dev/sdb2 ~/sdroot

拷贝 kernel 和 dtb:

sudo cp "./02、kernel镜像/zImage" ~/sdboot/
sudo cp "./02、kernel镜像/imx6ull-alientek-emmc.dtb" ~/sdboot/
sync

解压 rootfs:

sudo tar -xjf "./03、文件系统/02、busybox-1.29.0根文件系统/rootfs.tar.bz2" -C ~/sdroot
sync

检查一下:

ls ~/sdboot
# 应该看到 zImage 和 imx6ull-alientek-emmc.dtb

ls ~/sdroot | head
# 应该看到 bin、dev、etc、linuxrc 等

7. 卸载 SD 卡

sudo umount ~/sdboot
sudo umount ~/sdroot
sync

卡就做好了。

上电启动,进 U-Boot

  1. 开发板断电
  2. 插 SD 卡
  3. 拨码切到 SD 启动
  4. 接好串口(我用 MobaXterm)
  5. 上电

上电后顺利进入 U-Boot,说明串口和启动模式正常,SD 卡上的 U-Boot 已经被加载了。

在 U-Boot 里看看环境

敲几个命令:

version
bdinfo
printenv
mmc list
fatls mmc 0:1
fatls mmc 1:1

有两个发现:

(1)SD 卡和 eMMC 的编号

mmc list 输出:

FSL_SDHC: 0 (SD)
FSL_SDHC: 1
  • mmc 0 是 SD 卡
  • mmc 1 是 eMMC

(2)U-Boot 默认找的 dtb 名字对不上

printenv 里看到 fdt_file=imx6ull-14x14-emmc-7-1024x600-c.dtb,但我 SD 卡里放的是 imx6ull-alientek-emmc.dtb
如果直接 run mmcboot,会因为找不到正确的 dtb 而失败——后面果然遇到了。

碰到的坑:Bad Linux ARM zImage magic!

我一开始图省事,直接敲:

run mmcboot

结果报错:

Bad Linux ARM zImage magic!

原因其实不复杂:mmcboot 这个环境变量里虽然有加载 kernel 的动作,但在某些板子上它依赖的条件没满足,导致实际上没有把 zImage 正确加载到内存,就贸然执行了 bootz

解决办法:不依赖乱七八糟的自动脚本,手工一步一步加载

最终成功启动的命令

在 U-Boot 下依次敲:

fatload mmc 0:1 ${loadaddr} zImage
fatload mmc 0:1 ${fdt_addr} imx6ull-alientek-emmc.dtb
setenv bootargs console=ttymxc0,115200 root=/dev/mmcblk0p2 rootwait rw
bootz ${loadaddr} - ${fdt_addr}

每条命令在干什么:

  1. 把 SD 卡第 1 分区的 zImage 读到内存 ${loadaddr}(一般是 0x80800000
  2. 把第 1 分区的 dtb 读到内存 ${fdt_addr}(一般是 0x83000000
  3. 告诉内核:根文件系统在 /dev/mmcblk0p2,串口用 ttymxc0,波特率 115200,其他参数是标准挂载选项
  4. 启动内核

执行完,等了片刻,出现:

Please press Enter to activate this console.
/ #

进去了。启动链完全打通。

途中还闪过一条 No soundcards found...,那是 alsactl 脚本报的,不是启动失败,不用管。

这次实验让我学到的东西

以前总觉得“移植 Linux”或“移植 openEuler”是个很大的事。实际做下来发现,它可以先拆成几个具体到不能再具体的问题:

  1. 板子能不能从指定介质启动?
  2. U-Boot 能不能起来?
  3. U-Boot 能不能找到 kernel?
  4. dtb 是否匹配硬件?
  5. kernel 能不能找到 rootfs?
  6. rootfs 起来后能不能进 shell?

这些问题都摸清楚了,后面再去适配 openEuler 才不会像盲人摸象。

这对后续 openEuler 移植有什么用?

虽然这次用的是正点原子提供的 kernel + dtb + busybox rootfs,和 openEuler 还没直接关系,但这一步是实实在在的垫脚石:

  • 确认了板子可以从 SD 启动
  • 串口正常
  • U-Boot 工作正常
  • SD / eMMC 的编号关系清楚了
  • 手工启动命令已经验证
  • rootfs 挂载路径也跑通了

接下来要过渡到 openEuler Embedded,可以按顺序替换:

  1. 先保留厂商 U-Boot,只换 rootfs
  2. 再换 kernel 和 dtb
  3. 最后做 machine 和 BSP 层面的正式适配

这样一步步来,比一上来就硬怼 openEuler 靠谱得多。

一句话总结

如果手里有一块还在正常工作的板子,又想折腾系统移植,eMMC 保留旧系统,SD 卡做实验 是最舒服的路线——安全、可回滚、而且能让你真正搞懂启动链。

附:这次用到的关键命令汇总

Ubuntu 侧(制作 SD 卡)

lsblk
sudo umount /dev/sdb1
sudo wipefs -a /dev/sdb
sudo parted -s /dev/sdb mklabel msdos
sudo parted -s /dev/sdb mkpart primary fat32 8MiB 128MiB
sudo parted -s /dev/sdb set 1 boot on
sudo parted -s /dev/sdb mkpart primary ext4 128MiB 100%
sudo partprobe /dev/sdb
sudo mkfs.vfat -F 32 -n BOOT /dev/sdb1
sudo mkfs.ext4 -F -L rootfs /dev/sdb2
sudo dd if="./01、u-boot镜像/emmc/u-boot.imx" of=/dev/sdb bs=1K seek=1 conv=fsync
sync
mkdir -p ~/sdboot ~/sdroot
sudo mount /dev/sdb1 ~/sdboot
sudo mount /dev/sdb2 ~/sdroot
sudo cp "./02、kernel镜像/zImage" ~/sdboot/
sudo cp "./02、kernel镜像/imx6ull-alientek-emmc.dtb" ~/sdboot/
sudo tar -xjf "./03、文件系统/02、busybox-1.29.0根文件系统/rootfs.tar.bz2" -C ~/sdroot
sync
sudo umount ~/sdboot
sudo umount ~/sdroot
sync

U-Boot 侧(手工启动)

mmc list
fatls mmc 0:1
fatls mmc 1:1
fatload mmc 0:1 ${loadaddr} zImage
fatload mmc 0:1 ${fdt_addr} imx6ull-alientek-emmc.dtb
setenv bootargs console=ttymxc0,115200 root=/dev/mmcblk0p2 rootwait rw
bootz ${loadaddr} - ${fdt_addr}
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐