Linux 内核移植过程学习

简单修改内核

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 分段,链接后变成有序数组,内核启动时循环遍历数组批量调用(集中执行)初始化接口。

相关推荐
SteveSenna1 小时前
aubo学习:设置TCP
学习
茯苓gao2 小时前
嵌入式开发笔记:工业机器人通信协议深度解析——从现场总线到工业以太网
笔记·嵌入式硬件·学习·机器人·信息与通信
取地址符2 小时前
Rust语法学习 (基于Rustlings)(1):基础语法
经验分享·笔记·学习·rust
绝世番茄2 小时前
VisualEffect 视觉特效鸿蒙HarmonyOS ArkTS原生学习
学习·华为·harmonyos·鸿蒙
问简3 小时前
【共享盘】ubuntu、windows
linux·windows·ubuntu
xiaoduzi19913 小时前
ConcurrentHashMap学习
java·学习
zzzll11113 小时前
LangChain实战-RAG问答机器人
学习·计算机·程序员·大模型
霸道流氓气质3 小时前
Java 工程师 AI 智能体学习路线 · 阶段 4:智能体(Agent)核心原理 详解
java·人工智能·学习
小生不才yz3 小时前
Shell脚本精读 · S13-01 | POSIX sh 与 Bash:语法对照表
linux