嵌入式 Linux 开发核心流程(含应用运行、联网、内核移植与编译,向内核添加新文件)
一,在开发板运行ubuntu(虚拟机)的应用层程序:
 步骤:
步骤:
①在ubuntu的家目录下的nfs(网络文件系统)目录下编写应用程序:/home/linux/nfs
②利用交叉编译命令生成在开发板能运行的可执行文件:arm-linux-gnueabihf-gcc (app.c -o app)
③利用启动 minicom 串口通信工具的命令进入开发板:sudo minicom
④在开发板中挂载网络文件系统,使nfs中的文件和mnt中的文件共享:mount-o nolock,nfsvers=3 192.168.1.200:/home/linux/nfs /mnt (这个的使用条件为直接进入内核,不手动配置启动参数)
⑤在开发板的/mnt目录运行可执行文件:/mnt ./app
二,虚拟机(Ubuntu)联网设置:
步骤:①虚拟机 -> 设置 -> 网络适配器网络连接
②编辑 -> 虚拟网络编辑器 VMNET0桥接到wifi网卡
③修改网卡配置文件:sudo vim /etc/network/interfaces

e33:网卡名称(以太网通信的网络接口)


虚拟机联网的 “物理网卡类型(wifi / 以太网)”“IP 配置方式(动态 / 静态)”“网络模式(NAT / 桥接)” 是三个独立维度
- 想用 wifi 且自动获取 IP:选择桥接模式+dhcp配置;
- 想用以太网且固定 IP:选择桥接模式+ 静态 IP 配置; 
④每次重新配置完网络之后虚拟机都需要重启:sudo /etc/init.d/networking restart
三,linux系统(内核)移植

①启动流程逻辑:

- BootLoader 阶段(bl1、bl2):- 根据ROM中的固化代码,启动boot0/boot1(引脚),初始化硬件(CPU、内存、eMMC、网口等)。
- ROM将eMMC中的bl1(bootloader的前半部分程序)拷贝到到RAM(内存)中,bl1初始化好整个bl2的内存,并将bl2拷贝到内存中,由bl2配置环境变量,为内核启动准备条件。
 
- 根据ROM中的固化代码,启动
- 内核启动阶段:- bl2将 Linux 内核(- kernel)加载到 RAM 的- 0x80800000地址,同时准备页表和内核参数。
- 内核启动后,挂载 eMMC 中的rootfs(根文件系统),启动init进程,进入用户态。(根文件系统不需要搬入ram中,挂载就行,并且如果bl2在手动配置内核启动参数时配置了挂载环境之后,内核启动之后就不用再次挂载了)
 
- 开发调试支持:- 通过以太网(net)连接 Ubuntu 主机。
- 利用 ubuntu的/home/linux/tftpboot (简单文件传输协议)下载内核镜像和设备树文件(zImage+.dtb),并向开发板(如 ARM 开发板)传输。 ( 传输zImage(内核映像文件是编译后的 Linux 内核二进制文件)+.dtb文件(描述开发板硬件信息的二进制文件)的目的为开发板提供启动 Linux 系统的 “核心软件组件”,)
- 利用ubuntu的/home/linux/ nfs(网络文件系统)协议挂载根文件系统,实现开发阶段的快速迭代。(见“在开发板运行ubuntu(虚拟机)的应用层程序”)
 
