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

2-Linux驱动开发-内核;内核模块;设备树;设备树插件

交叉编译器以及基础环境和内核构建

  • 虚拟机的交叉编译要和硬件交叉编译的版本适配
  • 各个版本交叉编译器链接https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchain/
  • 下载以下版本gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz
    虚拟机环境构建
  • 拖到vscode一个文件夹然后进行解压sudo tar -xvf gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz
  • 将工具链路径添加到系统环境变量中,vim ~/.bashrc
  • 路径一定是你解压的位置,到你解压位置pwd,然后把路径替换为你的路径export PATH=$PATH:/opt/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf/bin
  • 让环境变量立即生效:source ~/.bashrc
  • 验证交叉编译器是否配置成功:arm-none-linux-gnueabihf-gcc -v
    在这里插入图片描述
    由于编译器默认名字太长,所以采用别名进行修改,在~/.bashrc中末尾添加alias arm-gcc='arm-none-linux-gnueabihf-gcc'source ~/.bashrc生效一下,操作见下图
    在这里插入图片描述在这里插入图片描述

其他插件

sudo apt install make bison flex libssl-dev dpkg-dev lzop
• bison 语法分析器
• flex 词法分析器
• libssl-dev OpenSSL 通用库
• lzop LZO 压缩库的压缩软件

编译内核

uname -r //查看内核版本
linux:
kun@kun-virtual-machine:~/Desktop$ uname -r
6.8.0-87-generic
stm32mp157:
root@lubancat:~# uname -r
4.19.94-stm-r1

说明:主机的 6.8.0 内核与驱动开发完全无关。它唯一的角色是提供一个工作台,来运行交叉编译工具链。

1.核心工作:在主机编译内核的真正目的真正目的是在主机上,构建一个与目标板 (lubancat) 内核版本(4.19.94)完全一致的“内核模块开发环境”。这个开发环境是后续编译所有外部驱动模块的绝对前提。缺少这一步,驱动模块(.ko)将无法编译或加载。
2.关键依赖:内核编译的“副产品”
编译内核的过程会生成三个关键的“副产品”,它们是编译外部 .ko 模块时必需的:内核头文件 (Headers): 提供了驱动开发所需的 API 声明和数据结构。.config 配置文件: 确保了您的驱动是基于与目标内核完全一致的功能配置来编译的。Module.symvers (符号表): “API 字典”,记录了4.19.94内核中所有导出的、可供模块调用的函数(如 printk, kmalloc)及其内存地址。

具体操作

获取内核源码
去https://github.com/Embedfire/ebf_linux_kernel.git下载ebf_4.19_star分支(对应板子内核源码分支) 
unzip ebf_linux_kernel-ebf_4.19_star.zip
内核源码进行编译
找到 make_deb.sh 脚本,里面有配置好的参数,只需要执行脚本便可编译内核。要进入对于文件夹
编译出来的内核相关文件存放位置,由脚本 make_deb.sh 中 build_opts="${build_opts}O=build_image/build" 指定。**需要进行以下两次修改(修改交叉链路径和bison环境变量)才能执行脚本**
make_deb.sh中文件详情如下:
============================================================
deb_distro=bionic
DISTRO=stable
build_opts="-j 16"
build_opts="${build_opts} O=build_image/build"
build_opts="${build_opts} ARCH=arm"
build_opts="${build_opts} KBUILD_DEBARCH=${DEBARCH}"
build_opts="${build_opts} LOCALVERSION=-stm-r1"
build_opts="${build_opts} KDEB_CHANGELOG_DIST=${deb_distro}"
build_opts="${build_opts} KDEB_PKGVERSION=1.$(date +%g%m)${DISTRO}"
# build_opts="${build_opts} CROSS_COMPILE=arm-linux-gnueabihf-" 
build_opts="${build_opts} CROSS_COMPILE=arm-none-linux-gnueabihf-" #这里我根据自己的.bashrc中的arm-gcc进行修改的交叉编译链
build_opts="${build_opts} KDEB_SOURCENAME=linux-upstream"
make ${build_opts}  stm32mp157_ebf_defconfig
#make ${build_opts} menuconfig
make ${build_opts}  
make ${build_opts}  bindeb-pkg
============================================================由于我的linux版本22.04所以新版 bison 生成的代码(dtc-parser.tab.o)和新版 flex 生成的代码(dtc-lexer.lex.o)在 4.l9 这个老脚本里,都声明了 yylloc 变量,会导致了冲突。
操作:/scripts/dtc/dtc-lexer.l中YYLTYPE yylloc;修改为extern YYLTYPE yylloc;最后执行编译脚本
./make_deb.sh

