栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

驱动开发(三)——地址空间与驱动辅助信息

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

驱动开发(三)——地址空间与驱动辅助信息

文章目录
  • 物理地址与虚拟地址关系
    • 测试程序
    • 测试
    • 问题
    • 问题分析
      • 单片机内存分析
      • Linux应用程序内存分析
  • 驱动程序的改进
    • 问题
    • 解决方法
    • 驱动程序
    • 测试应用程序
    • Makefile
    • 测试


物理地址与虚拟地址关系 测试程序
#include 
#include 
#include 
#include 
static int a=0;
int main(int argc ,char **argv){
    if(argc!=2){
        perror("[user argv error]");
        return -1;
    }
    //将传入的参数转换为long int型给a
    char *endptr;
    a=strtol(argv[1],&endptr,0);
    if(a==ERANGE){
        perror("[strtol error]");
        return -1;
    }
    printf("a=%dn",a);
    printf("address for a=%lxn",(unsigned long )&a);
    printf("address for main=%lxn",(unsigned long )main);
    while (1){
        sleep(100);
    }
    return 0;
}


测试

问题

当我们执行相同的程序时,它在内存中的实际地址与打印出的虚拟地址之间的关系是什么?

内存的映射机制和单片机的映射机制又有什么不同呢?

问题分析 单片机内存分析

对于单片机程序,我想大家一定很清楚,因为在学习一块单片机的时候,我们总是能看到如下这副图片
这是157开发板的单板内存映射图

因此,从上面我们可以分析出一个对应关系,在单片机中,我们编写的单片机程序,通过被加载到flash/RAM中,CPU读取我们的程序以后,直接来控制相应设备的寄存器。因此,在单片机中我们的CPU发出的地址是准确的实际物理地址,工作流程如下
CPU发出一个地址,给内存控制器,内存控制器通过判断地址范围,来对硬件设备进行片选,当片选成功某一个硬件设备时,那么对于CPU而言,整个结构里面就只存在该设备一个设备。那么对于硬件的操作也就变成一对一处理的方式

因此,在单片机程序中,CPU发出的地址是一个实际的物理地址。

Linux应用程序内存分析

操作系统诞生的原因,就在于我们要实现多任务。即不能像单片机程序那样,单一的处理某一个程序。因此在我们Linux应用程序中,CPU的工作模式如下

在运行操作系统的时候,会启动我们的MMU(内存管理单元),此时我们的CPU发出的地址不再是一个实际的物理地址,而是经过MMU转换的虚拟地址。
当我们的程序被加载进RAM时,MMU中会存储着该程序的实际内存地址与虚拟内存地址的映射表,当操作系统将程序的虚拟地址告诉CPU,CPU去读取时,将会发出该虚拟地址给MMU单元,MMU将虚拟地址进行转换,选中我们的RAM,进而使得CPU去处理我们的程序。

因此,在Linux应用程序中,我们的CPU发出的是一个虚拟地址,他会发送给MMU单元,通过MMU进行地址转换进而控制硬件。

这样做的好处是什么?,这就使得,对于操作系统中的每一个程序而言,都能独享全部的内存空间。因为即时虚拟地址相同,也会在MMU的映射控制下,映射到不同的实际内存空间。这也使得内存的管理变得高效,安全起来。也因此诞生了内存的段页式存储。

驱动程序的改进 问题

在上一篇博客中我们总是在挂载驱动之后要去对该驱动创建一个设备节点

sudo mknod /dev/xxx c xxx xxx。
这是不是显得非常的麻烦,为什么就不能通过程序直接自动的创建设备节点呢?

答案是,完全可以。

解决方法

在驱动程序中,引入我们的 class_create函数和device_create函数,以实现自动创建设备节点的功能

驱动程序
#include 
#include 
#include 
#include 
#include 
//设置主设备号
static int major=0;
//创建设备结构体对象
static struct class *class_for_hello;

//实现open函数
static int hello_open(struct inode *node, struct file *fp)
{
    return 0;
}
//实现read函数
static ssize_t hello_read(struct file *fp, char __user *buf, size_t len, loff_t *pos)
{
    int ret;
    ret=copy_to_user(buf,"hello world",11);
    return ret;
}
//实现write函数
static ssize_t hello_write(struct file *fp, const char __user *buf, size_t len, loff_t *pos)
{
    return 0;
}
//定义文件操作结构体对象
static struct file_operations fops={
        .owner=THIS_MODULE,
        .open =hello_open,
        .write=hello_write,
        .read =hello_read,
};

//入口函数
static int __init hello_init(void)
{

    printk("%s line %d init success n",__FUNCTION__,__LINE__ );
    major=register_chrdev(0,"hello_drv",&fops);
    class_for_hello=class_create(THIS_MODULE,"hello_class"); //创建在/sys/class目录下
    device_create(class_for_hello,NULL,MKDEV(major,0),NULL,"myhello");

    return 0;
}
//出口函数
static void __exit hello_exit(void)
{
    printk("%s line %d exit success n",__FUNCTION__,__LINE__ );
    //删除节点
    device_destroy(class_for_hello,MKDEV(major,0));
    //删除类对象
    class_destroy(class_for_hello);
    //注销设备号和驱动程序
    unregister_chrdev(major,"hello_drv");
    return ;
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jacky");


测试应用程序
#include 
#include 
#include 
#include 
#include 

#define file "/dev/myhello"
static char buffer[20]={0};
int main(int argc ,char **argv){

    int fd=open(file,O_RDWR);
    if(fd<0){
        perror("[open error]");
        return -1;
    }
    printf("fd : %dn",fd);
    int ret=write(fd,"good",4);
    if(ret<0){
        perror("[write error]");
        return -1;
    }
    printf("write : %dn",ret);

    ret=read(fd,buffer,sizeof(buffer)-1);
    if(ret<0){
        perror("[read error]");
        return -1;
    }
    printf("read : %sn",buffer);
    return 0;
}

Makefile
ARCH := x86
CROSS_COMPILE :=
KERNEL_VERSION :=$(shell uname -r)
KERNEL_DIR :=/lib/modules/$(KERNEL_VERSION)/build
SOURCE := app_test.c

all:
	make -C $(KERNEL_DIR) M=`pwd` modules
	$(CROSS_COMPILE)gcc -o test $(SOURCE)
.PHONY:clean
clean:
	make -C $(KERNEL_DIR) M=`pwd` modules clean
	rm -rf modules.order build

obj-m +=hello_drv.o
测试

挂载驱动
查看 /proc/devices

查看/sys/class 目录


查看hello_class 目录内容

查看是否创建设备节点文件
执行测试程序

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/925512.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号