2019-12-03 21:19:43 u010743406 阅读数 9
  • 驱动应该怎么学-linux驱动开发第1部分

    本课程是linux驱动开发的第一个课程,主要介绍linux驱动的概念、模块化设计理念、分类、安全性要求,后讲解了linux驱动课程的整体学习方法。学习本课程主要是为后续正式学习linux驱动打个基础。

    4754 人正在学习 去看看 朱有鹏

参考:宋宝华 Linux设备驱动开发详解  嵌入式Linux驱动开发教程

开发环境:ubuntu16.04

所需Makefile文件感谢网友,链接:https://www.cnblogs.com/guanguangreat/p/7920378.html

1- hello world 模块代码,名字取为hello.c。由于Makefile文件不会写,直接复制过来,人家用的就是hello.c,其他名字编不过。。。

#include<linux/init.h> //包含module_init module_exit
#include<linux/kernel.h> //包含printk函数声明
#include<linux/module.h> //

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_ALERT"hello world enter\n");
    return 0;
}
static void helllo_exit(void)
{
    printk(KERN_ALERT"hello world exit\n");
}

module_init(hello_init); //_init只会被调用一次
module_exit(helllo_exit);

MODULE_AUTHOR("lhk"); //作者
MODULE_DESCRIPTION("a simple hello world module"); //模块描述
MODULE_ALIAS("hello world module"); //模块别名

2- Makefile 文件

注意名字一定是Makefile!!!!并且注意TBL缩进

ifneq  ($(KERNELRELEASE),)
obj-m:=hello.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	rm -f *.ko *.o *.symvers *.cmd *.cmd.o
endif

之后在目录执行make命令,编译出所需的ko文件

make

3- 模块加载 模块卸载 查看模块信息

在编好的ko目录下,执行模块加载命令,将模块加载到内核

insmode hello.ko

通过lsmod查看内核中模块,通过dmesg查看那内核加载信息;通过modinfo查看模块信息

lsmod
dmesg
modinfo hello.ko

模块卸载

rmmod hello

 

总结:

学会了简单模块的编写

了解了加载模块Makefile文件的编写,此方面还有待学习。听说有个《跟我一起写Makefile》的资料不错,看下啊

学习了模块加载卸载相关内容

 

 

2019-12-09 14:49:21 qq_41988448 阅读数 49
  • 驱动应该怎么学-linux驱动开发第1部分

    本课程是linux驱动开发的第一个课程,主要介绍linux驱动的概念、模块化设计理念、分类、安全性要求,后讲解了linux驱动课程的整体学习方法。学习本课程主要是为后续正式学习linux驱动打个基础。

    4754 人正在学习 去看看 朱有鹏

Windows驱动开发学习笔记(一)—— 环境配置&第一个驱动程序

前言

一、学习自滴水编程达人中级班课程,官网:https://bcdaren.com
二、海东老师牛逼!

环境配置

安装VS2010:https://pan.baidu.com/s/1uZWWxCtB60QPaqlf4ICWVQ 提取码:qqro
安装WDK7600:https://pan.baidu.com/s/1OsWmwrMXClxzAhpfqli6ew 提取码:bvxh

附件:
DriverProperty.props 提取码:7y6b
KmdManager.exe 提取码:sntp


1、新建一个空项目
在这里插入图片描述
2、打开配置管理器
在这里插入图片描述
3、新建配置
在这里插入图片描述
在这里插入图片描述
4、打开属性管理器
在这里插入图片描述
5、添加新项目属性表
在这里插入图片描述
在这里插入图片描述
6、在项目目录中使用记事本打开新建的项目属性表
在这里插入图片描述
7、使用提前准备好的项目属性表替换文本内容
在这里插入图片描述
8、重启VS2010
9、新建源文件
在这里插入图片描述
在这里插入图片描述
10、写入测试代码并编译,编译通过即可
在这里插入图片描述

第一个驱动程序

1、使用VS2010编译以下代码

#include "ntddk.h"

//卸载函数
VOID DriverUnload(PDRIVER_OBJECT driver)
{
	DbgPrint("驱动程序已停止.\r\n");
}

//驱动程序入口函数,相当于控制台的main函数
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
	DbgPrint("驱动程序已运行.\r\n");

	//设置一个卸载函数  便于退出
	DriverObject->DriverUnload = DriverUnload;

	return STATUS_SUCCESS;
}

在这里插入图片描述
2、将编译好的文件拷贝到XP操作系统
3、开启DbgView的“监视核心”功能
在这里插入图片描述
4、使用KmdManager对编译好的驱动程序进行测试
在这里插入图片描述