编译和加载内核驱动模块

目的:使用刚编译好的内核环境,去逐个编译示例驱动,生成 .ko 文件,最后加载到 lubancat 板子上去验证。

获取内核驱动模块
git clone https://gitee.com/embedfire-st/embed_linux_driver_tutorial_stm32mp157_code.git

操作此路径linux_driver/module/hellomodule下的文件

首先修改Makefile文件
hellomodule
两处修改:首先是内核的build加载路径,改为你的绝对路径(在相应build下面进行pwd然后输出路径)KERNEL_DIR交叉编译链的具体名字,根据你下载的来进行修改 CROSS_COMPILE
=========================Makefile文件=============================
# KERNEL_DIR=../../../ebf_linux_kernel/build_image/build
KERNEL_DIR=/home/kun/kernal_code/ebf_linux_kernel-ebf_4.19_star/build_image/build
ARCH=arm
# CROSS_COMPILE=arm-linux-gnueabihf-
CROSS_COMPILE=arm-none-linux-gnueabihf-
export  ARCH  CROSS_COMPILE
obj-m := hellomodule.o
all:$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules.PHONE:clean copy
clean:$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean	
copy:sudo  cp  *.ko  /home/embedfire/workdir
================================================================
进行make生成hellomodule.ko文件

进行文件挂载:(如果构建好NFS此步跳过)

  • Linux上

    #关闭防火墙
    sudo ufw disable
    #虚拟机中安装并启动NFS 服务器,并设置为自启动
    sudo apt install nfs-kernel-server
    sudo systemctl start nfs-kernel-server
    sudo systemctl enable nfs-kernel-server
    #要告诉 NFS 服务器允许共享哪个文件夹,因为板子root用户会被默认为nobody,服务器会拒绝这个挂载请求
    sudo nano /etc/exports
    #添加你共享的目录
    /home/kun/arm_kernal *(rw,sync,no_subtree_check,no_root_squash)
    #生效配置
    sudo exportfs -a
    
  • 如果板子没有文件系统只需要下载文件系统,其他的都不需要

板子上进行挂载:
ko文件拖到虚拟机中的/home/kun/arm_kernal下面

sudo mount -t nfs -o nolock 192.168.137.3:/home/kun/arm_kernal  /mnt/host_projects

在这里插入图片描述

#插入这个内核模块 insmod仅用于测试用
debian@lubancat:/mnt/host_projects$ sudo insmod hellomodule.ko
#插入成功的默认内容输出
Message from syslogd@lubancat at Nov 13 21:12:09 ...kernel:[  666.015524] [ KERN_EMERG ]  Hello  Module Init
#利用管道查看此内核module
debian@lubancat:/mnt/host_projects$ lsmod | grep hellomodule
hellomodule            16384  0
#删除这个内核模块
debian@lubancat:/mnt/host_projects$ sudo rmmod hellomodule.ko

设备树

引言:内核模块 (驱动, .ko) 解决了“如何做”的问题(它包含代码)。 设备树 (.dtb) 解决了“做在谁身上”的问题(它包含数据)。实现了“代码”与“数据”分离;例如:通用的 LED 驱动(内核模块)。不知道 LED 在哪个引脚上,设备树 (.dtb)会告诉它取名叫 user-led,它连接在 GPIO A 口的第 5 引脚。

启动时: Bootloader (如 U-Boot) 加载 zImage (内核) 和 .dtb (设备树) 到内存中。
内核初始化: 内核启动,它首先读取 .dtb 文件,在内存中建立一个“硬件清单”,知道硬件上有什么设备。
加载驱动模块: 您通过 NFS 挂载,然后运行: sudo insmod led-driver.ko(内核模块插入示例)
匹配(Probe):led-driver.ko 向内核注册,内核马上去查它的“硬件清单”(来自 .dtb),匹配成功后,内核立刻“激活”这个驱动,并把从 .dtb 里读到的“数据”(“GPIO A 口第 5 引脚”)传递给 led-driver.ko。总结:Probe(匹配)就是内核使用设备树(.dtb)中的 compatible 属性,为“硬件”找到了能处理它的“驱动”,并把“硬件”的具体参数(如引脚、地址)传递给“驱动”使其运行
驱动工作: led-driver.ko (内核驱动模块文件)拿到引脚信息,开始工作。
编译和加载设备树
说明:
编译要在内核源码目录 (KSRC):/
所有产物会输出到:内核编译目录 (KOUT):/build_image/build下

