news 2026/9/24 16:44:57

Linux驱动01-系统移植

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux驱动01-系统移植

一、系统移植

1.1 系统移植介绍

① 系统移植主要指在开发板上运行Linux操作系统,涉及硬件驱动开发、Linux系统与硬件设备的兼容适配以及内核层面的编程工作。

将Linux系统移植到开发板的过程中,需要完成四个关键组件的移植:Bootloader(U-Boot,引导加载程序)、zImage(内核镜像)、.dtb(设备树文件)和rootfs(文件系统)。这些组件将被烧录至开发板的存储设备中,这一完整过程统称为系统移植。

  • Bootloader (U-Boot—Universal Boot Loader)是嵌入式系统中广泛使用的开源引导加载程序,其核心功能是为操作系统内核的启动提供硬件初始化、镜像加载及参数传递等支持。
  • zImage是Linux操作系统的内核镜像文件,实质上是系统的核心软件组件,负责处理器管理、内存分配、硬件设备控制、进程调度以及网络通信等关键功能。
  • .dtb(设备树文件)是描述硬件设备信息。
  • rootfs(文件系统)是Linux系统运行的基础,可以提供文件资源管理和用户交互界面等必要功能。
  • 注意:imx6ull-alientek-emmc.dtbs是Linux内核运行所需要的设备树文件,记录不同硬件平台的资源信息文件。 Linux3.x版本内核以前,此部分包含在zImage中,Linux3.x版本内核以后,该信息被独立出来称为设备树文件。

1. Bootloader 是做什么的? 系统上电后,CPU 通常不能直接启动 Linux 内核,需要一段小程序先做: 初始化最基础的硬件:时钟、DDR、串口、存储等 从 Flash、SD、eMMC、网络等介质找到内核 把 Linux 内核和设备树加载到内存 给内核传启动参数,例如 bootargs 跳转到内核入口,把控制权交给 Linux 这类程序统称为 Bootloader。 常见的 Bootloader 有: Bootloader 典型场景 U-Boot 嵌入式 Linux,ARM、RISC-V、MIPS 等 GRUB PC / x86 Linux LILO 早期 x86 Linux Barebox 嵌入式 RedBoot 早期嵌入式 BootROM SoC 内部固化的一级启动代码 SPL U-Boot 的二级程序加载器,常和 U-Boot 配合 2.U-Boot 是什么? U-Boot 全称通常叫 Das U-Boot,也叫 Universal Boot Loader。 它是嵌入式 Linux 里最流行的开源 Bootloader,主要功能包括: 初始化串口、DDR、MMC、NAND、网口等 支持从 SD、eMMC、NAND、SPI Flash、TFTP、USB 启动 加载 Linux 内核、设备树 .dtb、根文件系统 提供命令行交互 支持环境变量、启动脚本 支持 DFU、Fastboot、网络启动等 支持 SPL/TPL 多级启动 在嵌入式 Linux 启动链里,常见结构是: text: BootROM → SPL → U-Boot → Linux Kernel + DTB → rootfs 其中: BootROM:芯片内部固化,最底层启动 SPL:U-Boot 的二级程序加载器,负责初始化 DDR 等 U-Boot:完整引导程序,负责加载内核 Linux Kernel:操作系统内核

③ 操作系统:
操作系统本质上是一种管理计算机硬件资源并为程序提供运行环境的系统软件,其核心部分称为内核。内核通过系统调用接口与外部进行交互。在系统调用层之上,还构建了公共函数库以提供更高级的功能接口。应用程序既可以直接调用系统调用,也可以使用这些公共函数库。其中,shell作为一种特殊的应用程序,主要负责为用户提供执行其他程序的交互界面。

④ Linux内核组成


Linux内核主要由进程调度(SCHED)、内存管理(MM)、虚拟文件系统(VFS)、网络接口(NET)和进程间通信(IPC) 5个子系统组成。

  • 进程调度:进程调度控制系统中的多个进程对CPU的访问。
  • 内存管理:内存管理作用是控制多个进程安全地共享主内存区域。
  • 虚拟文件系统:Linux虚拟文件系统隐藏了各种硬件的具体细节,为所有设备提供了统一的接口。
  • 网络接口:网络接口提供了对各种网络标准的存取和各种网络硬件的支持。
  • 进程间通信:进程间通信支持进程之间的通信。

⑤ SD卡分区布局

i.MX6ULL 开发板:NXP官方有严格规定。

  • 1KB保留区:SD卡最前端,MBR分区表。

  • Uboot区域:从第2个扇区开始,存放引导加载程序。

  • 内核分区 (FAT32):存放Linux内核镜像及设备树文件。

  • 根文件系统分区 (ext3):存放Linux系统文件

