目录
[1. root=/dev/nfs](#1. root=/dev/nfs)
[2. nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs,nfsvers=3](#2. nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs,nfsvers=3)
[3. ip=192.168.1.123](#3. ip=192.168.1.123)
[4. console=ttymxc0,115200](#4. console=ttymxc0,115200)
[5. init=/linuxrcroot](#5. init=/linuxrcroot)
[1.将内核源码包拷贝到 Ubuntu 下,并解压到工作目录:](#1.将内核源码包拷贝到 Ubuntu 下,并解压到工作目录:)
2.向内核新增文件(以向drivers/char目录下新增demo.c为例):
[1.Kconfig 文件介绍(以添加 ABC 为例)](#1.Kconfig 文件介绍(以添加 ABC 为例))
[1. make zImage不了](#1. make zImage不了)
2.没有网口使用usb转网口转换器会出现开发板和虚拟机无法ping通
[3.启动内核出现类似no soundscard的报错提示](#3.启动内核出现类似no soundscard的报错提示)
一、Linux操作系统概述
1.操作系统
操作系统可以被看做是一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核。内核的接口被称为系统调用。公用的函数库构建在系统调用接口之上,应用程序可以使用公用函数库,也可以使用系统调用。shell是一种特殊的应用程序,为运行其他应用提供了一个接口。

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

进程调度:进程调度控制系统中的多个进程对CPU的访问。
内存管理:内存管理作用是控制多个进程安全地共享主内存区域。
虚拟文件系统:Linux虚拟文件系统隐藏了各种硬件的具体细节,为所有设备提供了统一的接口。
网络接口:网络接口提供了对各种网络标准的存取和各种网络硬件的支持。
进程间通信:进程间通信支持进程之间的通信。
3.Linux设备驱动与整个软硬件系统的关系
除了网络设备外,字符设备与块设备都被映射到Linux文件系统的文件和目录。通过调用open、read、write、close等即可访问字符设备和块设备。所以这就是Linux的"一切皆是文件"的思想。
Linux块设备有两种访问方法:一种是类似于/dev/sda、/dev/sdb的原始块设备,一种是在块设备上简历FAT、EXT4、BRTFS等文件系统,然后以文件路径的形式进行访问。在Linux中,针对NOR、NAND等提供了独立的内存技术设备(Memory Technology Device,MTD)子系统,其上运行YAFFS2、JFFS2、UBIFS等具备擦除和负载均衡能力的文件系统。针对磁盘或Flash设备的FAT、EXT4、YAFFS2、JFFS2、UBIFS等文件系统定义了文件和目录在存储介质上的组织。而Linux的虚拟机文件系统则统一对它们进行了抽象。
二、Linux内核启动流程解释
从Bootloader到根文件系统

1、整体架构
嵌入式Linux系统通常包含三大核心组件:
-
Bootloader(如U-Boot):引导程序
-
Kernel:操作系统内核
-
Rootfs:根文件系统
存储介质常见组合:
-
SD卡:存放bootloader、kernel、rootfs
-
8G eMMC:同样存放这三部分
-
网络启动:通过TFTP服务传输kernel(zImage + dtb)(我们使用这种)
内存大小:512M ,kernel加载地址通常为0x80000000或**0x80800000。**
2、Bootloader(以U-Boot为例)
Bootloader是一个为内核启动准备环境的裸机程序,负责引导内核。其主要工作包括:
初始化阶段
-
初始化异常向量表
-
初始化CPU工作模式
-
初始化栈指针
-
初始化时钟系统
-
关看门狗
-
关闭Cache(数据Cache必须关闭,指令Cache可选)
-
关闭MMU
-
关闭中断
-
初始化内存
-
初始化相关设备(串口、网口)
-
集成相关协议
-
搬移内核到内存 --- 向内核传参(根文件系统类型、init进程、控制台)
-
引导内核启动 --- bootload不再控制CPU,CPU控制权移交给内核
3、Kernel(操作系统核心)
内核是一个庞大而复杂的程序,负责管理整个系统的软硬件资源。主要功能模块:
-
文件管理:虚拟文件系统(VFS),支持多种文件系统
-
进程管理:进程创建、调度、终止
-
网络管理:TCP/IP协议栈
-
设备管理:驱动程序框架
-
内存管理:虚拟内存、页表、MMU管理
-
IPC进程间通信:管道、消息队列、共享内存、信号量等
内核启动最后阶段
内核启动到最后,会加载(挂载)根文件系统 ,然后启动第一个用户态进程------init进程。
内核通过exec系统调用启动init进程,之后init进程会依次启动其他进程 → 启动shell → 最终运行用户应用程序(userapp)。
4、根文件系统(Rootfs)
根文件系统是第一个挂载的文件系统,它是所有文件的集合,包括:
-
配置文件 :如
/etc/inittab、/etc/fstab -
系统命令 :
ls、cat、mount等Busybox工具 -
库文件 :动态链接库(
libc.so、ld-linux.so) -
用户程序:自定义应用程序
-
普通文件:文本、mp3、jpg等数据文件
根文件系统为系统提供了最基础的目录结构和运行环境。常见的根文件系统类型有:ext4、yaffs2、jffs2、ubifs、initramfs等。
三、Linux内核启动流程示例
1.整体框架
系统上电根据启动模式配置引脚从不同的介质加载bootloader(以SD卡为例)
1. cpu拷贝bootloader前半部分到OCRAM, bootloader在前半部分代码中初始化好内存,并搬移自己后半部分到内存中执行,bootloader执行到最后阶段搬移内核到内存,并引导内核启动
2-1 内核在SD卡中,则bootloader需要在代码中初始化好SD卡,然后读SD的kernel分区写入内存(忽略)
2-2 内核在ubuntu上,则bootloader需要在代码中初始化有线网卡及集成tftp协议,通过tftp协议下载内核到内存
3-1 根文件系统如果在SD卡中,则内核直接挂载SD卡的rootfs分区(忽略)
3-2 根文件系统在ubuntu上,则内核应该通过nfs挂载ubuntu上的rootfs目录(bootloader向内核传参是应该包含内核启动阶段使用的ip)
2.第一步:搬移内核(kernel)到内存
首先将我们编写好的zImage及xxx.dtb拷贝到tftp服务目录下(tftp服务如何配置上网搜索)
然后打开开发板终端到uboot命令下: 开发板上电后倒计时为0之前按回车键进入uboot命令行
tftp 0x80800000 zImagetftp下载,将zImage下载到内存的0x80800000地址处
tftp 0x83000000 pt.dtb tftp下载,将pt.dtb下载到内存的0x83000000地址处
部分uboot命令解释:
help/? 帮助
printenv 查看环境变量
setenv ipaddr 192.168.1.122 设置环境变量
setenv ipaddr 删除环境变量
saveenv 保存环境变量
ping 网络测试
tftp tftp下载
3.第二步:挂载根文件系统(rootfs)
输入下面命令即可
setenv bootargs root=/dev/nfs nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs,nfsvers=3 ip=192.168.1.123 console=ttymxc0,115200 init=/linuxrcroot
各参数详解
1. root=/dev/nfs
-
告诉内核:根文件系统(root filesystem)不在本地块设备(如 SD卡、eMMC),而是通过 NFS(网络文件系统) 提供。
-
/dev/nfs是一个虚拟设备,专门用于 NFS 根文件系统挂载。
2. nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs,nfsvers=3
-
192.168.1.3:NFS 服务器 IP 地址(通常是开发主机或服务器)。 -
/home/linux/nfs/imx6/rootfs:服务器上导出的 NFS 共享目录路径(即根文件系统的内容所在位置)。 -
nfsvers=3:指定使用 NFS 协议版本 3。版本 3 相比版本 2 支持更大的文件、异步写入等,且无需端口映射器(portmap)的复杂依赖。
3. ip=192.168.1.123
-
配置开发板(目标机)的 IP 地址为
192.168.1.123。 -
若需同时指定服务器 IP、网关、子网掩码等,可使用完整格式:
ip=192.168.1.123:192.168.1.3:192.168.1.1:255.255.255.0::eth0:off但此处简写只设置了客户端 IP,内核会自动通过 DHCP 或 Bootp 获取其余信息(若服务器支持)。
4. console=ttymxc0,115200
-
ttymxc0:串口设备名(i.MX6 系列 SoC 的第一个 UART 接口)。 -
115200:波特率。 -
内核启动信息以及后续的
init进程的标准输入/输出都会重定向到这个串口,方便调试。
5. init=/linuxrcroot
- init进程,根文件挂载完成后启动的第一个进程(1号进程:linuxrcroot)
整个命令的作用流程
-
U-Boot 启动后,将
bootargs传递给内核。 -
内核解析参数:
-
根据
ip=...配置网卡 IP。 -
根据
nfsroot=...尝试挂载 NFS 共享目录作为根文件系统。 -
挂载成功后,根据
console=...将控制台输出到串口。 -
最后执行
init=...指定的用户态程序
-
-
如果一切正常,开发板就从 NFS 启动,无需烧写根文件系统到本地存储------非常适合开发阶段频繁修改文件系统的场景。
注意:
-
网络连通性 :开发板必须能 ping 通 NFS 服务器(
192.168.1.3),且服务器需正确配置 NFS 导出(/etc/exports)。 -
NFS 服务 :服务器上要安装并启动 NFS 服务(如
nfs-kernel-server),且导出的目录权限允许开发板访问(通常设置rw,no_root_squash,sync)。 -
内核配置 :内核需编译支持 NFS 根文件系统(
CONFIG_ROOT_NFS=y及CONFIG_NFS_FS=y)。
4.第三步:启动内核
bootz 0x80800000 - 0x83000000 启动0x80800000地址处的内核
四、内核编译操作示例
这一部分主要讲的是如何编译内核,上面部分是启动已经编译好了的内核。
内核编译是将内核源码转换成可运行的镜像文件(zImage)和设备树文件(dtb)的过程。本章详细介绍内核编译的完整流程,包括配置、编译以及向内核添加自定义驱动。
1.将内核源码包拷贝到 Ubuntu 下,并解压到工作目录:
linux官网上下载一个内核源码包(要找对应的开发板的内核源码包,比如我这里是imx6ull):
tar -xvf linux-imx-xxx.tar.bz2 cd linux-imx-xxx
2.向内核新增文件(以向drivers/char目录下新增demo.c为例):
1. 在drivers/char目录下创建并编辑demo.c
2. 修改同层目录下的Makefile新增一行 obj-$(CONFIG_DEMO) += demo.o
3. 修改同层目录下的Kconfig文件,新增一个DEMO的配置
4. make menuconfig(在
里面查看我们新增的驱动是否生效)
5. make zImage -j20(编译内核)
3.内核编译流程(所有操作均在内核源码的顶层目录下执行):
1. 拷贝默认配置到.config cp arch/arm/configs/imx_alientek_emmc_defconfig .config
2. make menuconfig 内核配置(选择编译的模块)
3. make zImage 编译内核(仅生成zImage)
make dtbs 编译设备树(生成dtb文件)
make 全编译 -jn 多线程编译 n代表线程数,比如-j20
arch/arm/boot/zImage
arch/arm/boot/dts/imx6ull-alientek-emmc.dtb
五、总结和补充
1.Kconfig 文件介绍(以添加 ABC 为例)
Kconfig 是 Linux 内核(以及许多嵌入式系统如 U-Boot、Buildroot)中用于配置系统的脚本语言文件。它定义了配置选项的层次结构、类型、默认值和帮助信息,最终通过 menuconfig、nconfig 等工具生成 .config 文件,控制哪些功能被编译进内核或模块。
这里以添加的ABC为例:

关键部分解释
-
config ABC定义配置选项的名称,最终会生成
CONFIG_ABC的宏。
命名建议:大写字母,通常与功能相关。 -
bool "ABC support"类型为布尔型(bool),只有两种值:
y(编译进内核)或n(不编译)。
引号内的字符串是菜单中显示的名称 。其他类型还包括:
tristate(三态:y/m/n)、int、hex、string等。 -
default y默认值为
y。即不手动修改时,该选项会被选中。可以省略,默认值为
n。也可以根据其他选项条件默认,如default y if XYZ。 -
help帮助文本,详细解释该选项的作用。用户按
?或h时会显示。必须以缩进(通常是 tab 或空格)书写,直到下一个非缩进行为止。
添加位置:不要前后,要中间
在 Kconfig 文件中,选项的顺序会影响 menuconfig 的显示顺序。用户强调 添加 config 不要在前面和后面,最后是中间,意思是:
-
不要加在文件开头(可能会破坏依赖关系或默认菜单结构)。
-
不要加在文件末尾(末尾可能属于某个 menu/endmenu 之外,或影响整体层级)。
-
加在中间合适的位置 :通常是按功能分类,放在与 ABC 功能相关的
menu、if块内,或与其他同类选项一起。
如何修改生效
-
编辑对应目录下的 Kconfig 文件(如
drivers/Kconfig或新建子目录的 Kconfig)。 -
在合适位置(已有选项之间)添加
config ABC块。 -
运行
make menuconfig,即可看到新选项。 -
保存配置后,
.config中会出现CONFIG_ABC=y。
注意事项
-
如果希望 ABC 只在某个条件成立时才可见,可以用
depends on或if。例如: -
如果希望 ABC 直接修改其他配置(如自动选中另一个选项),可以用
select XYZ。 -
布尔选项的显示结果:
[*]表示y,[ ]表示n。
deponds on(弱依赖),要选择依赖里面的模块编译,才能选择这个模块是否编译
select(强依赖) ABC 如果选择了ABC1则一定会把ABC也一起选了
source 相当于include ,把kconfig里面的东西直接放到写source这个位置
2.问题汇总:
1. make zImage不了
解决办法:没装lzop:sudo apt install lzop 或者 终端窗口不够大也会报错,尽量把窗口放大make
2.没有网口使用usb转网口转换器会出现开发板和虚拟机无法ping通
解决办法:检查虚拟机是否把usb连接上了,这个转换器必须连接到主机。以及没有网口无法使用双网卡
3.启动内核出现类似no soundscard的报错提示
解决办法:根文件系统的挂载路径有问题,检查一下命令的路径和实际的路径是否一致
里面查看我们新增的驱动是否生效)