在虚拟机上将可读的文本文件(.dts)转换成内核可读的二进制文件(.dtb)
编译工具 (dtc): Device Tree Compiler (设备树编译器)。
源码文件 (.dts): Device Tree Source
目标文件 (.dtb): Device Tree Blob

#使用示例
内核目录/scripts/dtc/dtc -I dts -O dtb -o xxx.dtb xxx.dts
# -I (Input format: dts)
# -O (Output format: dtb)
# -o (Output file)
dtc -I dts -O dtb -o stm32mp157-lubancat.dtb stm32mp157-lubancat.dts

说明:

实际上设备树中有非常多的依赖关系,这些依赖关系通过 Makefile 文件去处理,所以一般情况下,设备树不仅仅只是通过一个 dtc 命令就能将编译出来的。
所要用到的设备树文件都存放在 内核源码/home/kun/kernal_code/ebf_linux_kernel-ebf_4.19_star/arch/arm/boot/dts中

编译内核时会自动去编译设备树,但是编译内核很耗时,所以我们推荐使用如下命令只编译设备树。在内核文件根目录执行。

#配置步骤。它不编译任何东西,它只生成一个 .config 文件,这个文件是编译的前提
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- stm32mp157_ebf_defconfig
#以 ARCH=arm 模式工作,目标架构
#使用 CROSS_COMPILE=... 编译器
#stm32mp157_ebf_defconfig: 指定要执行的构建目标 (Build Target)
#stm32mp157_ebf_defconfig默认配置,它会搜索 arch/arm/configs/ 目录,找到 stm32mp157_ebf_defconfig 这个“基准配置文件”(它由内核或板卡维护者提供),并以此为蓝本,在顶层目录生成最终的 .config 文件。#编译步骤。它读取 .config 文件,然后只编译设备树(.dts -> .dtb),跳过所有其他耗时的内核编译。
make ARCH=arm -j4 CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs
#以 ARCH=arm 模式工作,目标架构
#用 -j4 (4 个 CPU 核心) 来加速
#使用 CROSS_COMPILE=... 编译器
#执行 dtbs “目标”名称,#make 会首先读取 .config 文件,查看里面配置了哪些板子。#跳过所有 C 代码的编译。#只去 arch/arm/boot/dts/ 目录,找到所有需要编译的 .dts 源文件。#调用 scripts/dtc/dtc (设备树编译器) 来把它们全部编译成 .dtb 文件。
引入说明:
内核源码目录 (KSRC):/
内核编译目录 (KOUT):/build_image/build
在根目录下执行
生成配置文件:make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- stm32mp157_ebf_defconfig流程:读取arch/arm/configs/stm32mp157_ebf_defconfig(蓝本)生成/.config(隐藏文件在当前目录)执行编译:make ARCH=arm -j4 CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs流程:读取配置/.config,读取 .dts 源码/arch/arm/boot/dts/生成/build_image/build/arch/arm/boot/dts/
先筛选进一步找相应文件文件:ls /build_image/build/arch/arm/boot/dts/stm32mp157*发板适配的设备树文件名以及所在位置:
ebf_4.19_star/build_image/build/arch/arm/boot/dts/stm32mp157a-basic.dtb  通过NFS文件系统传给板子
stm32mp157a-basic.dtb 替换板子里面的/boot/dtbs/stm32mp157a-basic.dtb 
最后进行reboot新的设备树就生效了
编译和加载设备树插件

    设备树插件和设备树是互补的关系,设备树插件可以在主设备树定型的情况下,再对主设备树未描述的功能进行动态的拓展。
   设备树插件与设备树都是使用device tree compiler,但是区别在于设备树编译为.dtb,设备树插件编译为.dtbo。

写新设备树插件的时候,自己的设备树插件添加到:/arch/arm/boot/dts/overlays 目录下
修改 arch/arm/boot/dts/overlays/Makefile 文件,添加编译选项/添加dtbo文件
在这里插入图片描述
上述设备树插件添加后

