Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统

        在产品将要上线之前,需要制作不同类型格式的根文件系统

        在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统

        优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命

        【1】重启上位机nfs服务

        sudo service nfs-kernel-server restart

        【2】关闭上位机防火墙

        sudo service ufw stop

        【3】修改下位机的环境变量

        setenv bootargs root=/dev/nfs nfsroot=192.168.1.8:/nfs_share/_install ip=192.168.1.6:192.168.1.8:192.168.1.1:255.255.255.0 init=/linuxrc console=ttySAC0,115200 maxcpus=1 lcd=wy070ml tp=gslx680-linux

        【4】保存环境变量

        saveenv

        【5】重启

        re

二、Linux内核驱动开发的基础知识

        1、裸板驱动和内核驱动的区别

                1)裸板驱动

                        主观性较强,相当于英语考试中的作文模块

while (1) {
    // 代码逻辑
    ...
}
                2)Linux下的驱动开发

                        客观性较强,相当于英语考试中的完形填空

                        需要的知识:

                        【1】硬件的知识

                                读懂硬件原理图、读懂读写时序图、各种接口协议

                        【2】读取cpu数据手册

                                各种寄存器如何配置、各种外设如何配置

                        【3】驱动的编码框架

                                字符设备驱动(按字节访问,顺序固定)

                                块设备驱动(按块访问,顺序不固定)

                                网络设备驱动(按字节访问,顺序固定)

                        【4】内核态的编程规则

                                用户态和内核态的数据交互

                                内核模块的编程框架

                                解决竞态和并发

                                。。。

        2、Linux内核代码的特点

                1)介绍

                Linux内核本质上就是一个巨大的裸板程序,所有的函数都是自身实现的

标准C库系统调用Linux Kernel说明
fopenopensys_open打开文件
fcloseclosesys_close关闭文件
freadreadsys_read读文件
fwritewritesys_write写文件

                学习Linux内核最好的老师就是内核源码,遇到不会用的函数,去找内核源码。

                2)推荐书籍

                内核:<Linux内核的设计与实现>

                驱动:<LDD3>、<Linux设备驱动第三版>

        3、Linux内核需要注意的地方

                1)Linux内核不允许做浮点运算

                2)Linux内核中使用的是GUN C,不是标准C(GNU C是标准C的扩展版)

                3)Linux内核中每个线程都有两个栈

                        【1】用户态的栈

                        【2】内核态的栈

                4)Linux内核使用的内存空间是3G - 4G

                5)Linux内核更加注重代码的执行效率和可移植性

        4、搭建Linu内核的开发环境

                1)安装交叉编译器

                2)获取一份x6818上使用的Linux内核源码

                3)编译Linux内核源码

                4)制作并移植根文件系统

        5、使用source insight建立一个内核源码的项目工程

                source insight是一个阅读项目工程源码非常好用的工具

                官网:Source Insight Programming Editor and Code Browser

                1)安装source insight

                        序列号位置:sourcesightSN.txt

                2)添加Linux Kernel源码

                        【1】在window下某盘符中创建一个目录

                        【2】将Linux内核源码拷贝并解压到该目录

                        【3】打开kernel文件夹,新建文件夹,用来存储项目工程文件

                3)在source insight中添加项目工程

        6、编写内核的模块文件(*.ko)

                1)上位机编写模块文件

                【1】在虚拟机创建新目录,存放工程目录

                mkdir drivers

                【2】进入drivers目录

                cd drivers/

                【3】创建第一个工程目录

                mkdir hello_pro

                【4】进入hello_pro目录

                cd hello_pro/

                【5】编写工程文件hello.c

                vim hello.c

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");    // 声明开源,
                          // 如果不添加该声明,内核会报受到污染,因为没有遵守开源规则
MODULE_AUTHOR("Zjd");     // 声明作者

int __init hello_init(void)
{
    printk("<0>" "Hello, my owner kernel!\n");

    return 0;
}

void __exit hello_exit(void)
{
    printk("<0>" "bye, my owner kernel!\n");

    return ;
}

module_init (hello_init);
module_exit (hello_exit);

                【6】编写Makefile

                vim Makefile

obj-m += hello.o
KERNEL_PATH=/home/zjd/s5p6818/KERNEL/kernel

all:
    make -C $(KERNEL_PATH) M=$(PWD) modules

