- 论坛徽章:
- 0
|
kernel 2.6.32
1:kmalloc的内存想mmap到用户空间,书上说要先设置为保留,但是我看网上有的并没有先设置为保留,直接remap_pfn_range,而有的先设置为保留,到底需要先设置保留吗?
2: 不设置为保留内存的话,echo 到对应设备一串数据然后再通过应用层代码mmap,向其中写数据unmap,进程退出,再cat设备,发现数据并没有更新,这时为何?
3:所以我怀疑是要设置成保留,但是设置保留后SetPageReserved,加载该驱动时,老是被killed,求大侠指点?
/*======================================================================
A globalmem driver as an example of char device drivers
The initial developer of the original code is Baohua Song
<author@linuxdriver.cn>. All Rights Reserved.
======================================================================*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define GLOBALMEM_SIZE 0x1000 /*諾ÖÄú′æ×î′ó4K×Ö½ú*/
#define MEM_CLEAR 0x1 /*Çå0諾ÖÄú′æ*/
#define GLOBALMEM_MAJOR 0 /*Ô¤éèμÄglobalmemμÄÖ÷é豸oÅ*/
struct my_kobj {
int val;
struct kobject kobj;
};
struct attribute name_attr = {
.name = "name",
.mode = 0444,
};
struct attribute val_attr = {
.name = "val",
.mode = 0666,
};
struct attribute *my_attrs[] = {
&name_attr,
&val_attr,
NULL,/* ±ØDèéèÖÃÎaNULL */
};
ssize_t my_show(struct kobject *kobj, struct attribute *attr, char *buffer)
{
struct my_kobj *obj = container_of(kobj, struct my_kobj, kobj);
ssize_t count = 0;
if (strcmp(attr->name, "name") == 0) {
count = sprintf(buffer, "%s\n", kobject_name(kobj));
} else if (strcmp(attr->name, "val") == 0) {
count = sprintf(buffer, "%d\n", obj->val);
}
return count;
}
ssize_t my_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size)
{
struct my_kobj *obj = container_of(kobj, struct my_kobj, kobj);
if (strcmp(attr->name, "val") == 0) {
sscanf(buffer, "%d", &obj->val);
}
return size;
}
struct sysfs_ops my_sysfsops = {
.show = my_show,
.store = my_store,
};
static int globalmem_major = GLOBALMEM_MAJOR;
/*globalmemé豸½á11ìå*/
struct globalmem_dev
{
struct cdev cdev; /*cdev½á11ìå*/
unsigned char *mem; /*諾ÖÄú′æ*/
};
struct globalmem_dev *globalmem_devp; /*é豸½á11ìåÖ¸Õë*/
/*Îļt′ò¿aoˉêy*/
int globalmem_open(struct inode *inode, struct file *filp)
{
/*½«é豸½á11ìåÖ¸Õë¸3Öμ¸øÎļt˽óDêy¾YÖ¸Õë*/
filp->private_data = globalmem_devp;
return 0;
}
/*Îļtêí·Åoˉêy*/
int globalmem_release(struct inode *inode, struct file *filp)
{
return 0;
}
/* ioctlé豸¿ØÖÆoˉêy */
static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
int cmd, unsigned long arg)
{
struct globalmem_dev *dev = filp->private_data;/*»ñμÃé豸½á11ìåÖ¸Õë*/
switch (cmd)
{
case MEM_CLEAR:
memset(dev->mem, 0, GLOBALMEM_SIZE);
printk(KERN_INFO "globalmem is set to zero\n");
break;
default:
return - EINVAL;
}
return 0;
}
/*¶áoˉêy*/
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data; /*»ñμÃé豸½á11ìåÖ¸Õë*/
/*·ÖÎöoí»ñè¡óDD§μÄD′3¤¶è*/
if (p >= GLOBALMEM_SIZE)
return count ? - ENXIO: 0;
if (count > GLOBALMEM_SIZE - p)
count = GLOBALMEM_SIZE - p;
/*ÄúoË¿Õ¼ä->óû§¿Õ¼ä*/
if (copy_to_user(buf, (void*)(dev->mem + p), count))
{
ret = - EFAULT;
}
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
}
return ret;
}
/*D′oˉêy*/
static ssize_t globalmem_write(struct file *filp, const char __user *buf,
size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data; /*»ñμÃé豸½á11ìåÖ¸Õë*/
printk(KERN_ERR "filp->f_pos is %d \n", filp->f_pos );
/*·ÖÎöoí»ñè¡óDD§μÄD′3¤¶è*/
if (p >= GLOBALMEM_SIZE)
return count ? - ENXIO: 0;
if (count > GLOBALMEM_SIZE - p)
count = GLOBALMEM_SIZE - p;
/*óû§¿Õ¼ä->ÄúoË¿Õ¼ä*/
if (copy_from_user(dev->mem + p, buf, count))
ret = - EFAULT;
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
}
return ret;
}
/* seekÎļt¶¨Î»oˉêy */
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
loff_t ret = 0;
switch (orig)
{
case 0: /*Ïà¶ÔÎļt¿aê¼Î»ÖÃÆ«òÆ*/
if (offset < 0)
{
ret = - EINVAL;
break;
}
if ((unsigned int)offset > GLOBALMEM_SIZE)
{
ret = - EINVAL;
break;
}
filp->f_pos = (unsigned int)offset;
ret = filp->f_pos;
break;
case 1: /*Ïà¶ÔÎļtμ±Ç°Î»ÖÃÆ«òÆ*/
if ((filp->f_pos + offset) > GLOBALMEM_SIZE)
{
ret = - EINVAL;
break;
}
if ((filp->f_pos + offset) < 0)
{
ret = - EINVAL;
break;
}
filp->f_pos += offset;
ret = filp->f_pos;
break;
default:
ret = - EINVAL;
break;
}
return ret;
}
static int memdev_mmap(struct file*filp, struct vm_area_struct *vma)
{
struct globalmem_dev *dev = filp->private_data; /*»ñμÃé豸½á11ìåÖ¸Õë*/
vma->vm_flags |= VM_IO;
vma->vm_flags |= VM_RESERVED;
vma->vm_pgoff = ((u32)virt_to_phys(dev->mem)) >> PAGE_SHIFT;
if (remap_pfn_range(vma,vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
printk(KERN_NOTICE "mmap ok \n");
return 0;
}
/*Îļt2ù×÷½á11ìå*/
static const struct file_operations globalmem_fops =
{
.owner = THIS_MODULE,
.llseek = globalmem_llseek,
.read = globalmem_read,
.write = globalmem_write,
.ioctl = globalmem_ioctl,
.open = globalmem_open,
.release = globalmem_release,
.mmap = memdev_mmap,
};
struct my_kobj *obj1;
struct my_kobj *obj2;
struct kobj_type my_type;
int init_sysfile_by_helun()
{
obj1 = kzalloc(sizeof(struct my_kobj), GFP_KERNEL);
if (!obj1) {
return -ENOMEM;
}
obj1->val = 1;
obj2 = kzalloc(sizeof(struct my_kobj), GFP_KERNEL);
if (!obj2) {
kfree(obj1);
return -ENOMEM;
}
obj2->val = 2;
my_type.release = NULL;
my_type.default_attrs = my_attrs;
my_type.sysfs_ops = &my_sysfsops;
kobject_init_and_add(&obj1->kobj, &my_type, NULL, "mykobj-11");
kobject_init_and_add(&obj2->kobj, &my_type, &obj1->kobj, "mykobj-22");
return 0;
}
int exit_sysfile_by_helun()
{
kobject_del(&obj2->kobj);
kobject_put(&obj2->kobj);
kobject_del(&obj1->kobj);
kobject_put(&obj1->kobj);
return 0;
}
/*3õê¼»ˉ2¢×¢2ácdev*/
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
int err, devno = MKDEV(globalmem_major, index);
cdev_init(&dev->cdev, &globalmem_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &globalmem_fops;
err = cdev_add(&dev->cdev, devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}
/*é豸Çy¶ˉÄ£¿é¼óÔØoˉêy*/
int globalmem_init(void)
{
int result;
dev_t devno = MKDEV(globalmem_major, 0);
/* éêÇëé豸oÅ*/
if (globalmem_major)
result = register_chrdev_region(devno, 1, "globalmmap");
else /* ¶ˉì¬éêÇëé豸oÅ */
{
result = alloc_chrdev_region(&devno, 0, 1, "globalmmap");
globalmem_major = MAJOR(devno);
}
if (result < 0) {
printk(KERN_NOTICE "devo is busy \n");
return result;
}
/* ¶ˉì¬éêÇëé豸½á11ìåμÄÄú′æ*/
globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
if (!globalmem_devp) /*éêÇë꧰ü*/
{
printk(KERN_NOTICE "no mem \n");
result = - ENOMEM;
goto fail_malloc;
}
memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
globalmem_setup_cdev(globalmem_devp, 0);
globalmem_devp->mem = kmalloc(GLOBALMEM_SIZE, GFP_KERNEL);
if (globalmem_devp->mem == NULL) {
printk("globalmem_devp->mem is alloc null \n");
goto fail_malloc;
}
SetPageReserved(((u32)virt_to_phys(globalmem_devp->mem)) >> PAGE_SHIFT);
init_sysfile_by_helun();
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}
/*Ä£¿éD¶ÔØoˉêy*/
void globalmem_exit(void)
{
exit_sysfile_by_helun();
ClearPageReserved(((u32)virt_to_phys(globalmem_devp->mem)) >> PAGE_SHIFT);
cdev_del(&globalmem_devp->cdev); /*×¢Ïúcdev*/
kfree(globalmem_devp); /*êí·Åé豸½á11ìåÄú′æ*/
unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*êí·Åé豸oÅ*/
}
MODULE_AUTHOR("Song Baohua");
MODULE_LICENSE("Dual BSD/GPL");
module_param(globalmem_major, int, S_IRUGO);
module_init(globalmem_init);
module_exit(globalmem_exit);
|
|