当前位置: 首页 > news >正文

驱动(二)uboot编译+内核编译+文件系统

一、Makefile

工程管理:Makefile

语法:要生成的文件:依赖的所有文件

           生成的方式

步骤:make->Makefile、makefile->寻找文件中要生成的目标a.out->寻找依赖的所有文件->存在,则利用命令生成目标文件/ ->不存在,Makefile向下寻找依赖文件的生成方式

  • := 覆盖原来的值
  • ?=如果原来没值赋值新值,原来有值,不赋新值
  • += 原来值的基础上新加一个值

通过make传参

二、Uboot编译

1.概念

ubootbootloader的一种,主要作用是在内核加载前对硬件设备初始化,并为内核的运行提供引导功能。

2.编译

1.uboot (跨平台)

   (1).初始化硬件设备
(2).为加载内核做准备

2.使用宏实现条件编译,满足条件的加入编译中,不满足的从编译中去除最顶层目录.config配置文件(宏的配置,如果宏配置到该文件中则代码加入uboot编译)

3.当前平台为ARM,工具链为arm-linux-gnueabihf-,开启16核编译uboot
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig
make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
ARCH:指定目标硬件架构
CROSS_COMPILE:设置交叉编译工具链
V=0:控制编译输出的详细程度,0表示启动静默/精简输出模式,1表示完整的编译命令,便于调试。

最终生成:uboot.bin -> uboot.imx

三、uboot启动流程

第一阶段

1.开发板上电,加载0x0地址,IMX6ULL96k出厂固件代码(ROM),会根据启动方式将对应的存储设备前面的一段uboo代码加载到ARM执行
2.出厂固件代码及uboot 通过IMX6uLL内部的RAM执行
3.对外设初始化(初始化DDR和EMMC)    //自身资源空间有限
4.将IMX6ULL96kROM固件代码搬移到DDR中运行 

第二阶段
5.外设逐一初始化
6.进入与用户交互的系统中,等待用户按下按键
7.如果用户不操作uboot,倒计时结束后,会执行bootcmd
8.引导启动内核(需要串口、需要网口、文件系统的方式及路径、需要设备树...)

内核启动阶段:加载驱动和五大功能实现的展开
9.内核启动执行init进程(0号内核进程)挂载文件系统

用户态
10.启动用户进程(fork+exec)启动所有的进程
11.启动终端 (可以与用户实现交互)

四、内核与设备树文件

1.概念

内核是操作系统的核心功能代码,是一个大型的开源项目,我们需要对这个源码进行裁剪、编译。

2.编译

(1).解压缩源码 
   
         tar -zxvf linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek.tar.gz

(2).进入源代码中 
        cd linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/

(3).编译内核
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean                                    //清除之前的编译的文件

 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_erhmc_defconfig
 //将imx_alientek_emmc_defconfig中的设置作为.config设置,.config决定了哪些代码加入编译。哪些代码从编译中去除

 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf--j16
//用户可以通过界面对.config完成修改
参数说明:
distclean:表示清除之前的编译内容
imx_alientek_emmc_defconfig:将该配置作为内核的.config配置
menuconfig:通过图形界面配置.config
all -j16:通过16核编译代码
ARCH=arm:编译arm32位平台
CROSS_COMPILE=arm-linux-gnueabihf-:设置编译工具链
(4).编译完成后可以获得设备树文件和内核镜像文件
  • 设备树文件:arch/arm/boot/dts/imx6ull-alientek-emmc.dtb
  • 内核镜像文件:arch/arm/boot/zlmage
(5).将以上两个文件(内核镜像、设备树文件)拷贝到~/tftpboot
cp arch/arm/boot/zImage ~/tftpboot/ -rf
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb ~/tftpboot/ -rf

3.make menuconfig

  • *驱动项     编译生成的zImage中包含该驱动项     驱动 (静态加载)
  • M驱动项   编译生成的zImage中不包含该驱动项,该驱动将会成为一个独立的模块  .ko                             驱动 (动态加载)

步骤:

1.打开图形界面->1.图形界面中的配置项(根据Kconfig中的语法解析得到)

2.勾选/去除/模块选择编译目录->1.根据用户勾选将对应的宏写入.config     宏名=y/m

make -j16  -> 顶层的makefile会调用每一层的makefile,每层makefile都会根据.config中的宏的配置决定哪些.o文件加入编译,哪些.o文件不加入编译  -> vmlinux(可以调试的内核)-> Image(对vmlinux压缩后的镜像文件)/ ->zImage(添加解压算发的Image)

五、文件系统

