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
映射成功, 我们就可以在用户态操作内核态下面申请的地址块了。