2016-07-05 10:18:09 enjoy5512 阅读数 6111
  • 驱动应该怎么学-linux驱动开发第1部分

    本课程是linux驱动开发的第一个课程,主要介绍linux驱动的概念、模块化设计理念、分类、安全性要求,后讲解了linux驱动课程的整体学习方法。学习本课程主要是为后续正式学习linux驱动打个基础。

    4754 人正在学习 去看看 朱有鹏

转载请注明来源:
enjoy5512的博客 : http://blog.csdn.net/enjoy5512
GitHub : https://github.com/whu-enjoy

为了整理方便,可以在一个合适的路径下建立一个专门的文件夹用于保存源代码.打开桌面的x86 Checked Build Enviroment快捷方式,进到源代码所在文件夹下,可以看到每个程序至少有三个文件,一个源代码文件,一个是makefile,一个sources,头文件是可选的
这里写图片描述


头文件

/////////////////////////////////////////////////////////////////////////////
//  文件名 : fitst.h
//  工程 : first 
//  作者 : enjoy5512   修改者 : enjoy5512   最后优化注释者 : enjoy5512
//  个人技术博客 : blog.csdn.net/enjoy5512
//  个人GitHub   : github.com/whu-enjoy
//  描述 : 第一个驱动程序的头文件
//  版本 : 最终确定版  完成日期 : 2016年7月5日 09:25:30
//  修改 :
//  参考文献 :
//       <<Windows内核安全与驱动开发>> 谭文 陈铭霖 编著
//////////////////////////////////////////////////////////////////////////////

#ifndef __FIRST_H__
#define __FIRST_H__


//////////////////////////////////////////////////////////////////////////////
//*= = 头文件声明
//////////////////////////////////////////////////////////////////////////////
#include <ntddk.h>

//////////////////////////////////////////////////////////////////////////////
//*= = 宏与结构体
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//*= = 函数声明
//////////////////////////////////////////////////////////////////////////////
NTSTATUS
DriverEntry(
    __in PDRIVER_OBJECT DriverObject,
    __in PUNICODE_STRING RegistryPath
    );

VOID
DriverUnload(
    __in PDRIVER_OBJECT DriverObject
    );

#endif //End of __FIRST_H__

源代码

/////////////////////////////////////////////////////////////////////////////
//  文件名 : fitst.c
//  工程 : first 
//  作者 : enjoy5512   修改者 : enjoy5512   最后优化注释者 : enjoy5512
//  个人技术博客 : blog.csdn.net/enjoy5512
//  个人GitHub   : github.com/whu-enjoy
//  描述 : 第一个驱动程序
//  主要函数 :
//      VOID DriverUnload(PDRIVER_OBJECT driver) 卸载函数
//      NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) 入口函数
//  版本 : 最终确定版  完成日期 : 2016年7月5日 09:36:17
//  修改 :
//  参考文献 :
//       <<Windows内核安全与驱动开发>> 谭文 陈铭霖 编著
/////////////////////////////////////////////////////////////////////////////

#include "first.h"

//程序说明开始
//==================================================================================
//  功能 : 驱动程序入口函数
//  参数 :    __in PDRIVER_OBJECT DriverObject, in PUNICODE_STRING RegistryPath
//  (入口)  __in PDRIVER_OBJECT DriverObject  : 驱动对象
//          __in PUNICODE_STRING RegistryPath : 驱动在注册表中的键值
//  (出口)  无
//  返回 :  NTSTATUS
//  主要思路 : 先设置一个int3断点,然后输出一句话,设置卸载函数
//  调用举例 : 
//  日期 : 2016年7月5日 09:32:32
//==================================================================================
//程序说明结束
NTSTATUS 
DriverEntry(
    __in PDRIVER_OBJECT DriverObject, 
    __in PUNICODE_STRING RegistryPath
    )
{
    #if DBG
        _asm int 3
    #endif

    DbgPrint("first : hello ,load server!!\n");

    DriverObject->DriverUnload = DriverUnload;

    return STATUS_SUCCESS;
}

//程序说明开始
//==================================================================================
//  功能 : 驱动程序卸载
//  参数 :    __in PDRIVER_OBJECT DriverObject
//  (入口)  __in PDRIVER_OBJECT DriverObject  : 驱动对象
//  (出口)  无
//  返回 :  VOID
//  主要思路 : 输出一句话
//  调用举例 : 
//  日期 : 2016年7月5日 09:35:59
//==================================================================================
//程序说明结束
VOID 
DriverUnload(
    __in PDRIVER_OBJECT driver
    )
{
    DbgPrint("firts:Our driver is unloading!!\r\n");
}

makefile文件

这个文件是固定的,内容不变

!IF 0

Copyright (C) Microsoft Corporation, 1999 - 2002

Module Name:

    makefile.

Notes:

    DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
    file to this component.  This file merely indirects to the real make file
    that is shared by all the components of Windows NT (DDK)

