$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. C语言之输入输出

    标准库 IO 输入输出功能并非C语言的组成部分,ANSI标准定义了相关的库函数 输入输出 <stdio.h> 流stream是与设备关联的数据的源或者目的地. 文本流:由文本行组成的序列 ...

  2. weblogic历史漏洞

    weblogic历史漏洞 是什么?  weblogic是一个web服务器应用(中间件),和jboss一样都是javaee中间件,只能识别java语言,绝大部分漏洞都是T3反序列化漏洞  常见的中间件还 ...

  3. Linux-Centos安装配置

    一.安装CentOs CentOS是Linux系统的一个发行版本,还有Ubuntu.Fedora.Debian等. 安装VMware虚拟机 官网地址:https://www.vmware.com/pr ...

  4. linux下文件夹文件名称最大长度

    今天突发奇想,如果创建一个文件,不写入内容,就如我们之前说的写入扩展属性能快速查找数据,但是在SSD下只能写4000个左右的字符,那么有没有更快速的方法存储这样的信息呢? 我想到可以同文件名来存储信息 ...

  5. npm安装包出现Invalid Version,npm list报错UNMET DEPENDENCY报错

    执行 npm install 出现报错 2097 verbose stack TypeError: Invalid Version: 2097 verbose stack at new SemVer ...

  6. VUE懒加载的table前端搜索

    // 前端搜索 fliterData() { const search = this.search if (search) { this.blist = this.list.filter(item = ...

  7. element-ui table 实现表格展开行每次只能展开一行

    1.table 部分 :row-key='getRowKeys':expand-row-keys="expands"@expand-change="expandSelec ...

  8. Solr 学习(5) —- Solr查询语法和参数

    1.查询地址 建立好solr的索引后,可以通过管理界面进行查询.http://127.0.0.1:8983/solr/admin/form.jsp 要尝试多个查询方法的话,可以进入full inter ...

  9. 2021GPLT

    病毒溯源 给定一棵树,树上有\(n\)个节点,编号从\(0\)到\(n-1\),请你输出从根节点开始的最长的一条链,且该链字典序最小 题解:\(dfs\)树的遍历 + 贪心 首先我们先找到入度为\(0 ...

  10. base64计算文件大小方法(C#和js)

    base64文件大小计算 有时候图片被base64之后需要计算图片大小,因为被编码后全是字符,计算文件大小可以反序列化成文件之后再获取大小,但是会比较麻烦.简单介绍一种利用base64编码原理计算大小 ...