- 通过以太网(
②上电内核启动时进入bootloader配置环境(1.2阶段)的命令行按回车键可进入 U-Boot 命令行,用于手动配置启动参数:
1.ping serverip(虚拟机ip):验证开发板与服务器 / 主机的网络连通性
2.setenv 环境变量:设置环境变量
saveenv:保存设置
3. U-Boot 中配置 Linux 内核的启动参数:setenv bootargs rootfs=/dev/nfs/imx6/rootfs,nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs,nfsvers=3 console=ttymxc0,115200 ip=192.168.1.100 init=/linuxrc
- rootfs=/dev/nfs 根文件系统的类型为nfs类型 (网络文件系统)
- nfsroot=192.168.1.3:/home/linux/nfs/imx6/rootfs nfs文件系统的路径(位置):使用这个命令就相当于提前挂载了网络文件系统,后面内核启动之后就不用重新执行挂载目录了
- console=ttymxc0,115200 指定控制台为串口ttymxc0,波特率为115200
- ip=192.168.1.200 内核启动阶段使用的ip地址
- init=/linuxrc 指定init进程为/linuxrc
4.每次上电后需执行
- tftp 0x80800000 zImage 将zImage下载内存的0x80800000地址处
- tftp 0x83000000 1.dtb
- bootz 0x80800000 - 0x83000000 启动内核
- 开发板的内核:核心目标是 “让嵌入式硬件能运行 Linux 系统”,支撑后续的嵌入式应用开发(如工业控制、物联网设备),需优先保证硬件兼容性和资源轻量化(适配开发板有限的内存 / Flash)。
- 虚拟机的内核:核心目标是 “为虚拟机中的操作系统(如 Ubuntu)提供运行环境”,支撑主机端的开发工作(如编写内核代码、编译根文件系统),需优先保证通用性和功能完整性(如支持多任务、图形化界面)。
四,Linux 内核编译的配置与条件编译
(向内核新加文件的步骤,静态及动态两种方式)
核心是通过 “配置项定义→配置→结果保存→条件编译” 的流程实现内核功能的按需构建
1.放置源码文件:将新文件(如 led.c)放入内核源码的对应目录(例如 内核顶层目录/drivers/char/)。
2.Kconfig文件:定义make menuconfig等配置界面中的选项(如功能开关、模块选择),是配置项的 “定义层”(位于内核源码的各子目录中,每个子目录的 Kconfig 定义该目录相关的配置选项如/home/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/drivers/char)

用于在make menuconfig中添加 LED 功能的配置选项
3:修改 Makefile(添加编译规则)
在同目录的 Makefile 中添加编译条目:
obj-$(CONFIG_NEW_FEATURE) += led.oKconfig和Makefile成对出现
4.make menuconfig:提供交互式菜单界面,用于选择内核功能(如是否启用某驱动、某特性),生成 “内核配置地图”(无实体文件,是内核源码顶层目录/home/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek下的编译命令,用于启动交互式配置界面)

在 Linux 内核中添加新文件主要有 ** 静态编译(内置进内核)和动态加载(编译为模块)** 两种方式,主要的区别就是menuconfig中的配置:
①设置为 <*>(内置):为静态编译(内置进内核)将新功能直接编译到内核镜像(zImage)中,随内核启动时自动加载:(使用步骤:在内核的顶层目录下用make生成zImage,(生成的zImage内核顶层目录/arch/arm/boot)将更新过的zImage复制到/home/linux/tftpboot目录下,向开发板传输,作用于:三②)
Image :无压缩的内核镜像,可以直接运行的内核映像
zImage :包含解压引导程序(头部自带),启动时会先自动解压内核,再执行内核代码;无标准化的硬件适配头部,依赖 bootloader 直接识别内核格式。
uImage 64字节的头信息 + zImage
②设置为<M> 时,为动态加载(编译为模块)在内核顶层使用make modules命令将设为<M>新功能编译为 .ko 模块文件(在内核顶层目录/drive/char目录下,也就是新加文件目录下),可通过 insmod 动态加载、rmmod 动态卸载。(使用步骤:将生成的.ko文件复制到/home/linux/nfs/目录下,使用在开发板内核开启之后执行insmod .ko文件:动态加载模块文件,rmmod:.ko文件:动态卸载.ko文件)

5..config文件:保存make menuconfig的配置结果,是配置项的 “存储层”,Makefile 会读取其中的变量(存在于linux内核的顶层目录下)

make(all)编译内核的所有,包括
- 内核镜像(按配置生成 zImage/uImage/Image,取决于架构和配置);
- 设备树文件(.dtb,若架构支持,如 ARM 开发板);
- 内核模块(.ko,若配置中 CONFIG_MODULES=y且部分功能设为m)。
make all -j10:-j10 是多线程编译参数,指定用 10 个线程并行编译,可大幅缩短编译时间(尤其内核源码量大,单线程需数小时,多线程可压缩至几十分钟)。
make zImage:编译内核镜像
make pt.dtb:编译设备树文件
make modules:编译动态内核模块(.ko)
