$sudo apt-get install nfs-kernel-server nfs-common

配置


$sudo vim /etc/exports
#添加
#/home/pi/project/rootfs/ *(rw,sync,no_subtree_check,no_root_squash)

#/dir   :共享的目录
#*     :指定哪些用户可以访问
#       * 所有可以ping同该主机的用户
#       192.168.1.* 指定网段,在该网段中的用户可以挂载
#       192.168.1.12 只有该用户能挂载
#(ro,sync,no_root_squash): 权限
#ro : 只读
#rw : 读写
#sync : 同步
#no_root_squash: 不降低root用户的权限
#其他选项man 5 exports 查看

#Ubuntu 18.10默认的NFS不支持NFS2协议,需要手动添加协议支持
$/etc/default/nfs-kernel-server
#添加
RPCNFSDOPTS="--nfs-version 2,3,4 --debug --syslog"

在开发板上挂载NFS


#重启NFS服务
$sudo service nfs-kernel-server restart

#挂载NFS
$sudo mount -t nfs 192.168.2.100:/home/pi/nfs/ /home/pi/nfs/
#查看
$ls /mnt
卸载NFS
$umount /mnt

内核驱动Makefile

编译单文件驱动

KERNELDIR := /home/pi/kernel/linux
COMPILER := arm-linux-gnueabihf-
PWD := $(shell pwd)
all:
   make -C $(KERNELDIR) M=$(PWD) moudles ARCH=arm CROSS_COMPILE=$(COMPILER)
   #make -C 的作用是切换目录(切换进入内核源码目录,执行里面的makefile文件)
   #make -M 的作用是指定编译模块的路径
clean:
   make -C $(KERNELDIR) M=$(PWD) clean ARCH=arm CROSS_COMPILE=$(COMPILER)
install:
   cp *.ko /home/pi/nfs
obj-m := chrdev.o
   #obj-y 是编译进内核
   #obj-m 是编译成驱动模块.ko

编译多文件驱动

KERNELDIR := /home/pi/kernel/linux
COMPILER := arm-linux-gnueabihf-
PWD := $(shell pwd)
all:
   make -C $(KERNELDIR) M=$(PWD) moudles ARCH=arm CROSS_COMPILE=$(COMPILER)
clean:
   rm -f *.o *.mod.c *.ko *.symvers *.order *.makers *.cmd
install:
   cp *.ko /home/pi/nfs
obj-m := hello.o         #-m 生成模块:hello.o生成hello.ko
hello-y := chrdev.o add.o #-y 添加依赖:将chrdev.o add.o 编译进hello.o

驱动入口三要素

入口函数

static init __init driver_init(void)
{
   return 0;
}

出口函数

static void __exit driver_exit(void)
{

}

告诉内核驱动的出入口函数地址

module_init(driver_init);
module_exit(driver_exit);

GPL许可证

MODULE_LICENSE("GPL");	//linux/module.h头文件

创建索引文件

$cd kernel #进入内核源码根目录

$make tags #创建索引文件,普通项目创建索引的方法Ctags -R,但是内核中这样做可能会不完整

$ vi -t __init #搜索代码

内核模块的一些基本操作

基本模块命令

# 安装(args 传参可加可不加)
sudo insmod xxx.ko args # 查看已安装的模块
lsmod # 卸载模块
sudo rmmod xxx

在内核中打印语句

printk(KERN_INFO "%s,%s,%d", __func__, __FILE__, __LINE__);	 /* printk 的用法*/

/* 内核中的打印级别,数字越小级别越高,只有消息级别高于终端的级别打印的信息才会在终端上显示
printk如果不加KERN_LEVEL则会使用默认打印级别,可在/proc/sys/lernel/printk 中修改*/ #define KERN_EMERG KERN_SOH "0" /* system is unusable */
#define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */
#define KERN_CRIT KERN_SOH "2" /* critical conditions */
#define KERN_ERR KERN_SOH "3" /* error conditions */
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
#define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */
#define KERN_INFO KERN_SOH "6" /* informational */
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
#define KERN_DEFAULT KERN_SOH "d" /* the default kernel loglevel */