!ENDIF

!INCLUDE $(NTMAKEENV)\makefile.def


sources文件

TARGETNAME=first
TARGETTYPE=DRIVER
SOURCES=first.c

在源代码路径下,使用build命令编译驱动程序
这里写图片描述

将编译好的first.sys复制到虚拟机中
将程序符号文件路径加到windbg符号路径中
这里写图片描述

设置源代码路径
这里写图片描述

启动服务,可以看到虚拟机卡住了,windbg在int3处中断了,然后便可以开始调试运行了
这里写图片描述

2019-01-29 14:37:27 u013969018 阅读数 1092
  • 驱动应该怎么学-linux驱动开发第1部分

    本课程是linux驱动开发的第一个课程,主要介绍linux驱动的概念、模块化设计理念、分类、安全性要求,后讲解了linux驱动课程的整体学习方法。学习本课程主要是为后续正式学习linux驱动打个基础。

    4754 人正在学习 去看看 朱有鹏

linux设备驱动主要分为三类:字符设备驱动、块设备驱动、网络设备驱动

其中字符设备驱动适合用来入门,结构简单,更多关于设备驱动的东西这里就不作说明。

上传了完整项目文档说明和代码:操作系统课程设计-简单字符设备和块设备驱动程序

字符设备驱动开发流程

1.编写驱动代码

      1.1 定义一个cdev 来表示你的驱动所对应的设备

struct cdev chrdev;

       1.2 为你设备申请一个设备号

unsigned int TestMajor=0;// 主设备号
unsigned int TestMinor=0;// 次设备号
char *name="demo1";//驱动名称
dev_t dev_no; //设备号
int ret; // 返回结果
dev_no =MKDEV(TestMajor,TestMinor);
if(dev_no>0){
ret=register_chrdev_region(dev_no, 1,name);//静态注册设备号
}
else{//动态申请设备号
alloc_chrdev_region(&dev_no,TestMinor, 1,name);
}	
if(ret<0){
return ret;
}

       1.3 定义文件操作集

int my_open(struct inode *i,struct file *f){
        printk("cdev init\n");
        return 0;
}

int my_release(struct inode *i,struct file *f){
        printk("cdev release\n");
        return 0;
}

static ssize_t my_write(struct file *f,const char __user *u,size_t l,loff_t *o){
        printk("write string\n");
        return l;
}

static ssize_t my_read(struct file *f,char __user *u,size_t l,loff_t *o){
        printk("read string\n");
        return l;
}

struct file_operations fops={
        .owner=THIS_MODULE,
        .open=my_open,
        .release=my_release,
        .write=my_write,
        .read=my_read
};

 

      1.4 初始化 cdev并添加到内核

cdev_init(&chrdev,&fops);
cdev_add(&chrdev,dev_no,1);//先初始化设备号,然后注册cdev

         1.5 设备号和cdev 的注销

unregister_chrdev_region(dev_no, 1);
cdev_dev(&chrdev);

         在贴上完整代码前先注明一点内容:

          一个驱动程序必须的部分如下:

static int my_init(void){ 
        //驱动的初始化
        return 0;
}

static void my_exit(void){
        //驱动的退出
}

module_init(my_init); //调用系统函数来设置驱动初始化函数
module_exit(my_exit); //设置驱动结束的函数

MODULE_AUTHOR("guoz"); //设置作者 ,非必须
MODULE_DESCRIPTION("this ostest demo1"); //设置描述,非必须
MODULE_LICENSE("GPL"); // 必须加上,含义自行查找

           字符设备驱动涉及到了用户态和核态的信息传递,这里放上两个用户传递信息的系统函数:

#include<linux/uaccess.h> //头文件
//函数原型
unsigned  long  copy_to_user(void *to,  const void  __user  *from,  usigned long  count);
unsigned  long  copy_from_user(void __user *to,  const void *from,  usigned long  count);

         完整驱动程序代码如下:

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/kdev_t.h>
#include<linux/types.h>
#include<linux/uaccess.h>
#include<linux/string.h>

struct cdev chrdev;
unsigned int major=0;
unsigned int minor=0;
dev_t dev_no;
int ret;

int my_open(struct inode *i,struct file *f){
	printk("cdev init\n");
	return 0;
}

int my_release(struct inode *i,struct file *f){
	printk("cdev release\n");
	return 0;
}

static ssize_t my_write(struct file *f,const char __user *u,size_t l,loff_t *o){
	char buf[100];
	copy_from_user(buf,u,l);
	printk(KERN_EMERG"write string:%s",buf);
	return l;
}

static ssize_t my_read(struct file *f,char __user *u,size_t l,loff_t *o){
	char *buf="hello,user!";
	copy_to_user(u,buf,strlen(buf));
	printk(KERN_EMERG"read string:%s",buf);
	return l;
}