1.2 系统的烧录

① 常见的系统烧写模式

  • 模式一:烧录至SD卡;

应用场景:适用于多设备快速部署及系统刷机与恢复。

  • 模式二:烧录至eMMC;

应用场景:适用于开发完成后的产品量产阶段。

  • 模式三:通过SD卡烧录uboot + tftp下载zImage\ .dtb+ nfs挂载rootfs;

应用场景:便于开发调试。

② 模式一:烧写到SD卡

在windows上烧写步骤:

安装mfgtool工具:将 mfgtool.zip 解压到无中文路径的目录后即可使用,烧录文件为正点原子出厂系统镜像,通常无需修改,若需替换则必须保持文件名与出厂一致。

a. 启动mfgtool工具(Mfgtool2-eMMC-ddr512-SDCard.vbs,启动前先关闭虚拟机,防止开发板OTG识别到虚拟机中,应该让其识别在windows系统中;
b. 操作开发板插上12v的电源线为开发板供电;
c. 使用type-c连接线连接底板的USB_OTG接口与PC机(关闭虚拟机,让开发板OTG接口识别到windows系统中);
d. 将开发板拨码开关设置为USB启动方式(01000000);

e. 先去掉SD卡,防止软件识别错误;
f. 开发板上电后,即可看到windows中的软件识别到开发板OTG接口;
g. 插入SD卡;

h. 执行软件mfgtool工具中的start开始烧录;
i. 等待5分钟左右即可烧录完成,烧写完成后,先点击stop,然后exit退出;
j. 修改为SD卡启动(10000010)即可启动开发板Linux系统。

在Ubuntu上烧写步骤:

1. 烧录工具
烧录工具使用广商提供的烧写脚本即可, imx6mksdboot.sh负责将系统烧写到SD卡上, imx6mkemmcboot.sh负责将系统烧写到emmc上,需要注意emmc的烧写必须在开发板Linux系统启动后执行脚本才能完成烧写。
2. 烧录文件介绍
boot:存放要烧写的uboot、 zImage、设备树文件
filesystem:存放要烧写的文件系统的压缩包
modules:存放要烧写的内核模块文件
注意:如果想要烧写自己制作的系统,即可通过文件名替换成自己的文件即可,注意名字与出厂时保持一致

a. 将sd卡插入读卡器并连接到Ubuntu中。
b. 通过命令(sudo fdisk -l 或 df -h)查看sd卡是否连接成功,并被成功识别为/dev/sdb
c. 将(mfgtool\Profiles\Linux\OS Firmware)目录下的files文件夹拷贝到Ubuntu系统中。(imx6mksdboot.sh
脚本需要修复下将${PARITION2} ->修改为 ${PARTITION2})

d. 进入files对应的目录执行脚本:

sudo ./imx6mksdboot.sh -device /dev/sdb -flash emmc -ddrsize 512

e. 等待命令执行完成,显示SD卡启动系统烧写完成即可烧写成功;

f. 修改为SD卡启动(10000010)即可启动开发板Linux系统。

③ 模式二:烧写到EMMC

在windows上烧写步骤和模式一差不多,只是烧写工具(Mfgtool2-eMMC-ddr512-eMMC.vbs)不一样。

在Ubuntu上烧写步骤:

这步要先完成(模式一:烧写到SD卡)中的Ubuntu烧写步骤,因为EMMC烧写需要在开发板后的界面通过脚本烧录。还需要完成nfs服务器配置及minicom配置(见附录1)

a.将sd卡烧录为出厂系统,并选择SD卡启动。

b.使用minicom连接开发板,并显示开发板终端交互界面。(sudo minicom)

c.测试与主机是否网络连通。(ping 192.168.1.100)

d.将开发板的/mnt目录挂载到Ubuntu主机的共享目录下,形成共享文件夹(此操作是在minicom中操作开发板)

mount -o nolock,rw,nfsvers=3 192.168.1.100:/home/linux/nfs/rootfs /mnt

e.将(mfgtool\Profiles\Linux\OS Firmware)目录下的files文件夹拷贝到Ubuntu系统的/home/linux/nfs/rootfs目录下。

f.为imx6mkemmcboot.sh文件加上执行权限。

chmod +x /home/linux/nfs/rootfs/imx6mkemmcboot.sh

g.在开发板中执行烧录脚本(此操作是在minicom中操作开发板)

h. 进入/mnt/files对应的目录执行脚本:

cd /mnt/files ./imx6mkemmcboot.sh -device /dev/mmcblk1 -ddrsize 512

i. 等待命令执行完成,显示EMMC启动系统烧写完成即可烧写成功;

j. 修改为EMMC启动(10100110)即可启动开发板Linux系统。

④ 模式三:uboot烧写到SD卡 + zImage\.dtb通过tftp下载 + rootfs通过nfs挂载

思想:将uboot烧录到SD卡上,并设置为SD卡启动,开发板上电即可启动uboot,然后将zImage放入到tftp管理目录,通过tftp下载zImage和设备树文件到DDR中,并加载内核,最后将文件系统设置在nfs服务器上,内核挂载nfs服务器的文件系统,启动Linux系统。这样做的目的在于每次下载的zImage和dts设备树文件都是最新裁剪出来的,减少了烧录固化的时间,并且文件系统也是最新版本的,所以这种模式主要用于开发时使用。

首先需要完成tftp服务器配置、nfs服务器配置及minicom配置(见附录1)

操作步骤
a. 先完成(模式一:烧写到SD卡),可以将uboot烧写到sd卡中
b. 将开发板设置为sd卡启动
c. 将zImage和imx6ull-alientek-emmc.dtb拷贝到Ubuntu的/home/linux/tftpboot目录下(没有则创建目录并赋权限)。
d.将 rootfs.tar.bz2 解压到 Ubuntu的 /home/linux/nfs/rootfs 目录下(没有则创建目录并赋权限)。

e. 启动开发板,使用minicom进入uboot界面(启动开发板后输入回车进入uboot交互界面)

f. 设置启动参数

env default -a #uboot 变量恢复默认值 saveenv # 保存变量 reset #重启uboot setenv ipaddr 192.168.1.50 # 设置开发板ip地址 setenv ethaddr 00:04:9f:04:d2:35 #设置开发板网卡mac地址 setenv gatewayip 192.168.1.1 #设置开发板网关 setenv netmask 255.255.255.0 #设置开发板子网掩码 setenv serverip 192.168.1.100 #设置pc段的ip地址 setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000' setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/linux/nfs/rootfs,v3,proto=tcp rw ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off' saveenv # 保存变量 reset #重启uboot 测试与Ubuntu是否能够ping通:ping 192.168.1.100(只能是单向的,只能开发板向虚拟机)

地址是否可以修改:

1.0x80800000 是 Linux 内核(zImage)的加载地址 根本原因:i.MX6ULL 的 DDR 内存控制器映射的物理起始地址是 0x80000000。所有对 DDR 的访问都从这个地址开始。 预留空间:地址 0x80000000 到 0x807FFFFF(共 8MB)的空间,通常被 U-Boot 自身或用于存放启动参数(ATAGS)等占用。因此,Linux 内核被加载到 0x80800000,即从 DDR 起始地址偏移 8MB 的位置,避开了 U-Boot 的区域。 解压空间:zImage 是压缩的内核镜像。它会在内存中自解压。将加载地址设为一个较高的位置,可以为内核解压后的大小(通常远大于压缩镜像)预留出连续的内存空间,防止解压时覆盖其他关键数据(如设备树)。 2.0x83000000 是设备树(.dtb)的加载地址 避免覆盖:设备树文件必须加载到与内核镜像不重叠的地址。0x83000000 距离 0x80800000 有 24MB 的空间,这个间隔为内核镜像本身及其解压后的空间预留了足够的安全区域,确保两者不会相互破坏。 约定俗成:在许多 i.MX6ULL 的参考设计和教程(包括正点原子)中,都将设备树放置在 0x83000000,这已经成为一个广泛使用的惯例地址。 3.如何修改这些地址? 修改地址时,必须遵循两个核心原则,并注意一些实际限制。 核心原则一:地址必须在 DDR 的有效范围内 新的地址必须位于 DDR 的物理地址空间内。对于 i.MX6ULL,DDR 通常起始于 0x80000000。其结束地址取决于 DDR 的容量(例如,512MB 的 DDR 范围是 0x80000000 - 0x9FFFFFFF)。请确保你修改后的地址不超出实际 DDR 的物理范围。 核心原则二:确保不同文件的加载地址不重叠 这是最关键的一点。内核、设备树、以及可能存在的 ramdisk 等文件,它们在内存中的加载区域绝对不能重叠。在规划地址时,你需要考虑: 内核镜像大小:zImage 文件本身的大小。 解压后大小:内核解压后,会占用比 zImage 大得多的空间,必须为其预留足够的内存。 其他文件大小:设备树文件(.dtb)通常只有几十到几百 KB,但也要为其预留空间。

内核地址是否可以修改

0x80800000 放的是 压缩的 zImage 文件,而 0x80008000 是 zImage 自解压后,真正 Linux 内核开始执行的地址。 i.MX6ULL 内核的默认启动(运行)地址是 0x80008000。 这个地址由两部分构成: 0x80000000:这是 i.MX6ULL 处理器 DDR 内存的物理起始地址(PHYS_OFFSET)。处理器的内存映射决定了所有 DDR 访问都从这里开始。 0x8000:这是一个固定的偏移量(TEXT_OFFSET)。zImage 的自解压代码会将内核解压到 物理内存起始地址 + 0x8000 的位置。NXP 的官方文档也明确指出,这个 0x8000 的偏移是通用值,不建议修改,因为低 16KB 通常用于存放页表等关键数据。 因此,内核启动后,其代码执行的起始物理地址就是 0x80008000。这个地址也被 U-Boot 用作引导内核的默认入口点(UBOOT_ENTRYPOINT)。 2.这个地址能改吗? 从原理上可以,但实际操作非常复杂,强烈不建议修改。 你无法通过 bootcmd 命令来修改这个地址。bootz 80800000 只是告诉 U-Boot 把压缩的 zImage 放到 0x80800000,zImage 内部的自解压程序依然会按照自己预设的地址去解压和运行。 要真正修改内核启动地址,你需要: 重新配置并编译内核:修改内核配置(如 CONFIG_PHYS_OFFSET 或相关的 zreladdr 设置),然后重新编译 zImage。这相当于定制一个“知道”自己应该运行在其他地址的内核。 同步调整 U-Boot:可能还需要修改 U-Boot 的环境变量或配置,确保它传递给内核的启动参数与新的内核地址布局匹配。NXP 的应用笔记中甚至提到,在某些场景下需要同步修改 U-Boot 自身的起始地址来避免冲突。

g. 设置bootcmd,让uboot倒计时后通过tftp下载内核镜像和设备树文件。

setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000' #设置 下载zImage ,dtb

h. 设置bootargs对内核传参。

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/linux/nfs/rootfs,v3,proto=tcp rw ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off' #设置根文件系统的位置

i. 重新启动开发板,即可进入开发板Linux系统

a. 系统选择SD卡启动 b. 通过加载SD卡中的uboot初始化一些硬件设备 c. 设置uboot参数,并从Ubuntu服务器下载zImage内核镜像和imx6ullalientek-emmc.dtb设备树文件 d. 内核加载成功后,通过uboot传递给内核的bootargs参数,以nfs的形式挂载Ubuntu的文件系统 e. 启动Linux系统成功

⑤ 烧录自己制作的镜像文件

a.请参考(模式一:烧写到SD卡)中的Ubuntu烧写步骤,只需将files中对应目录中的文件替换成自己的文件即可


b. boot目录替换为自己的:
u-boot-imx6ull-14x14-ddr256-emmc.imx
dtb设备树文件(脚本会把所有的设备树文件进行烧写,在uboot阶段配置选择加载的设备树文件)
zImage

c. 将自己的根文件系统压缩并存放在filesystem目录;

d.烧写自己的镜像;

sudo ./imx6mksdboot.sh -device /dev/sdb -flash emmc -ddrsize 512

f.烧录成功后,我们需要设置uboot的启动方式,常见的启动方式有;

1. EMMC启动Linux系统 setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw' setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000; saveenv 2. 网络启动Linux系统 setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ullalientekemmc.dtb; bootz 80800000 - 83000000' saveenv

⑥ 使用mobaxterm(Windows 串口工具)
这个工具功能和minicom 一致。两者挑一个就可以了。
a. 连接开发板的串口, usb 转typec;
b. 双击xterm_personal_24.2 的图标;
c.在Windows设备管理器中查看串口编号;

d.选择连接方式(session -> Serial);

e.设置参数(Serial port:串口编号、Speed:115200、Serial engine: PuTTY、Data bits: 8、Stop bits: 1、Parity: None、Flow control: None);

f.点击 ok ,出现倒计时,按下空格键进入uboot 界面;

g.设置uboot 参数(可以使用左侧marco(宏)按键);

env default -a saveenv setenv ipaddr 192.168.1.50 setenv ethaddr 00:04:9f:04:d2:35 setenv gatewayip 192.168.1.1 setenv netmask 255.255.255.0 setenv serverip 192.168.1.100 setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/linux/nfs/rootfs_imx,proto=tcp rw ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off' setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-alientekemmc.dtb;bootz 80800000 - 83000000' saveenv reset

h.重新启动开发板,即可进入开发板Linux系统。

二、I.MX6ULL 启动总流程

2.1 I.MX6ULL开发板资源介绍

512MB(DDR3)+8GB(EMMC)核心板:

底板:各种外设

启动方式,通过拨码开关选择:
usb启动 (芯片级调试)
sd卡启动 (前面裸机阶段使用,软件开发阶段)
EMMC启动 (量产使用)
Nand flash启动(无)

2.2 Uboot介绍

2.2.1 基本概念介绍

① uboot是bootloader的一种,主要作用是在内核加载前对硬件设备初始化,并为内核的运行提供引导功能。
② 系统架构图

2.2.2 uboot常用命令与环境变量

① 环境变量操作命令

命令功能描述使用格式
printenv查看当前系统中所有环境变量printenv
setenv新建或修改环境变量setenv 环境变量名 环境变量值
saveenv保存当前环境变量到持久存储saveenv

② 内存操作命令(了解)

说明:.b表示字节(8位),.w表示字(16位),.l表示长字(32位)

  • 所有地址和值均使用十六进制格式输入。
  • 若未指定数据宽度(.b,.w,.l),默认按.l处理。
命令功能描述格式示例
md显示指定地址的内存内容md[.b,.w,.l] address [#ofobjects]

md.b 80000000 14:以字节格式显示地址80000000起始的 14 个字节。

nm修改指定地址的内存值nm[.b,.w,.l] address value

nm.w 80000000 AA55:将地址80000000处的字值改为AA55

mw使用指定数据填充一段内存mw[.b,.w,.l] address value [count]

mw.l 80000000 0A0A0A0A 10:将地址80000000起始的 10 个长字填充为0A0A0A0A

cp拷贝数据从源地址到目标地址cp[.b,.w,.l] source target [count]

cp.b 80000000 80000100 32:将80000000起始的 32 个字节复制到80000100

③ 网络命令

命令功能格式示例
ping测试网络是否连通ping destipping 192.168.1.100
tftp通过网络利用TFTP协议下载文件到SDRAMtftp [localAddress] [[hostIPaddr:]bootfilename]tftp 80800000 zImage
nfs通过网络利用NFS协议下载文件到SDRAMnfs [localAddress] [[hostIPaddr:]bootfilename]nfs 80800000 192.168.1.100:/home/linux/nfs/zImage

④ mmc操作命令(了解)

MMC(MultiMediaCard)是一种广泛使用的非易失性存储卡标准。在嵌入式开发和底层调试中,mmc命令通常出现在 U-Boot(Universal Boot Loader)环境中,用于管理和操作连接到系统上的 MMC 存储设备,如 SD 卡、eMMC(embedded MMC)等。

命令功能格式示例
mmc info显示当前MMC设备的详细信息,包括容量、类型、时钟频率等mmc infommc info
mmc read从MMC设备读取指定块的数据到内存地址mmc read addr blk cntmmc read 80800000 600 10
mmc write将内存中的数据写入MMC设备的指定块mmc write addr blk cntmmc write 80800000 2 2E6
mmc rescan重新扫描并识别MMC设备,适用于插入新卡或状态异常时mmc rescanmmc rescan
mmc part列出当前MMC设备的所有分区信息mmc partmmc part
mmc dev切换当前操作的MMC设备(0: SD卡, 1: eMMC)mmc dev [dev]mmc dev 0
mmc list列出系统中所有可用的MMC设备及其状态mmc listmmc list
mmc erase擦除MMC设备中指定起始块及数量的扇区mmc erase blk# cntmmc erase 600 10

⑤ boot命令

命令功能描述格式示例
bootz用于启动zImage镜像文件,支持加载内核、初始内存盘(initrd)和设备树(fdt)bootz [addr [initrd [:size] [fdt]]]bootz 80800000 - 83000000
bootm用于启动uImage镜像文件,自动解析并加载内核及可选的ramdiskbootm addrbootm 80800000
boot读取环境变量bootcmd中定义的命令,自动启动Linux系统bootboot
go跳转到指定地址处执行代码,常用于运行裸机程序或自定义应用go addr [arg ...]go 87800000
run运行环境变量中预先定义的命令序列,便于快速执行一组操作run envnamerun mmboot
mmc dev 1 0 tftp 80800000 u-boot.i mmc write 80800000 2 3 mmc partconf 1 1 0 0 注意:千万不要写SD卡或者EMMC的前两个块(扇区),里面保存着分区表!

注:以上命令均在U-Boot命令行环境中使用,适用于嵌入式开发板的引导阶段。实际使用时需确保内存地址正确且数据已正确加载至指定位置。

⑥ 环境变量

(1)bootcmd:bootcmd保存着uboot默认命令, uboot倒计时结束以后就会执行bootcmd中的命令。例如:

1. 从emmc中读取内核、设备树、启动 setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;' saveenv setenv bootcmd '...' 设置 U-Boot 的 bootcmd 环境变量,也就是自动启动命令 mmc dev 1 选择 MMC 设备 1。正点原子 i.MX6ULL 上通常是 eMMC;SD 卡可能是设备 0,具体看板子 fatload mmc 1:1 80800000 zImage 从 MMC 设备 1 的第 1 个分区(FAT 格式)读取 zImage 到内存地址 0x80800000 fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb 从同一个 FAT 分区读取设备树文件到内存地址 0x83000000 bootz 80800000 - 83000000 启动 zImage,没有 initrd,设备树地址为 0x83000000 上电 → U-Boot → mmc dev 1 选择 eMMC → 从 eMMC 分区1 FAT 中读 zImage 和 dtb 到内存 → bootz 启动 Linux 内核 → 内核根据 bootargs 挂载根文件系统 2.从网络中下载内核、设备树、启动 setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ullalientekemmc.dtb;bootz 80800000 - 83000000' saveenv tftp 80800000 zImage 用 TFTP 从服务器下载 zImage 到内存地址 0x80800000 tftp 83000000 imx6ullalientekemmc.dtb 下载设备树文件到内存地址 0x83000000 bootz 80800000 - 83000000 启动 zImage,没有 initrd,设备树地址是 0x83000000 上电 → U-Boot 执行 bootcmd → TFTP 下载 zImage 和设备树 → bootz 启动 Linux 内核 → 内核再根据 bootargs 挂载根文件系统

(2)bootargs:bootargs保存着uboot传递给Linux内核的参数,例如:

1. 从emmc中启动Linux系统: setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw' saveenv setenv bootargs 设置 U-Boot 环境变量 bootargs,Linux 内核启动时会读取它 console=ttymxc0,115200 指定内核控制台为 ttymxc0 串口,波特率 115200。ttymxc0 是 i.MX 系列常见的串口设备名 root=/dev/mmcblk1p2 指定根文件系统在 /dev/mmcblk1p2,即第 2 个 MMC 设备的第 2 个分区,通常是 eMMC 的第二个分区 SD 卡可能是 /dev/mmcblk0 eMMC 可能是 /dev/mmcblk1 分区 2 就是 p2 rootwait 等待根设备出现后再挂载,避免 eMMC/SD 还没初始化好就挂载失败 rw 根文件系统以读写方式挂载。如果想只读,用 ro 2.从nfs网络中启动Linux系统: setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/linux/nfs/rootfs,proto=tcp rw ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off' console=ttymxc0,115200 控制台使用串口 ttymxc0,波特率 115200 root=/dev/nfs 根文件系统使用 NFS nfsroot=192.168.1.100:/home/linux/nfs/rootfs NFS 服务器是 192.168.1.100,共享目录是 /home/linux/nfs/rootfs proto=tcp NFS 使用 TCP 协议 rw 根文件系统以读写方式挂载 ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off 内核网络配置:开发板 IP、服务器 IP、网关、子网掩码、网卡 eth0、关闭自动配置 saveenv 把环境变量保存到 Flash/eMMC,重启后仍然有效 saveenv

(3)完整的uboot环境变量配置

env default -a #uboot 变量恢复默认 saveenv # 保存变量 reset #重启uboot setenv ipaddr 192.168.1.50 # 设置开发板ip地址 setenv ethaddr 00:04:9f:04:d2:35 #设置开发板网卡mac地址 setenv gatewayip 192.168.1.1 #设置开发板网关 setenv netmask 255.255.255.0 #设置开发板子网掩码 setenv serverip 192.168.1.100 #设置pc段的ip地址 setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/linux/nfs/rootfs,v3,proto=tcp rw ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off' #设 置根文件系统的位置 setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-alientekemmc.dtb;bootz 80800000 - 83000000' #设置 下载zImage , dtb saveenv #保存变量 reset #重启uboot

2.2.3 编译uboot

① 解压uboot压缩包,并进入uboot源码目录

tar -zxvf uboot.tar.gz cd uboot

② uboot图形界面是基于ncurses库编写的,所以需要先安装该库

sudo apt-get install libncurses5-dev

③ 编译uboot源码

.config 的来源,作用 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihfmx6ull_alientek_emmc_defconfig make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 ARCH:指定目标硬件架构 CROSS_COMPILE:设置交叉编译工具链 V=0:控制编译输出的详细程度, 0表示启动静默/精简输出模式, 1表示完整的编译命令,便于调试。

④ 生成结果

生成的结果文件主要是位于uboot顶层目录的: u-boot.imx文件

2.2.4 uboot烧录

① 在Ubuntu下利用imxdownload完成u-boot.imx烧写

./imxdownload u-boot.bin /dev/sdd

② 开发板 sd卡启动,启动后需要配置uboot的参数

2.3 内核编译及裁剪

2.3.1 内核概念

内核是操作系统的核心功能代码,是一个大型的开源项目,我们需要对这个源码进行裁剪、编译。我们使用的内核版本为Linux4.1.15 。也就是 linux 操作系统

2.3.1 内核编译

1.先安装必要的工具 sudo apt-get install lzop //lzop 是一个基于 LZO 算法 的命令行无损压缩/解压工具 2.把linux内核复制到虚拟机,解压操作 tar -zxvf linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek.tar.gz ls 3.编译的命令 kconfig, .config ,Makefil cd linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihfimx_alientek_emmc_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig #内核地图,驱动,模块和c文件的关系 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16 4.生成结果 结果文件主要有2个: 内核镜像文件: arch/arm/boot/zImage 设备树文件: arch/arm/boot/dts/imx6ull-alientek-emmc.dtb文件 还有相关的驱动文件 *.ko 5.将编译好的两个文件拷贝到tftp管理目录下 cp arch/arm/boot/zImage ~/tftpboot/ -rf cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb ~/tftpboot/ -rf 6 .重新启动开发板,每次从Ubuntu管理目录下载最新版本的内核和设备树文件

2.4 根文件系统rootfs

① 在/home/linux/nfs 下,复制文件 rootfs.tar.bz2

cd nfs mkdir rootfs sudo tar -xvf rootfs.tar.bz2 #解压的时候,加上sudo,不然可能报错

② 为了开发板可以正常的启动,在次确认,相关选择。
uboot 中的bootargs, 注意 nfsroot=192.168.1.100:/home/linux/nfs/rootfs 。路径一定要对。

bootargs=console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/linux/nfs/rootfs,v3,proto=tcp rw ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off

③ 确认 nfs 的设置

vi /etc/exports /home/linux/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)

2.5 i.MX6ULL 正确启动流程

① i.MX6ULL 正点原子默认启动流程可以概括为:

1. 上电复位,CPU 从片内 Boot ROM 开始运行。 2. Boot ROM 根据拨码开关选择启动设备(SD/eMMC)。 3. 从启动设备偏移 0x400 读取 IVT 到 OCRAM 0x00900000 附近。 4. 解析 IVT、BootData、DCD。 5. Boot ROM 解释 DCD,配置时钟、IOMUX、DDR 控制器等。 6. 根据 BootData 将完整 u-boot.imx 加载到 DDR 0x877FF400。 7. 跳转到 IVT 中的 entry:0x87800000。 8. U-Boot proper 运行: - 重定位代码和向量表 - 初始化外设 - 进入命令行 - 执行 bootcmd 9. U-Boot 加载 zImage 到 0x80800000,dtb 到 0x83000000。 10. bootz 启动内核。 11. zImage 自解压到 0x80008000,内核运行。 12. 内核挂载根文件系统,执行 init。 13. init 启动配置文件/etc/inittab,运行/etc/init.d/rcS脚本,挂载 /etc/fstab,启动终端。

② 阶段 1:Boot ROM(片内固化程序)

(1)i.MX6ULL 上电或复位后,CPU 的程序计数器会指向片内 Boot ROM 的复位入口。复位向量映射到片内 Boot ROM,CPU 从那里开始取指。Boot ROM 是 NXP 出厂固化在芯片内部的只读程序,用户不能修改。它的核心任务只有一个:把外部启动设备中的 U-Boot 镜像搬进 DDR 并跳过去执行。

(2)Boot ROM 首先根据拨码开关检测启动模式:SD、eMMC、NAND、QSPI、USB 串行下载等。正点原子开发板通常通过拨码开关选择 SD 卡或 eMMC 启动。

(3)初始化最基础时钟,例如 ARM PLL、System PLL。Boot ROM 不会完整初始化 DDR 和所有外设时钟。这些复杂配置通常留给 DCD 完成。

(4)从启动设备偏移0x400处读取 IVT 到 OCRAM,常见地址0x00900000附近。对于 SD/eMMC 启动,i.MX6ULL 要求启动镜像的IVT 位于启动设备偏移0x400。Boot ROM 会从该偏移读取 IVT,并放到片内 OCRAM 中。

IVT 中关键字段包括: entry:U-Boot 入口地址 dcd_ptr:DCD 数据位置 boot_data_ptr:Boot Data 位置 self_ptr:IVT 自身地址 csf:安全启动相关

(5)解析u-boot.imx头部:IVT + Boot Data + DCD + u-boot.bin 。

Boot ROM 会解析:

  • IVT:知道入口在哪、DCD 在哪、Boot Data 在哪。

  • Boot Data:知道镜像要加载到 DDR 的哪个地址、镜像多大。

  • DCD:知道要配置哪些寄存器。

(6)执行 DCD 中的寄存器配置序列。DCD 是一串配置命令数据,Boot ROM 解析 DCD,并按 DCD 中的“写寄存器”命令去配置时钟、IOMUX、DDR 控制器等。

(7)DCD 执行完成后,DDR 已经可用。把完整u-boot.bin从启动设备加载到 DDR,常见地址0x87800000

(8)Boot ROM 根据 IVT 中的entry字段,跳转到 DDR 中的 U-Boot 入口,Boot ROM 结束。CPU 开始执行 U-Boot proper。

③ 阶段 2:DCD 配置阶段详细分析(这一阶段不是 U-Boot 自己在运行,而是 Boot ROM 在替 U-Boot 执行 DCD

(1)在 i.MX6ULL 默认 U-Boot 中,没有 SPL。但是可以支持 SPL的。

(2)正点原子默认通常直接使用u-boot.imx,不单独用 SPL。

DCD 通常负责:

(1)关闭看门狗。 (2)设置 CPU 主频、总线时钟,常见 792MHz。 (3)配置 IOMUXC,复用 DDR、SD/eMMC 引脚。 (4)初始化 DDR 控制器,完成 DDR 校准。 (5)配置启动设备相关引脚和控制器。 (6)让 DDR 可用,供 Boot ROM 加载完整 U-Boot。 这些工作由 Boot ROM 执行 DCD 完成,不是 Boot ROM 自己写死的逻辑,也不是 SPL。

*(3)如果启用 SPL,流程才是:

Boot ROM → 加载 SPL 到 OCRAM → SPL 初始化 DDR → 加载 u-boot.img 到 DDR → 跳转 U-Boot proper

④ 阶段 3:U-Boot proper

运行在 DDR,常见入口0x87800000。这是你能看到命令行、能敲printenvsetenvbootz的 U-Boot。

主要工作:

(1)初始化串口、网口、MMC、NAND、USB 等外设。

(2)提供命令行和环境变量。

(3)从 TFTP、SD、eMMC 加载zImage和设备树。

(4)设置bootargs,把参数传给内核。

(5)执行bootz启动 Linux 内核。

注意:DDR 已经在 DCD 阶段初始化好了,U-Boot proper 一般不会重新初始化 DDR。它只是使用 DDR 作为内存空间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 16:43:44

TVA具身智能运行机理(38):如何推动具身智能产业跨越式发展

前沿技术探索:TVA智能体(简称TVA) TVA智能体(亦称“AI智能体视觉”)是依托Transformer架构与“因式智能体”理论构建的新型工业视觉系统,也是当前最具代表性的具身视觉技术之一。它有机融合深度强化学习&a…

作者头像 李华
网站建设 2026/9/24 16:43:12

AI旅游赛道独立开发者怎么切入?4条路径不踩坑

AI旅游市场2026年预计2224亿美元,年增速33.7%,40%旅客已在用AI规划行程。海外Wanderlog积累100万用户,Layla年费49.99美元,已跑通订阅加联盟返佣的双收入模型。但照搬国内会立刻撞墙。 虎嗅网近期复盘的一个踩了五个坑的真实案例&…

作者头像 李华
网站建设 2026/9/24 16:35:07

王者荣耀弱网对抗:帧同步如何扛住460?

地铁,晚高峰,进站前最后三十秒。 你正在开团。屏幕右上角那个绿色的数字,突然变成了刺眼的红色: 460你做好了准备——画面冻结、角色僵直、然后瞬移回城泉水。 但这一次,什么都没发生。 你的技能照常释放,动画照常播放。只是敌人的走位,看起来慢了半拍。 三秒后,数字跳…

作者头像 李华