一、系统移植1.1 系统移植介绍① 系统移植主要指在开发板上运行Linux操作系统涉及硬件驱动开发、Linux系统与硬件设备的兼容适配以及内核层面的编程工作。②将Linux系统移植到开发板的过程中需要完成四个关键组件的移植BootloaderU-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 嵌入式 LinuxARM、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芯片内部固化最底层启动 SPLU-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/sdbc. 将mfgtool\Profiles\Linux\OS Firmware目录下的files文件夹拷贝到Ubuntu系统中。(imx6mksdboot.sh脚本需要修复下将${PARITION2} -修改为 ${PARTITION2})d. 进入files对应的目录执行脚本sudo ./imx6mksdboot.sh -device /dev/sdb -flash emmc -ddrsize 512e. 等待命令执行完成显示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 minicomc.测试与主机是否网络连通。ping 192.168.1.100d.将开发板的/mnt目录挂载到Ubuntu主机的共享目录下形成共享文件夹此操作是在minicom中操作开发板mount -o nolock,rw,nfsvers3 192.168.1.100:/home/linux/nfs/rootfs /mnte.将mfgtool\Profiles\Linux\OS Firmware目录下的files文件夹拷贝到Ubuntu系统的/home/linux/nfs/rootfs目录下。f.为imx6mkemmcboot.sh文件加上执行权限。chmod x /home/linux/nfs/rootfs/imx6mkemmcboot.shg.在开发板中执行烧录脚本此操作是在minicom中操作开发板h. 进入/mnt/files对应的目录执行脚本cd /mnt/files ./imx6mkemmcboot.sh -device /dev/mmcblk1 -ddrsize 512i. 等待命令执行完成显示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 consolettymxc0,115200 root/dev/nfs nfsroot192.168.1.100:/home/linux/nfs/rootfs,v3,prototcp rw ip192.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.MX6ULLDDR 通常起始于 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 放到 0x80800000zImage 内部的自解压程序依然会按照自己预设的地址去解压和运行。 要真正修改内核启动地址你需要 重新配置并编译内核修改内核配置如 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 dtbh. 设置bootargs对内核传参。setenv bootargs consolettymxc0,115200 root/dev/nfs nfsroot192.168.1.100:/home/linux/nfs/rootfs,v3,prototcp rw ip192.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.imxdtb设备树文件脚本会把所有的设备树文件进行烧写在uboot阶段配置选择加载的设备树文件zImagec. 将自己的根文件系统压缩并存放在filesystem目录;d.烧写自己的镜像;sudo ./imx6mksdboot.sh -device /dev/sdb -flash emmc -ddrsize 512f.烧录成功后我们需要设置uboot的启动方式,常见的启动方式有;1. EMMC启动Linux系统 setenv bootargs consolettymxc0,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 consolettymxc0,115200 root/dev/mmcblk1p2 rootwait rw setenv bootcmd tftp 80800000 zImage; tftp 83000000 imx6ullalientekemmc.dtb; bootz 80800000 - 83000000 saveenv⑥ 使用mobaxterm(Windows 串口工具)这个工具功能和minicom 一致。两者挑一个就可以了。a. 连接开发板的串口, usb 转typecb. 双击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: Nonef.点击 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 consolettymxc0,115200 root/dev/nfs nfsroot192.168.1.100:/home/linux/nfs/rootfs_imx,prototcp rw ip192.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 reseth.重新启动开发板即可进入开发板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查看当前系统中所有环境变量printenvsetenv新建或修改环境变量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 valuenm.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.100tftp通过网络利用TFTP协议下载文件到SDRAMtftp [localAddress] [[hostIPaddr:]bootfilename]tftp 80800000 zImagenfs通过网络利用NFS协议下载文件到SDRAMnfs [localAddress] [[hostIPaddr:]bootfilename]nfs 80800000 192.168.1.100:/home/linux/nfs/zImage④ mmc操作命令(了解)MMCMultiMediaCard是一种广泛使用的非易失性存储卡标准。在嵌入式开发和底层调试中mmc命令通常出现在 U-BootUniversal Boot Loader环境中用于管理和操作连接到系统上的 MMC 存储设备如 SD 卡、eMMCembedded MMC等。命令功能格式示例mmc info显示当前MMC设备的详细信息包括容量、类型、时钟频率等mmc infommc infommc read从MMC设备读取指定块的数据到内存地址mmc read addr blk cntmmc read 80800000 600 10mmc write将内存中的数据写入MMC设备的指定块mmc write addr blk cntmmc write 80800000 2 2E6mmc rescan重新扫描并识别MMC设备适用于插入新卡或状态异常时mmc rescanmmc rescanmmc part列出当前MMC设备的所有分区信息mmc partmmc partmmc dev切换当前操作的MMC设备0: SD卡, 1: eMMCmmc dev [dev]mmc dev 0mmc list列出系统中所有可用的MMC设备及其状态mmc listmmc listmmc erase擦除MMC设备中指定起始块及数量的扇区mmc erase blk# cntmmc erase 600 10⑤ boot命令命令功能描述格式示例bootz用于启动zImage镜像文件支持加载内核、初始内存盘initrd和设备树fdtbootz [addr [initrd [:size] [fdt]]]bootz 80800000 - 83000000bootm用于启动uImage镜像文件自动解析并加载内核及可选的ramdiskbootm addrbootm 80800000boot读取环境变量bootcmd中定义的命令自动启动Linux系统bootbootgo跳转到指定地址处执行代码常用于运行裸机程序或自定义应用go addr [arg ...]go 87800000run运行环境变量中预先定义的命令序列便于快速执行一组操作run envnamerun mmbootmmc dev 1 0 tftp 80800000 u-boot.i mmc write 80800000 2 3 mmc partconf 1 1 0 0 注意千万不要写SD卡或者EMMC的前两个块扇区里面保存着分区表注以上命令均在U-Boot命令行环境中使用适用于嵌入式开发板的引导阶段。实际使用时需确保内存地址正确且数据已正确加载至指定位置。⑥ 环境变量1bootcmdbootcmd保存着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 上通常是 eMMCSD 卡可能是设备 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 挂载根文件系统2bootargsbootargs保存着uboot传递给Linux内核的参数例如1. 从emmc中启动Linux系统 setenv bootargs consolettymxc0,115200 root/dev/mmcblk1p2 rootwait rw saveenv setenv bootargs 设置 U-Boot 环境变量 bootargsLinux 内核启动时会读取它 consolettymxc0,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 consolettymxc0,115200 root/dev/nfs nfsroot192.168.1.100:/home/linux/nfs/rootfs,prototcp rw ip192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off consolettymxc0,115200 控制台使用串口 ttymxc0波特率 115200 root/dev/nfs 根文件系统使用 NFS nfsroot192.168.1.100:/home/linux/nfs/rootfs NFS 服务器是 192.168.1.100共享目录是 /home/linux/nfs/rootfs prototcp NFS 使用 TCP 协议 rw 根文件系统以读写方式挂载 ip192.168.1.50:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off 内核网络配置开发板 IP、服务器 IP、网关、子网掩码、网卡 eth0、关闭自动配置 saveenv 把环境变量保存到 Flash/eMMC重启后仍然有效 saveenv3完整的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 consolettymxc0,115200 root/dev/nfs nfsroot192.168.1.100:/home/linux/nfs/rootfs,v3,prototcp rw ip192.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 #重启uboot2.2.3 编译uboot① 解压uboot压缩包并进入uboot源码目录tar -zxvf uboot.tar.gz cd uboot② uboot图形界面是基于ncurses库编写的所以需要先安装该库sudo apt-get install libncurses5-dev③ 编译uboot源码.config 的来源作用 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- distclean make ARCHarm CROSS_COMPILEarm-linux-gnueabihfmx6ull_alientek_emmc_defconfig make V0 ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -j16 ARCH指定目标硬件架构 CROSS_COMPILE设置交叉编译工具链 V0控制编译输出的详细程度 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 ARCHarm CROSS_COMPILEarm-linux-gnueabihf- distclean make ARCHarm CROSS_COMPILEarm-linux-gnueabihfimx_alientek_emmc_defconfig make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- menuconfig #内核地图驱动模块和c文件的关系 make ARCHarm CROSS_COMPILEarm-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.bz2cd nfs mkdir rootfs sudo tar -xvf rootfs.tar.bz2 #解压的时候加上sudo不然可能报错② 为了开发板可以正常的启动在次确认相关选择。uboot 中的bootargs 注意 nfsroot192.168.1.100:/home/linux/nfs/rootfs 。路径一定要对。bootargsconsolettymxc0,115200 root/dev/nfs nfsroot192.168.1.100:/home/linux/nfs/rootfs,v3,prototcp rw ip192.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 中的 entry0x87800000。 8. U-Boot proper 运行 - 重定位代码和向量表 - 初始化外设 - 进入命令行 - 执行 bootcmd 9. U-Boot 加载 zImage 到 0x80800000dtb 到 0x83000000。 10. bootz 启动内核。 11. zImage 自解压到 0x80008000内核运行。 12. 内核挂载根文件系统执行 init。 13. init 启动配置文件/etc/inittab运行/etc/init.d/rcS脚本挂载 /etc/fstab启动终端。② 阶段 1Boot ROM片内固化程序1i.MX6ULL 上电或复位后CPU 的程序计数器会指向片内 Boot ROM 的复位入口。复位向量映射到片内 Boot ROMCPU 从那里开始取指。Boot ROM 是 NXP 出厂固化在芯片内部的只读程序用户不能修改。它的核心任务只有一个把外部启动设备中的 U-Boot 镜像搬进 DDR 并跳过去执行。2Boot 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 中关键字段包括 entryU-Boot 入口地址 dcd_ptrDCD 数据位置 boot_data_ptrBoot Data 位置 self_ptrIVT 自身地址 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 控制器等。7DCD 执行完成后DDR 已经可用。把完整u-boot.bin从启动设备加载到 DDR常见地址0x87800000。8Boot ROM 根据 IVT 中的entry字段跳转到 DDR 中的 U-Boot 入口Boot ROM 结束。CPU 开始执行 U-Boot proper。③ 阶段 2DCD 配置阶段详细分析这一阶段不是 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④ 阶段 3U-Boot proper运行在 DDR常见入口0x87800000。这是你能看到命令行、能敲printenv、setenv、bootz的 U-Boot。主要工作1初始化串口、网口、MMC、NAND、USB 等外设。2提供命令行和环境变量。3从 TFTP、SD、eMMC 加载zImage和设备树。4设置bootargs把参数传给内核。5执行bootz启动 Linux 内核。注意DDR 已经在 DCD 阶段初始化好了U-Boot proper 一般不会重新初始化 DDR。它只是使用 DDR 作为内存空间。