$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. 大疆消费级无人机调参软件 Assistant 2 与模拟器

    0 大疆消费级无人机调参 Assistant 2 无人机调参软件常用来为无人机的某些参数做校准.大疆的无人机调参软件分为行业级版和消费级版. 行业级版本基本为每个适配机型都添加了与之对应的模拟器功能. ...

  2. uni-app H5 腾讯地图无法导航

    uni-app 打包H5腾讯地图无法导航 具体使用扫描二维码查看 前言: 最近几天用uni-app开发安卓和iOS应用,打包成APP安装包后,APP内做地图导航没有问题,APP内使用的是高德地图:但是 ...

  3. Jenkins Job触发其他远程Job

    https://blog.csdn.net/diaojian66/article/details/117334537 如果不想遇到连接远程Jenkins主机失败后的反复尝试,去掉认证会是一个不错的选择 ...

  4. 侯捷C++高级面向对象编程_下_课程笔记

    friend(友元):相同Class的各个objects互为friends(友元) class complex{ public: complex (double r = 0, double I = 0 ...

  5. Codeforces 1969 A-F

    题面 A B C D E F 难度:红 橙 绿 绿 蓝 紫

  6. java 中的Unsafe

    在阅读AtomicInteger的源码时,看到了这个类:sum.msic.Unsafe,之前从没见过.所以花了点时间google了一下. Unsafe的源码:http://www.docjar.com ...

  7. golang操作ini文件包之go-ini

    官网:ini.unknwon.io/docs github:https://github.com/go-ini/ini ini 是 Windows 上常用的配置文件格式.MySQL 的 Windows ...

  8. Mybatis【9】-- Mybatis占位符#{}和拼接符${}有什么区别?

    代码直接放在Github仓库[https://github.com/Damaer/Mybatis-Learning ],可直接运行,就不占篇幅了. 目录 1.#{}占位符 2.${}拼接符 3.#{} ...

  9. Ubuntu默认启动到字符界面

    修改/etc/default/grub sudo cp /etc/default/grub /etc/default/grub.bak sudo chmod 0777 /etc/default/gru ...

  10. 【C++】类的继承的深入探讨

    继承是扩展现有类并为基类提供新功能的一种方式. 本文主要探讨一个问题:子类会包含父类所包含的一切吗? 起初,作者认为这个问题的答案是否定的,因为子类无法访问父类的private成员 但是,运行下述一个 ...