查看和修改打印级别

#查看打印级别
cat /proc/sys/kernel/printk
4 4 1 7
终端级别 内核消息默认级别 终端的最高级别 终端的最低级别 #Ubuntu下的终端默认不显示内核打印信息,需要按Ctrl+Alt+[F1~F6]切换进入虚拟终端 #修改打印级别,需要切换到root,只能使用echo命令修改
su root
echo 4 3 1 7 > /proc/sys/kernel/printk

查看所有打印信息dmesg

sudo dmesg #查看所有打印信息

sudo dmesg -C #清理所有打印信息

驱动模块传参

/**  * module_param - typesafe helper for a module/cmdline parameter                 * @value:  要更改的变量和暴露的参数名称。
* @type: 参数的类型。
* @perm: 在sysfs中的权限
*
* @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
* ".") the kernel commandline parameter. Note that - is changed to _, so
* the user can use "foo-bar=1" even for variable "foo_bar".
*
* @perm is 0 if the the variable is not to appear in sysfs, or 0444
* for world-readable, 0644 for root-writable, etc. Note that if it
* is writable, you may need to use kernel_param_lock() around
* accesses (esp. charp, which can be kfreed when it changes).
*
* The @type is simply pasted to refer to a param_ops_##type and a
* param_check_##type: for convenience many standard types are provided but
* you can create your own by defining those variables.
*
* Standard types are:
* byte, short, ushort, int, uint, long, ulong
* charp: a character pointer
* bool: a bool, values 0/1, y/n, Y/N.
* invbool: the above, only sense-reversed (N = true).
*/
#define module_param(name, type, perm) \
module_param_named(name, name, type, perm)
--------------------------------------------------------
/* One for each parameter, describing how to use it. Some files do
* multiple of these per line, so can't just use MODULE_INFO.
* 模块传参描述
* @_parm:参数名
* @desc:描述的字段
*/
#define MODULE_PARM_DESC(_parm, desc) \ __MODULE_INFO(parm, _parm, #_parm ":" desc)
----------------------------------------------------------
/**
* module_param_array - a parameter which is an array of some type
* @name: 数组名
* @type: 数组类型
* @nump: 传入数组元素数量的指针
* @perm: 在sysfs中的权限
*
* Input and output are as comma-separated values. Commas inside values
* don't work properly (eg. an array of charp).
*
* ARRAY_SIZE(@name) is used to determine the number of elements in the
* array, so the definition must be visible.
*/
#define module_param_array(name, type, nump, perm) \
module_param_array_named(name, name, type, nump, perm)
---------------------------------------------------------------
/**
* module_param_string - a char array parameter
* @name: 参数名(字符数组名)
* @string: 字符数组名
* @len: 字符串的最大长度
* @perm: 在sysfs中的权限
*
* This actually copies the string when it's set (unlike type charp).
* @len is usually just sizeof(string).
*/
#define module_param_string(name, string, len, perm) \
static const struct kparam_string __param_string_##name \
= { len, string }; \
__module_param_call(MODULE_PARAM_PREFIX, name, \
&param_ops_string, \
.str = &__param_string_##name, perm, -1, 0);\
__MODULE_PARM_TYPE(name, "string")
驱动模块传参示例1:单个参数
#include <linux/module.h>
#include <linux/init.h> //定义默认值
int arg = 100; //接收传参
module_param(arg, int, 0664); //权限最大只能是0775否则编译报错
/* 将会在/sys/module/xxx驱动模块名称/paramters/ 出现对应的参数名称的文件
* 这个文件的权限就就是module_param中的权限,同时也可以对这个文件写数据来在
* 驱动安装完成之后向驱动模块传值 */ //传参描述
MODULE_PARM_DESC(a, "this is chrdev parameter, default=100,span 0-199"); static int __init chrdev_init(void) {
printk(KERN_EMERG "hello kernel!\n");
printk("param = %d\n", arg);
printk(KERN_EMERG "%s, %s, %d\n", __FILE__, __func__, __LINE__);
return 0;
} static void __exit chrdev_exit(void) {
printk(KERN_EMERG "%s, %s, %d\n",__FILE__, __func__, __LINE__);
} module_init(chrdev_init);
module_exit(chrdev_exit);
MODULE_LICENSE("GPL");

查看驱动模块信息

modinfo xxx.ko

打印效果

驱动模块传参示例2:多个参数
#include <linux/module.h>
#include <linux/init.h> //定义默认值
int val = 100;
char chr = ' ';
char *p = "defualt"; //接收传参
module_param(val, int, 0664);
module_param(chr, byte, 0664);
module_param(p, charp, 0664); //传参描述
MODULE_PARM_DESC(val, "val is this module parameter, default=100,span 0-199");
MODULE_PARM_DESC(chr, "chr is this module parameter, default=' '");
MODULE_PARM_DESC(val, "p is this module parameter, default=\"default\""); static int __init chrdev_init(void) {
printk(KERN_EMERG "hello kernel!\n");
printk(KERN_EMERG "param val = %d\n", val);
printk(KERN_EMERG "param chr= %c\n", chr);
printk(KERN_EMERG "param p = %s\n", p);
printk(KERN_EMERG "%s, %s, %d\n", __FILE__, __func__, __LINE__);
return 0;
} static void __exit chrdev_exit(void) {
printk(KERN_EMERG "%s, %s, %d\n",__FILE__, __func__, __LINE__);
} module_init(chrdev_init);
module_exit(chrdev_exit);
MODULE_LICENSE("GPL");

多个值同时传入

sudo insmod chrdev.ko val=99 chr=67 p="pypyn.com_blog"
# 参数名 = 传入值
# 字符传传入的适合注意空格,默认不识别空格,比如"hello world"(非法值),将空格用下划线代替

驱动模块传参示例3:数组
#include <linux/module.h>
#include <linux/init.h> //定义默认值
int val = 100;
char chr = ' ';
char *p = "defualt";
int arr[10]={0,};
int lenth; //接收传参
module_param(val, int, 0664); //权限最大只能是0775否则编译报错
module_param(chr, byte, 0664);
module_param(p, charp, 0664);
module_param_array(arr, int, &lenth, 0664); //注意长度需要取地址 //传参描述
MODULE_PARM_DESC(val, "val is this module parameter, default=100,span 0-199");
MODULE_PARM_DESC(chr, "chr is this module parameter, default=' '");
MODULE_PARM_DESC(val, "p is this module parameter, default=\"default\"");
MODULE_PARM_DESC(arr, "arr is int arr[10] array, default={0,}"); static int __init chrdev_init(void) {
int i=0;
printk(KERN_EMERG "hello kernel!\n");
printk(KERN_EMERG "param = %d\n", val);
printk(KERN_EMERG "%c\n", chr);
printk(KERN_EMERG "%s\n", p); for(i=0; i<lenth; i++){
printk(KERN_EMERG "arr[%d]=%d\n", i, arr[i]);
} printk(KERN_EMERG "%s, %s, %d\n", __FILE__, __func__, __LINE__);
return 0;
} static void __exit chrdev_exit(void) {
printk(KERN_EMERG "%s, %s, %d\n",__FILE__, __func__, __LINE__);
} module_init(chrdev_init);
module_exit(chrdev_exit);
MODULE_LICENSE("GPL");

多个值同时传入

sudo insmod chrdev.ko val=99 chr=67 p="pypyn.com_blog" arr=14,3,2,1,0
# 参数名 = 传入值
# 字符传传入的适合注意空格,默认不识别空格,比如"hello world"(非法值),将空格用下划线代替
# 数组=1,2,3

驱动模块传参示例4:字符数组
#include <linux/module.h>
#include <linux/init.h>

//定义默认值
char str[64]={0,};

//接收传参
module_param_string(str, str, 64-1, 0664);

//传参描述
MODULE_PARM_DESC(string, "str is this string array, default=NULL");

static int __init chrdev_init(void) {
   int i=0;
   printk(KERN_EMERG "%s\n", str);   
   printk(KERN_EMERG "%s, %s, %d\n", __FILE__, __func__, __LINE__);
   return 0;
}

static void __exit chrdev_exit(void) {
   printk(KERN_EMERG "%s, %s, %d\n",__FILE__, __func__, __LINE__);
}

module_init(chrdev_init);
module_exit(chrdev_exit);
MODULE_LICENSE("GPL");

多个值同时传入

sudo insmod chrdev.ko str=xiaoyang
# 参数名 = 传入字符(不需要双引号,不能用空格)

导出符号表

内存地址表


1G
0x4000 0000

2G
0x8000 0000

3G
0xC000 0000

4G
0xFFFF FFFF

【注意】:符号表中的地址不是内存地址。而是编译器生成的一个地址,内核可以通过这个地址找到导出 的变量或者函数入口。

【作用】:可以调用别人写的函数,简化开发和节省代码量。

1、导出:在A模块的C源码中添加


EXPORT_SYMBOL_GPL(function_name); /* 可导出函数,变量*/

编译这个驱动模块,导出的符号表在 Module.symvers 文件中

2、添加:在B模块中添加从别的模块导出的内容


/* 在源码中声名导入的函数名或者变量 */
extern int function_name(int arg...);
extern int dat;

拷贝A模块中的 Module.symvers 到B模块的根目录,执行make

3、注意事项


1、Module.symvers 符号表文件在执行make clean 之后将会被删除。所以需要注意如果执行了clean就需要将符号表文件重新复制。

2、安装和卸载模块的时候需要先安装导出符号表的模块,再安装导入符号表的模块。卸载模块的时候需要先卸载导入符号表的模块,再卸载导出符号表的模块。

4、导出内核中的函数的符号表


1、在内核源码或已经存在内核驱动源码中添加

EXPORT_SYMBOL(function_name); /* 不带GPL会将函数入口地址放到另外一个段中(内存地址)*/

2、重新编译内核后,导出的符号表将会保存在内核顶层目录下的Module.symvers 文件中。在B模块中添加后编译就不需要再把符号表文件拷贝过来了。因为我们编译内核的Makefile就是依赖内核源码顶层目录下的Makefile,而内核导出的符号表文件也在内核源码顶层目录下。所以编译的时候能直接找到,不需要手动复制。

配置Ubuntu上的NFS的更多相关文章

  1. Ubuntu 18.04 LTS上安装NFS服务器和客户端

    NFS是基于UDP/IP协议的应用,其实现主要是采用远程过程调用RPC机制,RPC提供了一组与机器.操作系统以及低层传送协议无关的存取远程文件的操作.RPC采用了XDR的支持.XDR是一种与机器无关的 ...

  2. 微软KinectV2深度传感器在Ubuntu上的配置和使用

    最新博客地址已转到: http://blog.csdn.net/zzlyw?viewmode=contents   ------------------------------------------ ...

  3. 在虚拟机VM中安装的Ubuntu上安装和配置Hadoop

    一.系统环境: 我使用的Ubuntu版本是:ubuntu-12.04-desktop-i386.iso jdk版本:jdk1.7.0_67 hadoop版本:hadoop-2.5.0 二.下载jdk和 ...

  4. Ubuntu上VNC 配置

    Ubuntu下VNC配置文章分类:操作系统通过将服务器配置成VNC SERVER,可以让其他主机使用图形方式登录这台服务器. 在ubuntu下配置vnc server很简单,方法如下: 服务器端: 1 ...

  5. Ubuntu在ARM上建立NFS服务

    先引用别人的做法: 1.进行NFS服务器端与客户端的安装: sudo apt-get install nfs-kernel-server nfs-common portmap 安装客户端的作用是可以在 ...

  6. Ubuntu上配置SQL Server Always On Availability Group(Configure Always On Availability Group for SQL Server on Ubuntu)

    下面简单介绍一下如何在Ubuntu上一步一步创建一个SQL Server AG(Always On Availability Group),以及配置过程中遇到的坑的填充方法. 目前在Linux上可以搭 ...

  7. ubuntu上配置nginx实现反向代理

    反向代理 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客 ...

  8. ubuntu上vsftpd服务配置

    Ubuntu上提供两种常用的ftp服务应用:vsftpd 和 tftpd,区别如下: 1)vsftpd 支持客户端上下传文件,支持浏览器显示及下载,支持用户名密码认证,支持匿名访问,默认端口TCP:2 ...

  9. Ubuntu上latex+atom配置

    网上流传的latex+atom大都是windows上的,Ubuntu与windows上的配置方式大同小异,这里写下自己的经验: 分为三个步骤,首先安装texlive,texlive是latex的依赖库 ...

  10. Configure Always On Availability Group for SQL Server on Ubuntu——Ubuntu上配置SQL Server Always On Availability Group

    下面简单介绍一下如何在Ubuntu上一步一步创建一个SQL Server AG(Always On Availability Group),以及配置过程中遇到的坑的填充方法. 目前在Linux上可以搭 ...

