linux mmap

mmap驱动

#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/gfp.h>
#include <linux/uaccess.h>

#define PAGE_FAULT

#define PAGE_ORDER  0  //data_buff size: 4KB
#define MAX_SIZE    (1UL << 12)

static struct page *page = NULL;
static char *hello_buf = NULL;

static struct class *hello_class;
static struct device *hello_device;
static struct cdev *hello_cdev;
static dev_t devno;

unsigned int pid;
module_param(pid, uint, 0644);

static int hello_open(struct inode *inode, struct file *file)
{
#ifndef PAGE_FAULT
    page = alloc_pages(GFP_KERNEL, PAGE_ORDER);
    if (!page) {
        printk("alloc_pages fail!\n");
        return -ENOMEM;
    }
    hello_buf = (char *)page_to_virt(page);
    printk("data_buf phys_addr 0x%lx  virt_addr 0x%lx\n",
            page_to_phys(page), (unsigned long)hello_buf);
#endif
    return 0;
}

static int hello_release(struct inode *inode, struct file *file)
{
    __free_pages(page, PAGE_ORDER);

    return 0;
}

static ssize_t hello_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    int len, ret;
    char *token = NULL, *cur = hello_buf;

    len = PAGE_SIZE - *ppos;
    if (count > len)
        count = len;

    ret = copy_to_user(buf, hello_buf + *ppos, count);
    if (ret)
        return -EFAULT;
    printk("read hello_buf %s\n", hello_buf);

    token = strsep(&cur, " ");
    while (token != NULL) {
        printk("read %s\n", token);
        token = strsep(&cur, " ");
    }

    *ppos += count;

    return count;
}

static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    int len, ret;
    char *token = NULL, *cur = hello_buf;
    struct task_struct *task = NULL;

    len = PAGE_SIZE - *ppos;
    if (count > len)
        count = len;

    printk("hello write\n");
    //simple_write_to_buffer()
    ret = copy_from_user(hello_buf + *ppos, buf, count);
    if (ret)
        return -EFAULT;
    
    printk("write hello_buf %s\n", hello_buf);

    token = strsep(&cur, " ");
    while (token != NULL) {
        printk("write %s\n", token);

        ret = kstrtouint(token, 10, &pid);

        task = find_task_by_vpid(pid);
        printk("pid %d task_name %s\n", (int)pid, task->comm);

        token = strsep(&cur, " ");
    }

    printk("current task name %s\n", current->comm);
    //printk("current_thread_info  task name %s\n", current_thread_info()->task->comm);
    printk("current_thread_info  preempt_count %lx\n", current_thread_info()->preempt_count);
    printk("current_thread_info  count %ld\n", current_thread_info()->preempt.count);
    printk("current_thread_info  need_resched %ld\n", current_thread_info()->preempt.need_resched);
    *ppos += count;

    return count;
}


#ifdef PAGE_FAULT

struct vm_area_struct *vma;

vm_fault_t hello_fault(struct vm_fault *vmf)
{
    printk("hello fault\n");
    page = alloc_pages(GFP_KERNEL, PAGE_ORDER);
    if (!page) {
        printk("alloc pages fail\n");
        return -ENOMEM;
    }

    hello_buf = (char *)page_to_virt(page);
    
    printk("data_buf phys_addr 0x%lx  virt_addr 0x%lx\n",
            page_to_phys(page), (unsigned long)hello_buf);

    vmf->page = page;
    get_page(vmf->page);

    return 0;
}

struct vm_operations_struct hello_vm_ops = {
    .fault  = hello_fault,
};

static int hello_mmap(struct file *file, struct vm_area_struct *vmap)
{
    vmap->vm_ops = &hello_vm_ops;
    vma = vmap;

    return 0;
}
#else
static int hello_mmap(struct file *file, struct vm_area_struct *vma)
{
    struct mm_struct *mm;
    unsigned long size;
    unsigned long pfn;
    int ret;

    mm = current->mm;
    pfn = page_to_pfn(page);

    size = vma->vm_end - vma->vm_start;
    if (size > MAX_SIZE) {
        printk("map size too large, max size is 0x%x\n", MAX_SIZE);
        return -EINVAL;
    }

    ret = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
    if (ret) {
        printk("remap_pfn_range fail\n");
        return -EAGAIN;
    }

    return ret;
}

#endif

static loff_t hello_llseek(struct file *file, loff_t offset, int whence)
{
    loff_t pos;
    switch(whence) {
        case SEEK_SET:
            pos = offset;
            break;
        case SEEK_CUR:
            pos = file->f_pos + offset;
            break;
        case SEEK_END:
            pos = MAX_SIZE + offset;
            break;
        default:
            return -EINVAL;
    }

    if (pos < 0 || pos > MAX_SIZE)
        return -EINVAL;
    
    file->f_pos = pos;

    return pos;
}

static const struct file_operations hello_chrdev_fops = {
    .owner  = THIS_MODULE,
    .open   = hello_open,
    .release= hello_release,
    .read   = hello_read,
    .write  = hello_write,
    .mmap   = hello_mmap,
    .llseek = hello_llseek
};

static int __init hello_init(void)
{
    int ret;

    ret = alloc_chrdev_region(&devno, 0, 1, "hello");   /* /proc/devices/hello */ 
    if (ret) {
        printk("alloc_chrdev_region fail\n");
        return ret;
    }

    hello_cdev = cdev_alloc();
    cdev_init(hello_cdev, &hello_chrdev_fops);

    ret = cdev_add(hello_cdev, devno, 1);
    if (ret) {
        printk("cdev_add fail\n");
        return ret;
    }

    hello_class = class_create(THIS_MODULE, "hello-class"); /* /sys/class/hello-clss */ 
    if (IS_ERR(hello_class)) {
        printk("create class fail\n");
        return -1;
    } 

    hello_device = device_create(hello_class, NULL, devno, NULL, "hello_dev");  /* /dev/hello_dev */ 
    if (IS_ERR(hello_device)) {
        printk("create class fail\n");
        return -1;
    } 

    return 0;
}

static void __exit hello_exit(void)
{
    cdev_del(hello_cdev);
    device_unregister(hello_device);
    class_destroy(hello_class);
    unregister_chrdev_region(devno, 1);
}

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

mmap_app

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

char write_buf[512];
char read_buf[512];

int main(void)
{
    int fd;
    char *mmap_adar;
    pid_t pid;

    fd = open("/dev/hello_dev", O_RDWR);
    if (fd < 0) {
        printf("open fail\n");
        return -1;
    }

    mmap_adar = (char *)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    memcpy(mmap_adar, "1234", strlen("1234"));  // page fault

    pid = getpid();
    printf("fd %d   pid %d\n", fd, pid);
    snprintf(write_buf, sizeof(write_buf), "%d", pid);

    printf("write_buf %s\n", write_buf);
    write(fd, write_buf, strlen(write_buf) + 1);
    lseek(fd, 0, SEEK_SET);
    read(fd, read_buf, 100);
    printf("read buffer %s\n", read_buf);

    printf("mmap read %s\n", mmap_adar);

    munmap(mmap_adar, 4096);
    pause();
    printf("end\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值