内核中ioctl和mmap使用

内核中ioctl和mmap使用


附上最基本的ioctl和mmap的操作。
ioctl用switch case 的格式实现, 切记不能用 if else. 其中命令的格式是有规定的,它是由32bit组成,包含dir, type, nr, size。
type和nr是幻数和分命令序号,本人认为这些数随便设置,主要用于避免重复宏定义。
dir是命令类型:读, 写, 读写, 不读不写。
size是要传入参数占多少字节。

mmap中共享的内存,要使用用kmalloc。

内核态 dipper_log.c

#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include "dipper_log.h"
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>

unsigned int major;
dev_t devno;
struct class *cls = {0};
char *shared_mem = NULL;

int log_write(char *content)
{

        return 0;
}

int dipper_open(struct inode *a, struct file *b)
{
        printk("hello\n");
        return 0;
}

long dipper_ioctl(struct file *fd, unsigned int cmd, unsigned long arg)
{
        unsigned long ret = 0;
        char shm_t[100] = {0};
        long arg_v = 666;
        printk("ioctl entry!!! \n");
        printk("the num arg is %lu", arg+1);

        switch(cmd)
        {
        case DIPPER_HELLO:
                //ret |= copy_from_user((void *)&arg_v, (void __user *)&arg, sizeof(long));

                printk("the num arg_v is %lu\n\r", arg_v);
                sprintf(shm_t, "helloworld:%lu\n", arg_v);
                ret |= copy_to_user((void *)arg, &arg_v, 8);
                break;
        }
        if (ret != 0)
        {
                printk("copy to user failed ! the ret num is %lu\n\r", ret);
        }
        else
        {
                printk("copy to user suceed ! %s:%lu\n\r", shm_t, arg_v);
        }
        return 0;
}

static int dipper_map(struct file *fd, struct vm_area_struct *vma)
{
        unsigned long page;
        page = virt_to_phys(shared_mem);
        remap_pfn_range(vma, (unsigned long)vma->vm_start, page>>PAGE_SHIFT, (unsigned long)(vma->vm_end - vma->vm_start), PAGE_SHARED);
        *shared_mem = 100;
        return 0;
}

struct file_operations dipper_log_fop=
{
        .open = dipper_open,
        .unlocked_ioctl = dipper_ioctl,
        .mmap = dipper_map,
};

static int log_init(void)
{
        int ret;
        int minor;
        shared_mem = (char *)kmalloc(4096, GFP_KERNEL);
        ret = register_chrdev(0, "dipper_log", &dipper_log_fop);
        if (ret < 0)
        {
                printk("register_chrdev failed!\n\r");
        }
        else
        {
                printk("register_chrdev succeed!the ret num is %d\n\r", ret);
        }
        major = ret;
        minor = 0;
        devno = MKDEV(major, minor);

        cls = class_create(THIS_MODULE, "logclass");
        device_create(cls, NULL, devno, NULL, "dipper_log");
        return 0;
}

static void log_exit(void)
{
        device_destroy(cls, devno);
        class_destroy(cls);
        unregister_chrdev(major, "dipper_log");
        return;
}




MODULE_LICENSE("GPL");
module_init(log_init);
module_exit(log_exit);

头文件 dipper_log.h

#define DIPPER_HELLO _IOWR('I', 1, long*)

用户态 user.c

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include "dipper_log.h"
#include <sys/mman.h>

int main()
{
        int ret = 0;
        int fd;
        long arg;
        char *shared_mem;
        fd = open("/dev/dipper_log",O_RDWR);
        printf("fd is %d", fd);
        ret = ioctl(fd, DIPPER_HELLO, &arg);
        printf("the errno is %d", errno);
        if(ret != 0)
        {
                printf("ioctl failed\n\rthe ret num is %d", ret);
        }
        else
        {
                printf("success!!\n\rthe num of arg is %lu\n\r", arg);
        }
        shared_mem = (char*)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        while(1)
        {
                sleep(1);
                printf("%s\n\r", shared_mem);
        }
        close(fd);
}

用户态user2

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include "dipper_log.h"
#include <sys/mman.h>

int main()
{
        int ret = 0;
        int fd;
        long arg;
        char *shared_mem;
        fd = open("/dev/dipper_log",O_RDWR);

        shared_mem = (char*)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        sprintf(shared_mem, "Write from user2, hello back !!!\n\r");
        close(fd);
}

Makefile

obj-m+=dipper_log.o


all:user user2
        make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules;

user:user.c
        gcc $< -o $@

user2:user2.c
        gcc $< -o $@

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean;
        

本代码实验用ioctl读取一个参数666。
在这里插入图片描述
同时两个进程,访问内核态内存,一个写入,一个监听。
在这里插入图片描述
所以mmap最好配和mutex进行操作,并封装一层函数,避免踩内存。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值