【MMP多个地址】

MMP多个地址空间到用户态

在另外一个文章中,我们实现了将内核空间申请的一片内存映射到用户空间,今天我们将内核空间申请的多个地址空间映射到用户态里面,原理都是一样的。

内核源码路径:
arch/arm64/kernel/sys.c [sys_mmap]->[sys_mmap_pgoff]
mm/mmap.c [SYSCALL_DEFINE6(mmap_pgoff]

1、ko文件内容:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/semaphore.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/netdevice.h>
#include <linux/uio_driver.h>
#include <linux/syscalls.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/kern_levels.h>


#define BUF_SIZE  (1024)
#define MEM_BLOCK (5)

struct self_data {
    int len;
    int arry[BUF_SIZE];
};

struct dc_mem_ioctl_t {
    int block_num;
    struct self_data *p_phyaddr;
};

/* variable declare */
static struct proc_dir_entry *mmap_dir  = NULL;
static struct proc_dir_entry *mmap_file = NULL;
struct self_data *p_mem[MEM_BLOCK]      = {NULL};
struct self_data *p_memphy[MEM_BLOCK]   = {NULL};
int               alloc_size            = 0;

/* function declare */
static int mmap_open(struct inode *p_node, struct file *p_file);
static int mmap_mmap(struct file *p_file, struct vm_area_struct *vma);
static int mmap_release(struct inode *p_node, struct file *p_file);
static long mmap_ioctrl(struct file *fp, unsigned int cmd, unsigned long arg);

static const struct file_operations mmap_opts = {
    .owner          = THIS_MODULE,
    .open           = mmap_open,
    .mmap           = mmap_mmap,
    .compat_ioctl   = mmap_ioctrl,
    .unlocked_ioctl = mmap_ioctrl,
    .release        = mmap_release,
};


static long mmap_ioctrl(struct file *fp, unsigned int cmd, unsigned long arg)
{
    struct dc_mem_ioctl_t  ioctl_args;

    if(copy_from_user(&ioctl_args, (struct dc_mem_ioctl_t  *)arg, sizeof(struct dc_mem_ioctl_t)))
    {
        pr_err("copy from user failed\n");
        return -EFAULT;
    }

    ioctl_args.p_phyaddr = p_memphy[ioctl_args.block_num];

    if (copy_to_user((void *)arg, (void *)&ioctl_args, sizeof(struct dc_mem_ioctl_t))) 
    {
        pr_err("copy to user failed.\n");
        return -EFAULT;
    }

    return 0;
}


int mmap_release(struct inode *p_node, struct file *p_file)
{
    return 0; //释放内存
}

static int mmap_open(struct inode *p_node, struct file *p_file)
{
    return simple_open(p_node, p_file);
}

static int mmap_mmap(struct file *p_file, struct vm_area_struct *vma)
{
    unsigned long size = vma->vm_end - vma->vm_start;
    int ret;

    //pr_err("\n------call dump_stack------\n");
    //dump_stack();

    ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size, PAGE_SHARED);
    if (ret != 0) {
        pr_err("remap_pfn_range failed!\n");
    }

    return ret;
}

static int __init my_mmap_init(void)
{
    int i = 0;
    
    mmap_dir= proc_mkdir("module_mmap", NULL);
    if (mmap_dir == NULL) {
        pr_err("proc_mkdie failed!\n");
    }

   mmap_file =  proc_create("self_mmap", 0666, mmap_dir, &mmap_opts);
   if (mmap_file == NULL) {
       pr_err("proc_data failed!\n");
   }

    for (i = 0; i < MEM_BLOCK; i++) {
        
        alloc_size = PAGE_ALIGN(sizeof(struct self_data));
        p_mem[i]  = kzalloc(alloc_size, GFP_KERNEL);
    
        if (p_mem == NULL) {
            pr_err("kmalloc failed!\n");
            return -1;
        }
        p_memphy[i] = __pa(p_mem[i]);
        pr_emerg("the %d block memory phy_addr:0x%p, vir_addr = 0x%p\n", i, p_memphy[i], p_mem[i]);
    }

    return 0;
}

static void __exit my_mmap_exit(void)
{
    unsigned int  i;
    
    for (i = 0; i < MEM_BLOCK; i++) {

        if (p_mem[i]) {
            kfree(p_mem[i]);
        }
        if (mmap_dir) {
        
        }
    }
}

module_init(my_mmap_init);
module_exit(my_mmap_exit);

MODULE_LICENSE("GPL v2");

Makefile 编写

obj-m :=module_mmap.o

KERNELDIR ?=
ARCH ?=
MODULE_KO_INCLUDE ?=
PWD := $(shell ped)

CROSS_COMPILE ?=
CC = $(CROSS_COMPILE )gcc
LD = $(CROSS_COMPILE )ld

all:
    $(MAKE) ARCH=$(ARCH) -C $(KERNELDIR) M=${PWD} modules
make ARCH=arm64 CROSS_COMPILE=/opt/gcc-linaro-6.2.1-2016.11-x86_64_aarch64-linux-gun/bin/aarch64-linux-gun-  KERNELDIR=/out/build/kernel all

2、应用程序源码

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


struct self_data {
    int len;
    int arry[1024];
};

struct dc_mem_ioctl_t {
    int block_num;
    struct self_data *p_phyaddr;
};

struct dc_mem_ioctl_t mem_ctl;

char *p_file = NULL;
char buf[1024];

int main (void)
{
    int ch;
    int opt_indx;
    int fd = 0;
    int i;
    void *p_viraddr[5] = {NULL};
    ssize_t len;

    for (i = 0; i < 1024; i++) {
        buf[i] = 'r';   
    }

    fd =  open("/proc/module_mmap/self_mmap", O_RDWR);
    if (fd < 0) {
        printf("file open failed\n");
        return 0;
    }

    for (i = 0; i < 5; i++) {
    
        mem_ctl.block_num = i;
        if (ioctl(fd, 0, (void *)&mem_ctl) < 0) {
            printf ("ioctl error\n");
        }
        printf("the %d block mem phy_addr : 0x%p\n", i, mem_ctl.p_phyaddr);  //获取物理地址

        p_viraddr[i] = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mem_ctl.p_phyaddr);
    }
    
   close(fd);

   return 0;
}

应用程序编译

 /opt/gcc-linaro-6.2.1-2016.11-x86_64_aarch64-linux-gun/bin/aarch64-linux-gun-gcc -g mmap_main.c -o mmap_main

ko打印信息:
the 0 block memory phy_addr:0x000000207969c000, vir_addr = 0xffffffdff969c000
the 1 block memory phy_addr:0x000000207969e000, vir_addr = 0xffffffdff969e000
the 2 block memory phy_addr:0x00000000ead48000, vir_addr = 0xffffffc06ad48000
the 3 block memory phy_addr:0x00000000ead4a000, vir_addr = 0xffffffc06ad4a000
the 4 block memory phy_addr:0x00000000f95a6000, vir_addr = 0xffffffc0795a6000

应用程序打印:
the 0 block mem phy_addr : 0x207969c000
the 1 block mem phy_addr : 0x207969e000
the 2 block mem phy_addr : 0xead48000
the 3 block mem phy_addr : 0xead4a000
the 4 block mem phy_addr : 0xf95a6000

映射成功, 我们就可以在用户态操作内核态下面申请的地址块了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值