clean:
    make -C $(KERNEL_PATH) M=$(PWD) clean

                【7】编译工程文件

                make

                【8】将工程文件拷贝到共享的根文件系统中

                cp hello.ko /nfs_share/_install/

                2)下位机验证模块文件

                【1】查看内核中的模块

                lsmod

                【2】安装模块

                insmod hello.ko

                【3】卸载模块

                rmmod hello

        提示缺少 /lib/modules/ 目录

                mkdir /lib/modules

        提示缺少 3.4.39-embTwoGroup 目录

                mkdir /lib/modules/3.4.39-embTwoGroup

        卸载成功

        7、导出符号

                在C语言中,使用extern关键字修饰的符号可以跨模块访问

         进行内核态开发时,需要额外添加一个宏去修饰

        EXPORT_SYMBOL:它所修饰的符号,在内核中,所有的模块都可以访问到

        EXPORT_SYMBOL_GPL:它所修饰的符号,在内核中,只有遵循GPL规则的模块才能访问到

        1)上位机编写试验文件

                【1】创建新的项目工程

                mkdir export

                【2】进入实验目录

                cd extern_pro

                【3】创建文件

                touch export.c import.c export.h

                【4】编写程序

                vim export.h

#ifndef __EXPORT_H
#define __EXPORT_H

extern int add(int a, int b); 

#endif

                vim export.c

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zjd");

int add(int a, int b)
{
    return a + b;
}

EXPORT_SYMBOL(add);

                vim import.c

#include <linux/init.h>
#include <linux/module.h>
#include "export.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zjd");

int __init import_init(void)
{
    int ret = add(20, 6); 

    printk("<0>" "ret = %d\n", ret);

    return 0;
}

void __exit import_exit(void)
{
    printk("<0>" "I'm going.\n");

    return ;
}

module_init(import_init);
module_exit(import_exit);

                【5】编写Makefile

                vim Makefile

obj-m += export.o import.o
KERNEL_PATH=/home/zjd/s5p6818/KERNEL/kernel
ROOTFS_PATH=/nfs_share/_install

all:
    make -C $(KERNEL_PATH) M=$(PWD) modules
    cp *.ko $(ROOTFS_PATH)

clean:
    make -C $(KERNEL_PATH) M=$(PWD) clean
        2)下位机验证

                【1】挂载export.ko

                insmod export.ko

                【2】挂载import.ko

                insmod import.ko

                【3】卸载import

                rmmod import

                【4】挂载export

                rmmod export

                【5】注意事项

        1】安装和卸载模块的顺序是相反的

        2】安装时要填写 *.ko 文件,卸载时直接填写文件名 *

        8、printk

                1)简介

                printk是内核中的打印函数,它输出到内核自己维护的缓冲区。

        printk的使用方法:

        printk("<0/1/2/3.../7>" "info");

注释:

<0/1/2/3.../7>:代表该条消息的打印优先级,越小优先级越高

info:代表要打印的消息

它的用法与printf相同,只不过前面多了一个消息优先级的配置,且不需要用 ',' 分开

                2)特殊情况

        printk("ret = %d\n", ret);        // 使用的是默认优先级

Linux内核将打印优先级设定为8个等级(0~7),值越小,优先级越高

printk输出的信息先到内核维护的缓冲区

缓冲区的内容能不能输出到控制终端是有限制的

                3)限制

        在uboot中设置的bootargs环境变量中的loglevel代表Linux内核设置的优先级阈值

当我们设定printk的优先级大于loglevel所设置的优先级,则可以打到终端,相反则不可以打印到终端。

                4)验证

        【1】创建实验目录

        mkdir printk_pro

        【2】进入实验目录

        cd printk_pro/

        【3】编写程序

        vim myprintk.c

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zjd");

int __init printk_init(void)
{
	printk("<0>" "Level 0!\n");
	printk("<1>" "Level 1!\n");
	printk("<2>" "Level 2!\n");
	printk("<3>" "Level 3!\n");
	printk("<4>" "Level 4!\n");
	printk("<5>" "Level 5!\n");
	printk("<6>" "Level 6!\n");
	printk("<7>" "Level 7!\n");

	return 0;
}

void __exit printk_exit(void)
{
	return ;
}

module_init(printk_init);
module_exit(printk_exit);

        【4】查看内核源码

        在Source Insight中查找printk

        【5】优先级说明

宏名宏值说明
KERN_EMERG"<0>"系统不可用
KERN_ALERT"<1>"立即操作
KERN_CRIT"<2>"临界条件
KERN_ERR"<3>"错误
KERN_WARNING"<4>"警告
KERN_NOTICE"<5>"正常但重要
KERN_INFO"<6>"消息
KERN_DEBUG"<7>"调试

        【6】更改程序内容

        vim myprintk.c

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zjd");