随机推荐

  1. ABC 364

    ABC 364 E - Maximum Glutton 给定 \((a_i,b_i),X,Y\), 记 \(k\) 是第一个让 \(\sum_{i=1}^{k} a_i > X\) 或 \(\s ...

  2. FA分析树

    \(CFG\) 的分析树 例如语句 \[(1)E \rightarrow E +E \\ (2)E \rightarrow E *E\\ (3)E \rightarrow -E\\ (4)E \rig ...

  3. 高德地图API-搜索提示并定位到位置,卫星地图和标准地图的切换

    // _yourMap地图实例 _yourMap.plugin(["AMap.MapType"], function () { //添加地图类型切换插件 //地图类型切换 mapT ...

  4. JS中如何获取当前日期,并与输入日期作比较

    首先我们获取到"2020-5-5"类型的值 通过Date函数转换 var inputDate = new Date(Date.parse(realTimeEnd)); 获取当前时间 ...

  5. 内网 BitTorrent 下载环境搭建——基于 Transmission

    背景 前段时间为公司的产品增加了磁力链.种子下载的能力,测试时发现网上搜到的热门种子,有时好用,有时不好用,不好用主要表现在:没速度.速度慢.速度不稳定.下载一部分后没速度等,严重拖累了测试工作.为此 ...

  6. 4G模组软件指南 | json数据处理深度学习篇

    针对4G模组软件的json数据处理,我已做出如下示例分享给大家,以4G模组Air780E为例: 1.JSON介绍 JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式 ...

  7. Apache Log4j2远程命令执行漏洞复现

    目录 漏洞原理 复现 漏洞修复 Apache Log4j2 是一个基于Java的日志记录工具,被广泛应用于业务系统开发,开发者可以利用该工具将程序的输入输出信息进行日志记录.Log4j2 远程代码执行 ...

  8. HTTP服务七层架构技术探讨

    作者: phpkernel  发布时间: 2012-11-26 13:27  阅读: 3998 次  推荐: 8   原文链接   [收藏]   1. 为什么分层? 计算机领域的体系结构普遍采用了分层 ...

  9. TreeMap源码分析——深入分析(基于JDK1.6)

    TreeMap有Values.EntrySet.KeySet.PrivateEntryIterator.EntryIterator.ValueIterator.KeyIterator.Descendi ...

  10. vue中使用elementUI的全选表格,点击全选,选中子表格的checkbox

    效果图如下: 由于elementUI提供的表格没办法满足需求,我就在elementUI表格的基础上又做了一些改动 首先,全选的checkbox不是表格自带的,是自己加上去的,子表格中的checkbox ...