简单修改内核
1.内核启动流程
内核目录如下:
bash
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$
1.1修改Makefile

修改Makefile中上述位置如下
c
//arm架构
ARCH ?= ARM
交叉编译工具链时arm-linux-
CROSS_COMPILE ?= arm-linux-
bash
//查看编译链版本信息
arm-linux-gcc -v

1.2使用默认配置
在内核中查找默认配置
bash
find -name "*defconfig"

查找到有不同的架构。arm架构在 arch/arm 目录下。
先在设备树中修改设备树中的晶振频率。在内核根目录执行下面命令在内核根目录下生成 .config
bash
make 100ask_imx6ull_defconfig
1.3make uImage
执行
bash
make uImage
生成的内核在 arch/arm/boot/uImage
使用u-boot命令设置machine id ,如果没有设置machid就会使用默认id。设置 machine id适用于无设备树的老平台
bash
set machid 33245
save
在内核源码 linux-4.1.15/arch/arm/tools/mach-types 中找到 machine id

- machine_is_xxx:内核代码判断板子用的宏,比如 machine_is_smdk2440()
- CONFIG_xxxx:内核编译开关,make xxx_defconfig 会开启这个配置
- MACH_TYPE_xxx:U-Boot / 内核头文件里的宏名,如 MACH_TYPE_SMDK2440
- number:十进制机器 ID(你 set machid 后面填的数字,也可转十六进制输入)
对应imx6ull,u-boot命令修改串口波特率
bash
set bootargs console=ttymxc0,115200 root=/dev/mmcblk1p2 rootfstype=ext4
saveenv
ttymxc0是NXP的串口驱动命名,/dev/mmcblk1p2 开发板板载 SD 卡(mmc1),mmcblk1p1 SD卡1分区。
标准双分区布局
mmcblk1p1(FAT32)
存放:u-boot.bin、zImage、imx6ull-xxx.dtb(内核 + 设备树,U‑Boot 读取)
mmcblk1p2(ext4)
存放:完整 Linux 根文件系统,bootargs 里 root=/dev/mmcblk1p2
使用u-boot里的nfs命令把内核文件下载到内存如下:
0x32000000 把 PC 下载的完整 uImage(带 64 字节头部的压缩内核)临时存在这里。
bash
nfs 0x32000000 192.168.1.123:/work/nfs_root/uImage_new
u-boot命令启动内核:
bash
bottom 32000000
修改分区和制作根文件系统
修改分区
对于 eMMC 焊死在开发板 PCB 上,无法读卡器直插 PC;不直接 PC 操作 eMMC,PC 先使用fdisk工具制作带完整分区的 TF 卡,将uboot、zImage、dtb通过 TF 卡下载镜像整块写入 eMMC。
制作根文件系统
环境说明
1.PC Ubuntu 终端:编译 BusyBox、复制库、构建 rootfs、编译内核、制作 ext4 镜像
2.开发板 U-Boot 串口:配置网络、烧写镜像、设置 bootargs、启动内核
3.工程根目录:~/100ask_imx6ull-sdk
4.交叉工具链路径:~/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf
5.目标根文件系统目录:~/100ask_imx6ull-sdk/rootfs
6.平台特性:设备树架构,无 machid;串口ttymxc0;存储使用 SD/eMMC+ext4,不使用 JFFS2/YAFFS2
一、前置环境配置(PC Ubuntu)
1.配置交叉编译器环境变量
bash
# 打开环境变量配置文件
vim ~/.bashrc
# 在末尾添加
export PATH=$PATH:~/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
# 生效配置
source ~/.bashrc
# 验证编译器是否可用
arm-linux-gnueabihf-gcc -v
也可以将Toolchain信息添加到Busybox的根目录下的Makefiel中。
二、交叉编译安装 BusyBox(PC Ubuntu)(建议编译内核和应用使用同一个编译器)
1.进入 BusyBox 源码目录
bash
cd ~/100ask_imx6ull-sdk/busybox-1.29.0
2.图形化配置
bash
# 先加载默认配置,在根目录下生成基础.config配置文件
make defconfig
bash
# 图形化裁剪功能
# Busybox Setting -> Build Options -> Cross Compiler prefix 修改为 arm-linux-
make menuconfig
3.编译并安装到 rootfs 目录(提前创建rootfs目录)
bash
# 使用CONFIG_PREFIX指定安装目录
make install CONFIG_PREFIX=~/100ask_imx6ull-sdk/rootfs
此时在rootfs中已具备:
- 完整 shell(ash/hush)、文件操作命令:ls、cp、mv、mkdir、rm
- 网络工具:ifconfig、ip、ping、route、httpd
- 系统管理:init、reboot、halt、mdev、mount、insmod
- 文本工具:vi、sed、grep、echo
- 内核启动入口 linuxrc
rootfs目录下此时有 bin、linuxrc、 sbin、 usr 目录。
在roofts/bin目录中命令文件均为软链接,不存储任何程序代码,仅记录指向 busybox 的相对路径。当开发板执行 ls 命令时:
- 系统读取 bin/ls,识别到是软链接,跳转至实体文件 busybox;
- 操作系统将链接文件名 ls 作为参数传入 busybox;
- busybox 内部根据传入文件名匹配对应功能,执行列出目录的逻辑。
执行 ls rootfs/bin/ -l 命令输出:
bash
# 首字符l代表该文件为软连接
# ls是用户输入的命令名、链接文件名
# -> busybox代表此链接指向同目录下的实体程序 busybox
lrwxrwxrwx 1 book book 7 7月 4 10:00 ls -> busybox
roofts/bin目录:存放管理员系统底层操作命令(重启、驱动、分区、挂载)。
roofts/usr/bin :上层普通工具,非开机必需,日常辅助命令:find、du、df、grep、sed 等。
rootfs/usr/sbin:上层管理工具,网络服务、后台程序:httpd、telnetd 等小型服务器工具。
roofts/linuxrc:根目录顶层独立软链接文件,指向 roofts/bin/busybox,是内核挂载根文件系统后执行的首个程序,负责启动系统初始化流程。
三、复制交叉编译器 GLIBC 动态库(PC Ubuntu,修正正确路径)
执行 echo $PATH 输出交叉编译工具链位置:
bash
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bn:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
1.创建存放库的目录
bash
# -p 选项一次性创建usr、lib两个目录
mkdir -p ~/100ask_imx6ull-sdk/rootfs/lib
mkdir -p ~/100ask_imx6ull-sdk/rootfs/usr/lib
2.复制核心 glibc 系统库(必须,含 ld-linux-armhf.so.3 动态加载器)
bash
# -d 选项将原来的链接文件依旧作为链接文件拷贝,减小文件体积
cp ~/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/*.so* ~/100ask_imx6ull-sdk/rootfs/lib -d
3.复制 GCC/C++ 运行时动态库(运行 C++ 程序必备)
bash
cp ~/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib/*.so* ~/100ask_imx6ull-sdk/rootfs/lib -d
4.复制 usr 应用层库文件
bash
cp ~/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib/*.so* ~/100ask_imx6ull-sdk/rootfs/usr/lib -d
说明:仅复制*.so*动态库,.a静态库、.la、ldscripts、.o无需复制。./libc/lib、./libc/usr/lib中的库只满足运行C程序,若想运行C++程序,还要拷贝 ./lib 中C++相关的依赖库。
四、构建根文件系统标准目录(PC Ubuntu)
查看完整文档文件夹内容
bash
ls Busybox_1.30.0/docs/
1.拷贝 /etc 系统配置模板
bash
cp -r ~/100ask_imx6ull-sdk/etc_template/* ~/100ask_imx6ull-sdk/rootfs/etc
etc/fstab、init.d、inittab ,内核启动的第一个进程就会打开 inittab ,之后根据 inittab 的内容执行 init.d/rcS 脚本,脚本中的 mount -a 就是根据fstab 文件的内容挂接各种根文件系统。
2./dev 设备目录说明
bash
mkdir dev
# 手动创建设备节点 c:表示字符设备 5:主设备号 1:次设备号,内核打印日志、串口终端输入输出都依赖 /dev/console
sudo mknod dev/console c 5 1
# 空设备节点,写入任何数据都会直接丢弃,读取永远返回空;常用场景:屏蔽程序输出
sudo mknod dev/null c 1 3
程序输出屏蔽示例:
bash
# 把程序打印全部丢进黑洞,不输出到串口
./test > /dev/null
手动创建这两个节点,在 init.d/rcS 脚本中的 mdev -s 会自动创建dev中的其他内容。
只要内核同时开启两个配置:CONFIG_DEVTMPFS=y + CONFIG_DEVTMPFS_MOUNT=y,NXP 全系列 i.MX 平台完全不需要提前手动在rootfs 里创建任何设备文件。但是要先存在 rootfs/dev 空目录作为挂载点。
3.创建 Linux 标准空目录
bash
cd ~/100ask_imx6ull-sdk/rootfs
mkdir proc sys mnt tmp var root mnt/nfs mnt/mmc
- /proc、/sys:内核虚拟文件系统
- /tmp、/var:临时文件、运行日志
- /mnt:外挂存储挂载点
五.打包 ext4 镜像(用于 SD/eMMC 量产烧录,PC Ubuntu)
bash
# 1. 生成128M空白镜像文件
dd if=/dev/zero of=rootfs.ext4 bs=1M count=128
# 2. 格式化为ext4文件系统
mkfs.ext4 -F rootfs.ext4
参考:
https://www.cnblogs.com/fuzidage/p/18019053
编译并下载内核镜像及根文件系统
一、编译 Linux 内核(PC Ubuntu,生成 zImage + dtb 设备树)
编译前的准备
1.defconfig
将要编译要的 imx6ull_100ask_defconfig 放到 arch/arm/configs 目录下,按照芯片架构修改 imx6ull_100ask_defconfig 中的内容。
2.dtb
将要编译的 xxx_xxx_xxx.dts 文件放到 arch/arm/boot/dts 目录下,修改 arch/arm/boot/dts/Makefile ,找到"dtb-$(CONFIG_SOC_IMX6ULL)"配置项,在此配置项中加入"xxx_xxx_xxx.dtb"。不然编译的时候是不会编译刚添加的这个设备树的。
bash
cd ~/100ask_imx6ull-sdk/Linux-4.9.88
# 加载100ask imx6ull默认内核配置,打开eabi支持防止出现非法指令报错
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx6ull_100ask_defconfig
# 并行编译内核镜像与设备树
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs -j4
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage -j4
二、文件下载、固化
uboot命令网络配置示例:
初始化网络参数(仅首次配置,永久保存)
bash
# 开发板静态IP
set ipaddr 192.168.1.50
# PC Ubuntu主机NFS服务器IP
set serverip 192.168.1.123
# 保存到Flash,重启不丢失
saveenv
1.下载、固化U-Boot
ROM中有精简的TFTP服务端程序,可以直接用来传输uboot。
bash
# 1.TFTP下载u-boot.imx固件到DDR缓存
tftp 0x80800000 u-boot.imx
# 2.切换到eMMC设备
mmc dev 1
# 3.擦除eMMC头部裸区存放uboot的扇区
mmc erase 0 0x400
# 4.将DDR内uboot裸写入eMMC头部起始扇区0(裸区写入uboot)
mmc write 0x80800000 0 $filesize
# 烧写完成重启,新U-Boot生效
reset
2.DDR临时启动
1.TFTP 下载 zImage 内核到 DDR
bash
tftp 0x80800000 zImage
2.TFTP 下载 dtb 设备树到 DDR
bash
tftp 0x83000000 imx6ull-100ask.dtb
3.配置 NFS 网络根文件系统启动参数
DDR 调试启动不走 "下载 rootfs 镜像到 DDR",是为了节省内存、加快启动、方便实时调试。
bash
# 根文件系统走网络 NFS 挂载
set bootargs console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.123:/home/book/100ask_imx6ull-sdk/rootfs ip=192.168.1.50:192.168.1.123::255.255.255.0::eth0:off rootfstype=ext4 rw
4.DDR 内存直接拉起内核启动
bash
bootz 0x80800000 - 0x83000000
3.eMMC本地固化启动(上面U-Boot已经固化到emmc)
eMMC 分区结构前置说明(裸区 / FAT32 /ext4 三区划分)
i.MX6ULL eMMC 整体分为裸存储区(RAW 裸区)、FAT32 Boot 分区、ext4 根文件分区三块,扇区物理隔离、互不重叠:
裸区(RAW 无文件系统,全局扇区 0 ~ 0xFFFFF):
- 无格式化、无文件系统,存放 U-Boot 固件、U-Boot 环境变量分区表;
- 使用 mmc write 裸扇区读写,直接操作物理块;
- 上电 SOC BootROM 优先读取该区域 U-Boot 引导程序。
mmc1:1 FAT32 分区(全局起始扇区 0x100000 前,裸区末尾分界):
- 标准 FAT32 文件系统,存放 zImage 内核、imx6ull-100ask.dtb 设备树;
- U-Boot 通过 fatload / fatwrite 按文件名称读写,自动管理分区内偏移。
mmcblk1p2 ext4 分区(全局起始扇区 0x100000):
- Linux 标准 ext4 文件系统,存放完整 rootfs.ext4 根文件系统;
- U-Boot 无 ext4 读写能力,只能通过 mmc write 整块镜像裸写入扇区;
- Linux 内核启动后挂载该分区作为系统根目录。
1.固化 zImage 内核到 eMMC FAT32 boot 分区 mmc1:p1
bash
# uboot命令NFS下载内核镜像到DDR缓存
# 0x80800000:DDR 内存起始物理地址,存放下载的 zImage;i.MX6ULL 标准加载地址,避开栈、环境变量占用区
# 192.168.1.123:NFS 服务器(Ubuntu 电脑)IP,对应前面serverip配置
# :/xxx/zImage:主机 NFS 共享目录下内核文件完整路径
nfs 0x80800000 192.168.1.123:/home/book/100ask_imx6ull-sdk/Linux-4.9.88/arch/arm/boot/zImage
# 切换选中板载eMMC设备
# mmc:U-Boot 操作存储介质指令
# dev 1:切换存储设备,dev 0=SD 卡,dev 1= 板载 eMMC
mmc dev 1
# FAT文件系统写入zImage到FAT32分区1,仅操作boot分区内部空间,不触碰裸区与ext4根文件扇区
# fatwrite:向 FAT 文件系统写入文件(仅 FAT32 分区可用)
# mmc 1:1:存储设备 + 分区号,1=eMMC,1= 第 1 个分区(FAT32 boot 分区)
# 0x80800000:源地址,DDR 中 zImage 存放位置
# zImage:写入 FAT 分区后的文件名,启动时fatload按此名称读取
# $filesize:U-Boot 内置环境变量,自动记录上一条 nfs/tftp 下载文件的字节大小,不用手动填镜像长度
fatwrite mmc 1:1 0x80800000 zImage $filesize
2.固化 dtb 设备树到 eMMC FAT32 boot 分区 mmc1:p1
bash
# NFS下载dtb到DDR缓存
nfs 0x83000000 192.168.1.123:/home/book/100ask_imx6ull-sdk/Linux-4.9.88/arch/arm/boot/dts/imx6ull-100ask.dtb
# 写入FAT32 boot分区文件系统
fatwrite mmc 1:1 0x83000000 imx6ull-100ask.dtb $filesize
3.固化 rootfs.ext4 根文件系统到 eMMC ext4 第二分区 mmcblk1p2
bash
# NFS下载完整ext4根文件系统镜像到DDR
nfs 0x80800000 192.168.1.123:/home/book/100ask_imx6ull-sdk/rootfs.ext4
# 选中eMMC设备
mmc dev 1
# 裸盘扇区写入:从全局绝对扇区0x100000开始覆盖ext4完整分区,U-Boot不支持ext4,只能绕过文件系统直接裸写磁盘
# mmc write:裸扇区写入命令,不识别文件系统,直接按扇区覆盖存储介质
# 0x80800000:源 DDR 地址,存放完整 rootfs.ext4 镜像
# 0x100000:eMMC 全局绝对起始扇区扇区, 0 ~ 0xFFFFF:eMMC 裸区 + mmc1:1 FAT32 boot 分区,从 0x100000 扇区开始:对应 mmcblk1p2 ext4 根文件分区
# $filesize:rootfs 镜像总字节数,U-Boot 自动换算占用扇区数量,完整覆盖第二分区
mmc write 0x80800000 0x100000 $filesize
4.配置 eMMC 本地启动环境变量
bash
# 设置内核启动参数,告知Linux根文件系统位于eMMC ext4第二分区mmcblk1p2
# console=ttymxc0,115200:串口控制台配置,串口 0,波特率 115200,内核日志打印到此串口
# root=/dev/mmcblk1p2:指定根文件系统设备,eMMC 第 2 个逻辑分区
# rootfstype=ext4:告诉内核该分区文件系统格式为 ext4
# rw:根分区挂载为可读可写,不加则默认只读
set bootargs console=ttymxc0,115200 root=/dev/mmcblk1p2 rootfstype=ext4 rw
# 配置上电自动执行eMMC本地启动脚本bootcmd:从FAT32分区读取zImage/dtb到DDR启动
set bootcmd "mmc dev 1; fatload mmc 1:1 0x80800000 zImage; fatload mmc 1:1 0x83000000 imx6ull-100ask.dtb; bootz 0x80800000 - 0x83000000"
# 永久保存所有环境变量至eMMC裸区,断电不丢失
# 将所有 set 配置的变量(ipaddr、bootargs、bootcmd 等)保存到 eMMC 硬件 BOOT 裸区,断电不丢失。
saveenv
脚本内容解释:
bootcmd:上电自动执行的启动脚本,分 4 条指令用;分隔串行执行:
- mmc dev 1:选中 eMMC 设备
- fatload mmc 1:1 0x80800000 zImage:从 eMMC p1 FAT 分区读取 zImage 到 DDR 0x80800000
- fatload mmc 1:1 0x83000000 imx6ull-100ask.dtb:读取 dtb 到 DDR 0x83000000
- bootz 内核地址 - dtb地址:拉起 zImage 启动
bootz:启动 zImage 格式内核的专用命令
中间-:无 ramdisk 内存盘,填空占位
5.测试 eMMC 本地启动
不重启开发板,直接手动执行启动流程验证镜像是否正常:
bash
run bootcmd
无启动报错后,重启开发板即可自动从 eMMC 裸区 U-Boot 引导,读取 FAT32 分区内核、挂载 ext4 分区根文件系统完整本地运行。(记得将拨码开关选择到emmc启动,ROM 只会从你拨码选定的存储介质加载引导程序(uboot))
三、根文件系统添加 etc 配置脚本
创建/etc/init.d/rcS
rcS 是个 shell 脚本,Linux 内核启动以后需要启动一些服务,而 rcS 就是规定启动哪些文件的脚本文件。在 rootfs 中创建/etc/init.d/rcS 文件,然后在 rcS 中输入如下所示内容:
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
PATH 环境变量保存着可执行文件可能存在的目录;
LD_LIBRARY_PATH 环境变量保存着库文件所在的目录;
mount 命令来挂载所有的文件系统,这些文件系统由文件/etc/fstab 来指定;
创建目录/dev/pts,然后将 devpts 挂载到/dev/pts 目录中。
使用 mdev 来管理热插拔设备,通过这两行,Linux 内核就可以在/dev 目录下自动创建设备节点。
这只是一个很简单的rcS。
bash
chmod 777 rcS
重新启动 Linux 内核生效。
创建/etc/fstab
fstab 在 Linux 开机以后自动配置哪些需要自动挂载的分区,6列格式如下:
第一列:要挂载的特殊的设备,也可以是块设备,比如/dev/sda 等等
第二列:挂载点。
第三列:文件系统类型,比如 ext2、ext3、proc、romfs、tmpfs 等等。
第四列:挂载选项,一般使用 defaults,defaults 包含了 rw、suid、 dev、 exec、 auto、 nouser 和 async。
第五列:为 1 的话表示允许备份,为 0 不备份,一般不备份,因此设置为 0。
第六列:磁盘检查设置,为 0 表示不检查。根目录'/'设置为 1,其他的都不能设置为 1,因此这里一般设置为 0
配置如下:

fstab 文件创建完成以后重新启动 Linux打印如下:

自动挂载成功。
创建/etc/inittab
inittab 的详细内容可以参考 busybox 下的文件 examples/inittab。init 程序会读取/etc/inittab这个文件,inittab 由若干条指令组成。
busybox 支持的动作如下:
sysinit: 在系统初始化的时候 process 才会执行一次。
respawn: 当 process 终止以后马上启动一个新的。
askfirst:和 respawn 类似,在运行 process 之前在控制台上显示"Please press Enter to activate this console."。只要用户按下"Enter"键以后才会执行 process。
wait: 告诉 init,要等待相应的进程执行完以后才能继续执行。
once: 仅执行一次,而且不会等待 process 执行完成。
restart: 当 init 重启的时候才会执行 procee。
ctrlaltdel: 当按下 ctrl+alt+del 组合键才会执行 process。
shutdown: 关机的时候执行 process。

# 系统启动以后运行/etc/init.d/rcS 这个脚本文件。
::sysinit:/etc/init.d/rcS
# 将 console 作为控制台终端,也就是 ttymxc0。
console::askfirst:-/bin/sh
# 重启的话运行/sbin/init。
::restart:/sbin/init
# 按下 ctrl+alt+del 组合键的话就运行/sbin/reboot,看来 ctrl+alt+del 组合键用于重启系统。
::ctrlaltdel:/sbin/reboot
# 关机的时候执行/bin/umount,也就是卸载各个文件系统。
::shutdown:/bin/umount -a -r
# 关机的时候执行/sbin/swapoff,也就是关闭交换分区。
::shutdown:/sbin/swapoff -a
创建/etc/reslov.conf
/etc/resolv.conf是DNS客户机配置文件,用于设置DNS服务器的IP地址及DNS域名,还包含了主机的域名搜索顺序。该文件是由域名解析器(resolver,一个根据主机名解析IP地址的库)使用的配置文件。如果这个文件为空那板子只能ping IP,不能ping网址。
DNS = Domain Name System,域名系统,核心作用:把好记的域名翻译成计算机能看懂的 IP 地址。
nameserver: 配置DNS服务器地址(顺序来查询,且只有当第一个nameserver没有反应时才查询下面的nameserver)
domain: 声明主机的域名,当查询不完全的域名时主机名将被使用(相当于search的默认值)
search: 它的多个参数指明域名查询顺序。当查询不完全的域名时会使用到(domain和search不能共存)
参考文章:
https://www.cnblogs.com/fuzidage/p/18019053
四、常见报错与解决方案
1.SIGILL illegal instruction 非法指令
原因:交叉工具链为 EABI 标准,内核未开启 EABI 支持
解决:make menuconfig → Kernel Features → 勾选 EABI support,重新编译内核。
2.提示 cannot load library ld-linux-armhf.so.3
原因:仅复制 gcc 库,缺失 libc 核心动态库
解决:重新执行拷贝完整libc/lib下的.so*文件。
3.串口无输出、乱码
- bootargs 串口必须写ttymxc0,不能使用ttySAC0;
- U-Boot 串口波特率 115200 与 bootargs 保持一致;
- 设备树中 24M 晶振clock-frequency = <24000000>与硬件匹配。
对于无设备树 ATAG 架构(旧平台)(例:S3C2440):
步骤一:
设置machine id
步骤二:
在.c文件中修改外接晶振频率
步骤三:
编译默认配置,编译内核
步骤四:
在uboot中指定波特率
而对于NXP设备树平台 i.MX6ULL,一二步均在设备树文件中修改,第三步添加编译设备树文件。对于没有设备树的平台需要去修改对应的.c文件。
板子上电启动流程
i.MX6ULL 芯片出厂时,内部焊死了一段不可擦除的 ROM 固件,它不依赖 eMMC 里有没有 U-Boot,上电第一时间自动执行。
空板完整烧写流程:
1.拨码切换为网口下载模式;
2.上电,ROM 自动初始化网口,等待 TFTP 服务器传输 u-boot.imx;
3.PC 开 TFTP 服务器,上传 u-boot.imx,ROM 下载到 DDR 并启动 U-Boot;
4.进入 U-Boot 命令行,此时拥有nfs/mmc全部命令;
5.用 nfs 下载 zImage/dtb/rootfs,执行mmc write全部固化到 eMMC;
6.拨码切回 eMMC 启动,后续上电直接跑 eMMC 里的 U-Boot,不用再依赖网络。
内核启动流程
https://www.cnblogs.com/fuzidage/p/17995165

bootloader:
- 将内核读入内存
- 设置TAG参数
- 启动:
R0 = 0
R1 = machid
R2 = TAG参数地址
内核:
- 根据R1,判断能否支持该机器,调用机器相关的初始化函数
- 解析TAG参数
- 装载驱动程序
- 挂载根文件系统
- 启动应用程序
initcall机制:
用宏把各个子系统 / 驱动的初始化函数指针,按优先级分门别类放进 ELF 不同小节;链接时自动拼成有序数组,内核启动统一遍历挨个调用。
各个模块用宏(分散注册,各个模块各写一行initcall宏)把初始化函数地址注册到指定 ELF 分段,链接后变成有序数组,内核启动时循环遍历数组批量调用(集中执行)初始化接口。