int __init printk_init(void)
{
	printk(KERN_EMERG "Level 0!\n");
	printk(KERN_ALERT "Level 1!\n");
	printk(KERN_CRIT "Level 2!\n");
	printk(KERN_ERR "Level 3!\n");
	printk(KERN_WARNING "Level 4!\n");
	printk(KERN_NOTICE "Level 5!\n");
	printk(KERN_INFO "Level 6!\n");
	printk(KERN_DEBUG "Level 7!\n");

	return 0;
}

void __exit printk_exit(void)
{
	return ;
}

module_init(printk_init);
module_exit(printk_exit);

        【7】编写Makefile

        vim Makefile

obj-m += myprintk.o
KERNEL_PATH=/home/zjd/s5p6818/KERNEL/kernel
ROOTFS_PATH=/nfs_share/_install

all:
    make -C $(KERNEL_PATH) M=$(PWD) modules
    cp *.ko $(ROOTFS_PATH)

clean:
    make -C $(KERNEL_PATH) M=$(PWD) clean

        【8】下位机验证

------------------------------------------------

查看内核优先级设置

cat /proc/sys/kernel/printk

第一个值:优先级阈值(这里是2)

第二个值:内核默认优先级(这里是4)

------------------------------------------------

        9、模块参数(三步法)

        在C语言中,我们使用argc、argv给程序传参

./a.out xxx yyy zzz

// int main(int argc, char **argv)

int main(int argc, char *argv[]){

        ...

};

                1)定义全局变量
int irq = 0;
char *str = "Hello World!";
int fish[10] = {0};
int num = 10;

int __init module_param_init(void)
{
    ...;
    return 0;
}
                2)通过特定的宏

module_param(name, type, perm)

name:要声明为模块参数的变量名

type:变量的类型

perm:权限

module_param_array(name, type, nump, perm)

name:要声明为模块参数的数组名

type:数组元素的类型

nump:数组元素个数指针

perm:权限

                3)使用模块参数

        insmod module_param.ko

        insmod module_param.ko irq=10 str="easthome" fish=1,2,3,4,5,6

                4)验证

        【1】创建工程目录

        mkdir module_param

        【2】进入工程目录

        cd module_param

        【3】编写程序

        vim module_param.c

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zjd");

int irq = 0;
char *str = "hello world!";
int len = 10;
int arr[10] = {0};

module_param(irq, int, 0644);
module_param(str, charp, 0);
module_param_array(arr, int, &len, 0644);

int __init module_param_init(void)
{
	int i = 0;

	printk(KERN_EMERG "irq = %d\n", irq);
	printk(KERN_EMERG "str = %s\n", str);

	// Linux Kernel apply the define of ARRAY_SIZE 
	// to count the number of members
	// #define ARRAY_SIZE(x) sizeof(x) / sizeof(x[0])
	for (i = 0; i < ARRAY_SIZE(arr); i++) {
		printk(KERN_EMERG "arr[%d] = %d\n", i, arr[i]);
	}

	return 0;
}

void __exit module_param_exit(void)
{
	printk(KERN_EMERG "bye ~\n");

	return ;
}

module_init(module_param_init);
module_exit(module_param_exit);

        【4】编写Makefile

        vim Makefile

obj-m += module_param.o
KERNEL_PATH=/home/zjd/s5p6818/KERNEL/kernel
ROOTFS_PATH=/nfs_share/_install

all:
	make -C $(KERNEL_PATH) M=$(PWD) modules
	cp *.ko $(ROOTFS_PATH)

clean:
	make -C $(KERNEL_PATH) M=$(PWD) clean

        【5】下位机验证

        模板参数在系统中有负责维护的节点

        /sys/module/module_param/parameters/

        【6】思考

        我们在驱动代码里面定义了3个全局变量,这里只出来两个,arr、irq

        因为我们将str全局变量的权限设定为0,所以没有显示

        我们给irq与arr全局变量设定的权限就是该节点文件的权限

        【7】意义

        我们可以在内核中验证寄存器的功能,将寄存器声明为模块参数,在安装模块的时候就可以使用模块参数(REG=VAL)

        a、系统调用

                系统调用是用户进入内核空间的一种方式(还可以通过中断进入内核空间)

        1)意义

        【1】用户空间到内核空间

                是用户空间调用内核空间函数的一种方式

        【2】安全

                系统调用保证了内核的安全,允许应用程序调用内核中的函数(以安全的方式)

        2)系统调用的实现

        1】应用程序首先使用适当的值,填充寄存器

        2】调用特殊的指令

        3】执行指令,跳转到某个位置

        4】在该位置,根据填充到寄存器的值,找到内核中对应的函数

        5】调用该函数

        6】函数执行完毕后,原路返回到用户空间

        3)验证

        【1】应用程序选取适当的值

        vim kernel/arch/arm/include/asm/unistd.h

        【2】填充寄存器

        vim kernel/arch/arm/kernel/entry-common.S

        寄存器:r7

        【3】调用特殊指令

        vim kernel/arch/arm/kernel/entry-common.S