1.概念

        根文件系统是Linux操作系统组成的基础,是内核启动时所要挂载的第一个文件系统,我们的一些配置文件、库函数、系统命令都保存在文件系统中,同时也可以通过文件系统实现用户与操作系统功能的交互
        根文件系统的制作常见有如下几种:busybox构建根文件系统、Buildroot构建根文件系统、Yocto构建根文件系统。我们这里采用busybox构建根文件系统,其特点是易于构建简单的根文件系统,而且文件系统占用空间小,但是需要自己配置库文件,易于理解移植过程

2.操作步骤

内核启动后->挂载文件系统->执行linuxrc->/etc/inittab脚本(决定系统启动执行哪些脚本、重启执行哪些脚本、ctrlaltdel执行哪些脚本)->系统启动执行/etc/init.d/rcS脚本->设置环境变量、参数->挂载所有文件系统(mount-a)->执行/etc/fstab文件->挂载所有文件系统->/etc/profile脚本->启动bash shell->与用户交互->./a.out->fork+exec(./a.out)

如何实现开机自启动?  将./a.out& 放在/etc/profile脚本或etc/init.d/rcS脚本

六、驱动

驱动是针对内核的开发

驱动要解决的问题:

  • 1.如何在一个已经运行起来的代码中执行我们的驱动代码
  • 2.驱动代码的编写的框架是什么?
  • 3.驱动代码最终还是完成对寄存器的操作,如何实现虚拟地址和物理地址的映射

(一)内核编写驱动

1.静态加载

        (1).编写驱动led.c
(2).编译代码
1.修改.config,增加一条该驱动的说明,需要增加一个关于该条驱动的宏名
2.用户通过make menuconfig选择该条驱动<*>,会引|起.config中的配置的变化宏名=y
3.修改Makefile obj-$(宏名)+=led.o,驱动编译时就会加入led.c代码的编译
4.代码编译->链接->压缩->ZImage(包含了led驱动)
(3).通过ttp下载最新的zImage来执行内核,此时内核中增加了led驱动

2.动态加载

        (1).编写驱动led.c
(2).编译代码
1.在makefile中 obj-m+=led.o
2.在内核中通过make modules来完成对内核模块的编译
3.编译成功后生成led.ko内核模块文件
(3).将内核模块拷贝到~/nfs/rootfs
(4).在开发板中(Linux系统已经启动),通过insmod命令加载内核模块,通过rmmod命令卸载内核模块

3.工程搭建和代码编译

4.加载驱动

insmod demo_drv.ko

http://www.xdnf.cn/news/1343323.html

相关文章:

  • AI 绘画争议背后:版权归属、艺术原创性与技术美学的三方博弈
  • 排序---插入排序
  • Oracle APEX 经典报表中的Checkbox
  • 使用EasyExcel自定义导出表格
  • 开发二手车小程序时,如何确保信息的真实性和可靠性?
  • C#:窗体间传值
  • 计数组合学7.20(平面分拆与RSK算法)
  • 亚矩阵云手机:亚马逊第三方店铺多账号安全合规运营的核心技术支撑
  • Matplotlib 可视化大师系列(六):plt.imshow() - 绘制矩阵与图像的强大工具
  • 2026年计算机毕设推荐:基于大数据的慢性肾病数据可视化分析系统技术选型指南【Hadoop、spark、python】
  • 决策树基础学习教育第一课:从概念到核心原理
  • 【Canvas与旗帜】美国星条旗玻璃光圆饼
  • Lua脚本如何执行主程序的C函数
  • ODYSSEY:开放世界四足机器人的探索与操控,助力长范围任务
  • Node.js 开发 JavaScript SDK 包的完整指南(AI)
  • 基于Node.js服务端的社区报修管理系统/基于express的在线报修管理系统
  • 数据工程师——ETL
  • FastText 词向量全景指南(没那么全)
  • 如何创建一个Cloudfalare worker项目?
  • vue-admin-template权限管理
  • 【python】os.makedirs和with open
  • pytorch与mindspore的简单ViT实现
  • 【数据分享】中国371个城市的坡度矢量数据和excel数据
  • uniappx与uniapp的区别
  • 【在ubuntu下使用vscode打开c++的make项目及编译调试】
  • MongoDB 从入门到实践:全面掌握文档型 NoSQL 数据库核心操作
  • 3-2〔OSCP ◈ 研记〕❘ WEB应用攻击▸WEB安全防护体系
  • 云计算学习100天-第27天
  • 嵌入式学习day34-网络-tcp/udp
  • 新手向:用FastAPI快速构建高性能Web服务