struct file_operations fops={
	.owner=THIS_MODULE,
	.open=my_open,
	.release=my_release,
	.write=my_write,
	.read=my_read
};

static int my_init(void){
	dev_no=MKDEV(major,minor);
	if(dev_no>0){
		ret=register_chrdev_region(dev_no,1,"demo1");
	}else{
		ret=alloc_chrdev_region(&dev_no,0,1,"demo1");
	}
	if(ret<0){
		return ret;
	}
	cdev_init(&chrdev,&fops);
	chrdev.owner=THIS_MODULE;
	cdev_add(&chrdev,dev_no,1);
	return 0;
}

static void my_exit(void){
	unregister_chrdev_region(dev_no,1);
	cdev_del(&chrdev);
}

module_init(my_init);
module_exit(my_exit);

MODULE_AUTHOR("guoz");
MODULE_DESCRIPTION("this ostest demo1");
MODULE_LICENSE("GPL");

 

2.编写Makefile文件

    用于编译驱动程序,文件可复制粘贴使用,注意修改 obj-m 的值

    

ifneq ($(KERNELRELEASE),)
obj-m := demo1.o
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	rm -fr .*.cmd *.o *.mod.c *.ko .tmp_versions modules.* Module.*
endif

   这里也有坑注意,只有当该行写的命令时才能用 tab 符号开头,而且字符编码需要用 utf-8

3.检查驱动安装是否完成

     上面的步骤完成后,结果就是两个文件 

demo1.c Makefile

      3.1 在当前目录执行 make 命令(默认执行的是make all)

gz@ubuntu:~/Desktop/demo1$ ls
demo1.c  Makefile  test.c
gz@ubuntu:~/Desktop/demo1$ make
make -C /lib/modules/4.15.0-43-generic/build M=/home/gz/Desktop/demo1 modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-43-generic'
  CC [M]  /home/gz/Desktop/demo1/demo1.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/gz/Desktop/demo1/demo1.mod.o
  LD [M]  /home/gz/Desktop/demo1/demo1.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-43-generic'
gz@ubuntu:~/Desktop/demo1$ ls
demo1.c   demo1.mod.c  demo1.o   modules.order   test.c
demo1.ko  demo1.mod.o  Makefile  Module.symvers

      3.2 向内核插入驱动程序并获取设备号

root@ubuntu:/home/gz/Desktop/demo1# insmod demo1.ko 
root@ubuntu:/home/gz/Desktop/demo1# cat /proc/devices 
Character devices:
  ...
243 demo1
  ...

   3.3 添加设备文件

        从上一步可以得知 设备号为 243

root@ubuntu:/home/gz/Desktop/demo1# mknod /dev/demo1 c 243 0
root@ubuntu:/home/gz/Desktop/demo1# ll /dev/demo1 
crw-r--r-- 1 root root 243, 0 Jan 28 22:28 /dev/demo1

 

4.编写简单测试程序

测试文件比较简单,这里直接贴完整代码 (test.c)

#include<stdio.h>
#include <unistd.h>
#include<fcntl.h>
int main(void)
{
int fd;
char *buf="test.c";
char buf2[20];
fd=open("/dev/demo1",O_RDWR);
if(fd<0){
	printf("fd<0\n");
}else{
	printf("fd:%d\n",fd);
}
write(fd,buf,7);
read(fd,buf2,18);
printf("res:%s",buf2);
close(fd);
}

5.检验成果

运行测试程序,结果如下:

root@ubuntu:/home/gz/Desktop/demo1# gcc test.c 
root@ubuntu:/home/gz/Desktop/demo1# ./a.out
fd:3
res:hello,user!root

在驱动程序中,使用printk输出的内容我们不能直接看到,这里采用dmesg命令查看

root@ubuntu:/home/gz/Desktop/demo1# dmesg
...
[  909.055395] cdev init
[  909.055458] write string:test.c
[  909.055461] read string:hello,user!
[  909.055469] cdev release

 

参考文章:字符设备驱动模块与测试代码编写

2014-08-22 14:36:23 a1844811904 阅读数 116
  • 驱动应该怎么学-linux驱动开发第1部分

    本课程是linux驱动开发的第一个课程,主要介绍linux驱动的概念、模块化设计理念、分类、安全性要求,后讲解了linux驱动课程的整体学习方法。学习本课程主要是为后续正式学习linux驱动打个基础。

    4754 人正在学习 去看看 朱有鹏

#include<NTDDK.h>


VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject)

{

KdPrint(("卸载函数!"));

}


//驱动程序入口函数

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)

{

KdPrint(("你好,驱动程序!"));


//注册卸载函数

pDriverObject->DriverUnload=DriverUnload;

}

没有更多推荐了,返回首页