检查系统调用号

去系统调用表中的宏进行匹配

输出调用号,跳转到asm_syscall()

        vim kernel/arch/arm/kernel/traps.c

        vim arch/arm/kernel/calls.S

        4)演示

        【1】新增一个系统调用号

        vim kernel/arch/arm/include/asm/unistd.h

        【2】新增一个内核中的API(接口)函数

        vim kernel/arch/arm/kernel/sys_arm.c

        【3】修改系统调用表

        vim kernel/arch/arm/kernel/call.S

        【4】重新编译内核

        make uImage

        【5】重新烧录内核

        cp arch/arm/boot/uImage /tftpboot

        tftp 48000000 uImage

        mmc write 48000000 2000 3000

        re

        【6】系统调用syscall

        【7】编写测试程序

        mkdir sys_call

        vim sys_add.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>

#define SYS_ADD_NUM		378

int main(void)
{
	int ret = 0;

	ret = syscall(SYS_ADD_NUM, 20, 6);

	printf("ret = %d\n", ret);

	return 0;
}

        【8】编译sys_add.c文件

                arm-cortex_a9-linux-gnueabi-gcc sys_add.c -o sys_add

        【9】下位机测试

                cp sys_add /nfs_share/_install/

        【a】调试

                1】查找交叉编译链工具位置

        which arm-cortex_a9-linux-gnueabi-gcc

                2】进入gcc的库目录

        cd /opt/toolchains/arm-cortex_a9-eabi-4.7-eglibc-2.18/arm-cortex_a9-linux-gnueabi/lib

                3】拷贝需要的库文件根文件系统

        cp libgcc_s.so.1 /nfs_share/_install/lib/

        【b】再次测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/877495.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WPF利用Path自定义画头部导航条(TOP)样式

1;新建两个多值转换器&#xff0c;都有用处&#xff0c;用来动态确定PATH的X,Y州坐标的。 EndPointConverter 该转换器主要用来动态确定X轴&#xff0c;和Y轴。用于画线条的。 internal class EndPointConverter : IMultiValueConverter {public object Convert(object[] val…

wifiip地址可以随便改吗?wifi的ip地址怎么改变

对于普通用户来说&#xff0c;WiFi IP地址的管理和修改往往显得神秘而复杂。本文旨在深入探讨WiFi IP地址是否可以随意更改&#xff0c;以及如何正确地改变WiFi的IP地址。虎观代理小二将详细解释WiFi IP地址的基本概念、作用以及更改时需要注意的事项&#xff0c;帮助用户更好地…

PPT中的图形与图片:插入、调整与格式设置技术详解

目录 引言 一、图形与图片的插入 1. 插入图形 2. 插入图片 二、图形与图片的调整 1. 调整大小与位置 2. 裁剪与旋转 3. 图形与图片的合并与组合 三、图片格式与布局设置 1. 图片格式设置 2. 图片布局设置 示例案例&#xff1a;制作产品展示PPT 四、结论 引言 在现…

Harmony OS DevEco Studio低代码开发流程 - HarmonyOS开发自学5

一. 为什么要用低代码开发&#xff1f; HarmonyOS低代码开发方式&#xff0c;具有丰富的UI界面编辑功能&#xff0c;例如基于图形化的自由拖拽、数据的参数化配置等&#xff0c;通过可视化界面开发方式快速构建布局&#xff0c;可有效降低用户的时间成本和提升用户构建UI界面的…

【JVM】类加载

1. 类加载过程 Java虚拟机&#xff08;JVM&#xff09;的 类加载 过程是将字节码文件&#xff08;.class文件&#xff09;从存储设备加载到内存&#xff0c;并为其创建相应的类对象的过程。类加载是Java程序运行的基础&#xff0c;保证了程序的动态性和安全性。JVM的类加载过程…

Unity 粒子系统参数说明

一、Particle System 1. Duration&#xff08;持续时间&#xff09; 粒子系统运行一次所需的时间。它决定粒子系统持续播放的时间长度。 2. Looping&#xff08;循环播放&#xff09; 如果启用&#xff0c;粒子系统将在播放完一次后自动重新开始播放&#xff0c;直到你停止它…