make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- stm32mp157_ebf_defconfig
make ARCH=arm -j4 CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs
make ... dtbs
上述操作完成两个操作:
自动编译主设备树,生成主 .dtb 文件。
同时(同步),它会自动去 arch/arm/boot/dts/overlays/Makefile 目录,编译所有被您登记在册的插件,生成插件 .dtbo 文件。

板子上加载设备树插件

#将.dtbo 设备树插件拷贝到开发板 /usr/lib/linux-image-4.19.94-stm-r1/overlays/ 上
mv 挂载文件地址  /usr/lib/linux-image-4.19.94-stm-r1/overlays/ 
#修改/boot下的uEnv.txt,写入加载的设备树插件
dtoverlay=/usr/lib/linux-image-4.19.94-stm-r1/overlays/"这里对应的你的设备树插件名字".dtbo

在这里插入图片描述
在这里插入图片描述

总结设备树,设备树插件

设备树,设备树插件说明:

对比项设备树 (Device Tree)设备树插件 (Device Tree Overlay)
作用主蓝图 (完整的硬件地图)补丁 (对主蓝图的“修改”或“补充”)
源码示例stm32mp157a-basic.dtsfire-rgb-led-overlay.dts
编译方式make dtbs 会自动找到。需将 .dts 放入 overlays/ 目录,并修改 overlays/Makefile 进行登记。
编译命令make … dtbsmake … dtbs (同一个命令,它会“顺带”编译插件)
编译产物stm32mp157a-basic.dtb (.dtb 文件)rgb.dtbo (.dtbo 文件)
加载方式替换 /boot/ 目录文件复制到“货架” , 修改 uEnv.txt

make … stm32mp157_ebf_defconfig ; dtbs命令说明

make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- stm32mp157_ebf_defconfig
“内核”自带功能的“总开关”列表,生成了一份功能清单 (.config),只要没有运行 make clean 或 make distclean就不需要重新运行 defconfigmake ARCH=arm -j4 CROSS_COMPILE=arm-none-linux-gnueabihf- dtbs
无论是修改主设备树(.dts)还是设备树插件(.dts / .dtbo),都只需要 make ... dtbs。

.config, .dtb, .ko分工

文件类型.config (内核配置文件).dtb / .dtbo (设备树).ko (内核模块)
角 色“软件功能清单”“硬件布局蓝图”“驱动程序代码”
内 容软件功能的开关列表硬件数据的描述列表CPU 机器指令
生成指令make ..._defconfigmake dtbs (调用 dtc 工具)make (在模块目录中)
谁依赖它make dtbsmake (编译 .ko) 都依赖它。驱动(.ko)的 probe 依赖它。(无,它是最终执行者)
http://www.dtcms.com/a/612135.html

相关文章:

  • 郑州中原区网站建设创建网站需要哪些步骤
  • 自学网站建设看什么书ftp发布asp.net网站
  • ORACLE数据库中如何找到过去某个时间某个表被谁修改了
  • 网站备案的幕布是什么网站在线答题怎么做
  • 廊坊网站建设廊坊网络公司驻梦温州网站开发建设
  • 网站关于我们模板卖手表的网站
  • 广州的一起做网站接家装活找哪个平台
  • 网站建设收税梅州建站联系方式
  • 医药网站建设中图片网站建设公司华网天下买赠两年
  • 高性能网站建设指南 当当镇江网站建设机构
  • JMM小知识
  • 企业网站建设报价方案设计师入门必学软件
  • 软件开发和网站建设一样吗手机上自己做网站
  • 网站建设 管理系统开发做百度推广代运营有用吗
  • 网站关键词挖掘工具企业内部网络属于什么网络
  • 沈阳高端网站网站怎么添加外链
  • 铜陵网站建设推广自媒体网站源码
  • 济南市建设执业资格注册中心网站wordpress加载latex慢
  • 专业性行业网站有哪些上海二手房网站
  • 自助建站系统建的网站做排名吗长尾关键词搜索
  • 网站建设市场分析东莞seo网站制作报价
  • 谷歌企业网站seo代驾网站开发
  • 公司外贸网站郑州友网站建设
  • 大庆建设局网站首页建设系统网站
  • 建设网站用什么app中国营销网站
  • 云羽网络网站建设四川自助seo建站
  • 京东网站建设目标是什么react做网站
  • 抖音做我女朋友的网站php网站怎么注入
  • 本溪网站制作广告代理公司
  • 嘉兴市住房和城乡建设局门户网站网上编程课的哪家好