pgrouting实战应用

1&#xff09;下载地区地区数据&#xff08;下载数据是XYZM 四位数据&#xff09; 2&#xff09;下载裁剪行政区数据 3&#xff09;使用arcgis pro添加路网数据和行政区数据 4&#xff09;裁剪数据&#xff0c;仅历下行政区路网 5&#xff09;arcgis pro要素转线&#xff0…

【数据结构】顺序表和链表经典题目

系列文章目录 单链表 动态顺序表实现通讯录 顺序表 文章目录 系列文章目录前言一、顺序表经典例题1. 移除元素2. 合并两个有序数组 二、链表经典例题1. 移除链表元素2. 反转链表3. 合并两个有序链表4. 链表的中间节点5. 环形链表的约瑟夫问题 总结 前言 我们通过前面对顺序表…

ArrayList 源码解析

ArrayList是Java集合框架中的一个动态数组实现&#xff0c;提供了可变大小的数组功能。它继承自AbstractList并实现了List接口&#xff0c;是顺序容器&#xff0c;即元素存放的数据与放进去的顺序相同&#xff0c;允许放入null元素&#xff0c;底层通过数组实现。除该类未实现同…

HTB-Vaccine(suid提权、sqlmap、john2zip)

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天来为大家讲解Vaccine靶机 渗透过程 信息搜集 服务器开放了 21FTP服务、22SSH服务、80HTTP服务 通过匿名登录FTP服务器 通过匿名登录到服务器&#xff0c;发现backup.zip文件&#xff0c;可能存在账号密码 发现b…

2024.9.16 day 1 pytorch安装及环境配置

一、配置pytorch环境&#xff0c;安装pytorch 1.查看python版本 python --version 2.在anaconda命令中创建pytorch环境 conda create -n pytorch python3.12(python版本&#xff09; 3.pytorch安装 pytorch首页 PyTorchhttps://pytorch.org/ os为windows推荐package选择…

算法练习题27——疫情下的电影院(模拟)

其实思路还好 就是输入有点难搞 Java import java.util.ArrayList; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);String input scanner.nextLine();// 去掉输入字符串的方括号if (input.…

react 安装使用 antd+国际化+定制化主题+样式兼容

安装antd 现在从 yarn 或 npm 或 pnpm 安装并引入 antd。 yarn add antd修改 src/App.js&#xff0c;引入 antd 的按钮组件。 import React from react; import { Button } from antd;const App: React.FC () > (<div className"App"><Button type&q…

USB摄像头视频流转RTSP流

一、VLC查看USB摄像头视频流原理&#xff1a; USB摄像头的工作原理与VLC播放其他视频文件类似&#xff0c;主要区别在于视频流的来源是实时捕获的&#xff0c;而不是预先录制的文件。如果使用VLC将USB摄像头的视频流作为RTSP服务器广播&#xff0c;需要进一步配置 二、VLC查看…

[机器学习]决策树

1 决策树简介 2 信息熵 3 ID3决策树 3.1 决策树构建流程 3.2 决策树案例 4 C4.5决策树 5 CART决策树&#xff08;分类&回归&#xff09; 6 泰坦尼克号生存预测案例 import pandas as pd from sklearn.model_selection import train_test_split from sklearn.tree import …

扣子智能体实战-汽车客服对话机器人(核心知识:知识库和卡片)

这一节的主要内容是通过创建一个汽车客户对话机器人学习扣子平台知识库和卡片的使用。 机器人参考&#xff1a; 企业汽车客服 资深汽车销售 一&#xff0c;汽车销售机器人需求简介 汽车销售是一个需要 7*24h在线的客服咨询岗位&#xff0c;专业性强&#xff0c;但流动性非…

【数据结构】排序算法---直接插入排序

文章目录 1. 定义2. 算法步骤3. 动图演示4. 性质5. 算法分析6. 代码实现C语言PythonJavaCGo 7. 折半插入排序代码实现——C 结语 1. 定义 直接插入排序是一种简单直观的排序算法。它的工作原理为将待排列元素划分为「已排序」和「未排序」两部分&#xff0c;每次从「未排序的」…

自定义EPICS在LabVIEW中的测试

继续上一篇&#xff1a;LabVIEW中EPICS客户端/服务端的测试 变量定义 You can use CaLabSoftIOC.vi to create new EPICS variables and start them. CA Lab - LabVIEW (Realtime) EPICS INPUT: PV set Cluster-array of names, data types and field definitions to crea…

【Go】Go语言介绍与开发环境搭建

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【Elasticsearch系列六】系统命令API

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…