If I use copy_to_user in ioctl function, i can copy the data to the user space, but if I put the copy_to_user into the timeout handler function, copy_to_user can not be successful. Why?
#include <linux/init.h>
...
#define GLOBAL_MEMSIZE 0x1000//4K
...
static struct timer_list mytimer;
...
typedef struct globalmem_dev{
struct cdev cdev;
unsigned char mem[GLOBAL_MEMSIZE];
} Glo_dev, *Pglo_dev;
Pglo_dev globalmem_devp;//global pointer
If I put copy_to_user in here, I can not copy the data to user correctly
/*Timeout handler function*/
static void timer_func(unsigned long data)
{
int retc = 0;
retc = copy_to_user((void __user *)data, globalmem_devp->mem, 8);
if(retc)
{
printk("timer_func------->copy_to_user fail\n");
}
mod_timer(&mytimer, jiffies + 2*HZ);
}
/*file open function*/
static int hello_open(struct inode *inode, struct file *file)
{
printk("hello open!\n");
file->private_data = globalmem_devp;
return 0;
}
/*file close function*/
static int hello_release(struct inode *inode, struct file *file)
{
del_timer_sync(&mytimer);
printk("hello closed\n");
return 0;
}
The copy_to_user work fine in the ioctl function
/*ioctl*/
static long int globalmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
/*if(copy_to_user((void __user *)arg, globlmem_devp->mem, 8))
{
printk("copy_to_user fial\n");
}*/
setup_timer(&mytimer, timer_func, arg);
mytimer.expires = jiffies + HZ;
add_timer(&mytimer);
return 0;
}
static struct file_operations hello_ops = {
...
};
/*init function*/
static int __init hello_init(void)
{
...
globalmem_devp = kmalloc(sizeof(Glo_dev), GFP_KERNEL);//
if(NULL == globalmem_devp)
{
return -ENOMEM;
}
...
return 0;
}
static void __exit hello_exit(void)
{
...
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("test");
module_init(hello_init);
module_exit(hello_exit);
copy_to_user() copies the data into the memory of the current user-space process, so it can be used only in some code that has been called from such a process.
An interrupt handler can run at any time, so there might be no current process, or worse, the current process is some other process.
Related
so I have this code
this is what I am doing in ioctl implementation
if( copy_from_user(&value ,(struct aa*) arg, sizeof(value)) )
{
pr_err("Data Write : Err!\n");
}
__u64 a=value.a;
__u32 *b=(__u32 *)a;
pr_info("wow Value = [%x]\n", (int)b[0]);
but I am passing from userspace float so but my passed values are not correctly printing in printk
this is my program
struct aa
{
uint64_t a;
};
#define WR_VALUE _IOW('a','a',struct aa*)
#define RD_VALUE _IOR('a','b',struct aa*)
int main()
{
struct aa a;
float *f=(float[]){2,2,3};
a.a=(uint64_t)f;
printf("sizeof = %zu\n",sizeof(*f));
int fd;
int32_t value, number;
printf("*********************************\n");
printf("*******WWW.EmbeTronicX.com*******\n");
printf("\nOpening Driver\n");
fd = open("/dev/etx_device", O_RDWR);
if(fd < 0) {
printf("Cannot open device file...\n");
return 0;
}
printf("Enter the Value to send\n");
scanf("%d",&number);
printf("Writing Value to Driver\n");
ioctl(fd, WR_VALUE, (struct aa *) &a);
printf("Reading Value from Driver\n");
ioctl(fd, RD_VALUE, (struct aa*) &a);
printf("Value is %d\n", value);
printf("Closing Driver\n");
close(fd);
}
full code
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include<linux/slab.h> //kmalloc()
#include<linux/uaccess.h> //copy_to/from_user()
#include <linux/ioctl.h>
#include <asm/fpu/api.h>
struct aa
{
__u64 a;
};
#define WR_VALUE _IOW('a','a',struct aa *)
#define RD_VALUE _IOR('a','b',struct aa *)
struct aa value;
dev_t dev = 0;
static struct class *dev_class;
static struct cdev etx_cdev;
/*
** Function Prototypes
*/
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
static int etx_open(struct inode *inode, struct file *file);
static int etx_release(struct inode *inode, struct file *file);
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len,loff_t * off);
static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t * off);
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/*
** File operation sturcture
*/
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = etx_open,
.unlocked_ioctl = etx_ioctl,
.release = etx_release,
};
/*
** This function will be called when we open the Device file
*/
static int etx_open(struct inode *inode, struct file *file)
{
return 0;
}
/*
** This function will be called when we close the Device file
*/
static int etx_release(struct inode *inode, struct file *file)
{
return 0;
}
static long etx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case WR_VALUE:
if( copy_from_user(&value ,(struct aa*) arg, sizeof(value)) )
{
pr_err("Data Write : Err!\n");
}
__u64 a=value.a;
__u32 *b=(__u32 *)a;
pr_info("wow Value = [%x]\n", (int)b[0]);
kernel_fpu_end();
break;
case RD_VALUE:
if( copy_to_user((struct aa*) arg, &value, sizeof(value)) )
{
pr_err("Data Read : Err!\n");
}
break;
default:
pr_info("Default\n");
break;
}
return 0;
}
/*
** Module Init function
*/
static int __init etx_driver_init(void)
{
/*Allocating Major number*/
if((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) <0){
pr_err("Cannot allocate major number\n");
return -1;
}
pr_info("Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&etx_cdev,&fops);
/*Adding character device to the system*/
if((cdev_add(&etx_cdev,dev,1)) < 0){
pr_err("Cannot add the device to the system\n");
goto r_class;
}
/*Creating struct class*/
if((dev_class = class_create(THIS_MODULE,"etx_class")) == NULL){
pr_err("Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if((device_create(dev_class,NULL,dev,NULL,"etx_device")) == NULL){
pr_err("Cannot create the Device 1\n");
goto r_device;
}
pr_info("Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev,1);
return -1;
}
/*
** Module exit function
*/
static void __exit etx_driver_exit(void)
{
device_destroy(dev_class,dev);
class_destroy(dev_class);
cdev_del(&etx_cdev);
unregister_chrdev_region(dev, 1);
pr_info("Device Driver Remove...Done!!!\n");
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeTronicX <embetronicx#gmail.com>");
MODULE_DESCRIPTION("Simple Linux device driver (IOCTL)");
MODULE_VERSION("1.5");
what am I doing wrong in kernel ioctl because I casted float to uint_64 like a.a=(uint64_t)f; and passed struct a to kernel now I want to read float *f elements passed from userspace through ioctl in ioctl implementation
I'm learning Linux and I have the task that I can't handle. I have to create character device and make possible to read and write across users. For instance, I open first terminal and I use echo 'test' > /tmp/ringdev (where ringdev is my character device). I also open second terminal and I use cat /tmp/ringdev and I expect that output will be test. I have already read some example snippets, but all of them are just about the basics which I already have.
The question is how to read from / write to character device across users?
#define pr_fmt(fmt) "ringdev: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
DECLARE_WAIT_QUEUE_HEAD(head);
/*
* mutex used for access synchronization to buffer (ringdev_buf and ringdev_len)
*/
static struct mutex ringdev_lock;
/*
* buffer and number of written bytes in the buffer
*/
static char ringdev_buf[4096];
static size_t ringdev_len;
static int ringdev_open(struct inode *inode, struct file *filp)
{
printk("device_open called \n");
return 0;
}
static ssize_t ringdev_read(struct file *filp, char __user *buf, size_t count,
loff_t *off)
{
ssize_t ret = 0;
printk("device_read called \n");
/*
* access to ringdev_buf i ringdev_len is protected by ringdev_lock,
* take that lock
*/
//wait_event_interruptible(head,ringdev_len!=0);
mutex_lock(&ringdev_lock);
if (*off > ringdev_len)
count = 0;
else if (count >= ringdev_len - *off)
count = ringdev_len - *off;
/*
* for access to user memory special functions must be used,
* to copy to user memory copy_to_user must be used.
*/
ret = -EFAULT;
if (copy_to_user(buf, ringdev_buf + *off, count))
goto out_unlock;
ret = count;
*off += ret;
out_unlock:
mutex_unlock(&ringdev_lock);
ringdev_len=0;
return ret;
}
static ssize_t ringdev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *off)
{
ssize_t ret=0;
ringdev_len=0;
printk("device_write called \n");
mutex_lock(&ringdev_lock);
ret=-EFAULT;
if(copy_from_user(ringdev_buf+ringdev_len ,buf, count)==0){
ringdev_len= ringdev_len + count;
ret=count;
wake_up_interruptible(&head);
goto out_unlock;
}
else{
ret=-ENOSPC;
}
/*
* not supported yet. Do not forget about copy_from_user().
*/
out_unlock:
mutex_unlock(&ringdev_lock);
return ret;
}
static int ringdev_release(struct inode *inode, struct file *filp)
{
mutex_unlock(&ringdev_lock);
printk("device_release called \n");
return 0;
}
static const struct file_operations ringdev_fops = {
.owner = THIS_MODULE,
.open = ringdev_open,
.read = ringdev_read,
.write = ringdev_write,
.release = ringdev_release,
};
static struct miscdevice ringdev_miscdevice = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ringdev",
.fops = &ringdev_fops
};
static int __init ringdev_init(void)
{
int ret;
mutex_init(&ringdev_lock);
ret = misc_register(&ringdev_miscdevice);
if (ret < 0) {
pr_err("can't register miscdevice.\n");
return ret;
}
pr_info("minor %d\n", ringdev_miscdevice.minor);
return 0;
}
static void __exit ringdev_exit(void)
{
misc_deregister(&ringdev_miscdevice);
mutex_destroy(&ringdev_lock);
}
module_init(ringdev_init);
module_exit(ringdev_exit);
MODULE_DESCRIPTION("Device");
MODULE_AUTHOR("xxx");
MODULE_LICENSE("GPL");
I wrote this linux char driver just to control open call,
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>
#include <linux/device.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
#define CLASS_NAME "myclass"
#define MINOR_NUM 0
#define MINOR_CNT 1
static struct class *myclass=NULL;
static struct device *mydevice=NULL;
static dev_t mycdevt;
static struct cdev *mycdev;
static struct semaphore *sem;
static int myopen(struct inode *inod, struct file *fp)
{
down(sem);
printk(KERN_INFO "critical section\n");
return 0;
}
static int myclose(struct inode *inod, struct file *fp )
{
up(sem);
printk(KERN_INFO "critical section freed\n");
return 0;
}
static ssize_t myread(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static ssize_t mywrite(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static struct file_operations fops =
{
.open = myopen,
.release = myclose,
.read = myread,
.write = mywrite,
};
static int __init myinit(void)
{
int ret;
ret = alloc_chrdev_region ( &mycdevt, MINOR_NUM, MINOR_CNT, "mycdevt");
if(ret<0)
{
printk(KERN_INFO "chardev can't be allocated\n");
// goto label;//todo
}
mycdev = cdev_alloc();//instead of cdev_alloc, we can use cdev_init(&mycdev, &fops);
if(mycdev == NULL)
{
printk(KERN_INFO"cdev_alloc failed\n");
// goto label;//todo
}
mycdev->ops = &fops;
ret = cdev_add(mycdev, mycdevt, 1);
if(ret < 0)
{
printk(KERN_INFO"cdev_add failed\n");
// goto label;//todo
}
myclass = class_create(THIS_MODULE, CLASS_NAME);
if(myclass == NULL)
{
printk(KERN_INFO"class create failed\n");
// goto label;//todo
}
mydevice = device_create(myclass, NULL, mycdevt, NULL, "mydevice");
if(mydevice == NULL)
{
printk(KERN_INFO"device create failed\n");
// goto label;//todo
}
sema_init(sem, 1);//here is the problem
printk(KERN_INFO"myinit done\n");
return 0;
}
static void __exit myexit(void)
{
device_destroy(myclass, mycdevt);
class_unregister(myclass);
class_destroy(myclass);
cdev_del(mycdev);
unregister_chrdev(MAJOR(mycdevt), "mycdevt");
printk(KERN_INFO "exited\n");
}
module_init(myinit);
module_exit(myexit);
I am following ldd3 book, and tried to use simple APIs to use semahore for an app.
What happened is my kernel crashed when it called sema_init function. I read that semaphore is used in mutex mode
http://www.makelinux.net/ldd3/chp-5-sect-3
I also read that semaphore is not a mutex as there is no ownership. I have yet to explore that 'ownership' thing, but for now I am not able to make a simple semaphore.
What wrong I am doing here?
There's no actual semaphore.
This line:
static struct semaphore *sem;
creates a pointer to a semaphore, not a semaphore itself. It's almost certain initialized to NULL.
You probably want something like
static struct semaphore sem;
and therefore
sema_init( &sem, 1);
along with
up( &sem );
and
down( &sem );
Note that these calls are taking the address of an actual semaphore.
I wrote a simple char driver for my beaglebone kernel
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/fs.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("mrigendra.chaubey#gmail.com");
#define DEVICE_NAME "experm"
#define CLASS_NAME "exp"
static struct class* myclass = NULL; ///< The device-driver class struct pointer
static struct device* mychardevice = NULL; ///< The device-driver device struct pointer
static int myopen(struct inode *, struct file *);
static int release(struct inode *, struct file *);
static int myioctl(struct inode *, struct file *, unsigned int cmd, unsigned long arg);
static size_t myread(struct file *,char * , size_t, loff_t *);
static size_t mywrite(struct file *,char * , size_t, loff_t *);
static dev_t mydev;
static int myopen(struct inode *nd, struct file *fp)
{
printk(KERN_INFO "myopen\n");
return 0;
}
static int myrelease(struct inode *nd, struct file *fp)
{
printk(KERN_INFO "myrelease\n");
return 0;
}
static int myioctl(struct inode *nd, struct file *fp, unsigned int cmd, unsigned long arg)
{
printk(KERN_INFO "myioctl\n");
return 0;
}
static size_t myread(struct file *fp, char *buf, size_t len, loff_t *ofs)
{
printk(KERN_INFO "myread\n");
return 0;
}
static size_t mywrite(struct file *fp, char *buf, size_t len, loff_t *ofs)
{
printk(KERN_INFO "mywrite\n");
return 0;
}
static struct file_operations fops = {
.open = myopen,
.release = myrelease,
.read = myread,
.write = mywrite,
.unlocked_ioctl = myioctl,
};
static int __init myinit(void)
{
int err;
//extern int alloc_chrdev_region(dev_t *, unsigned minor number, unsigned total, const char *);
err = alloc_chrdev_region(&mydev, 0, 1, "expermdev");
if(err<0)
{
printk(KERN_INFO "major and minor can't be created, err = %d\n", err);
return err;
}
//struct class * class_create ( struct module *owner, const char *name);
myclass = class_create(THIS_MODULE, CLASS_NAME);
if(IS_ERR(myclass))
{
unregister_chrdev(MAJOR(mydev), "expermdev");
printk(KERN_ALERT "Failed to register device class\n");
return PTR_ERR(myclass);
}
//struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
//This function can be used by char device classes. A struct device will be created in sysfs, registered to the specified class.
mychardevice = device_create(myclass, NULL, mydev, NULL, "expermdev");
if(IS_ERR(mychardevice))
{
class_destroy(myclass);
unregister_chrdev(MAJOR(mydev), "expermdev");
printk(KERN_ALERT "Failed to create the device\n");
return PTR_ERR(mychardevice);
}
printk(KERN_INFO "my device created correctly\n");
return 0;
}
static void __exit myexit(void)
{
device_destroy(mychardevice, mydev);
class_unregister(myclass);
class_destroy(myclass);
unregister_chrdev(MAJOR(mydev), "expermdev");
printk(KERN_INFO "exited\n");
}
module_init(myinit);
module_exit(myexit);
and app.c file
#include <stdio.h>
#include<fcntl.h>
int main()
{
int fp;
fp = open ("/dev/expermdev", O_RDWR);
if(fp < 0)
printf("file can't be opened\n");
else
printf("file opened\n");
return 0;
}
I am compiling the driver as a module and insmod it, also compiled app.c with the same cross compiler, and put this binary in bin directory. I ran this bin file, but it says
file can't be opened
What am I doing wrong?
Got it. I did not used cdev struture and added fops to it. After that I have to tell kernel about it.
cdev = cdev_alloc();//allocate memory to Char Device structure
cdev->ops = &fops;//link our file operations to the char device
result=cdev_add(cdev,mydev,1);//Notify the kernel abt the new device
also delete this cdev in exit function before unregistering the driver.
In register_chrdev_region we do both things at the same time, but in dynamic allocation of major and minor numbers we have to use cdev to do the rest.
I have shared memory segment created in kernel using mmap. I need to access this mapped memory from both kernel and user space. What mechanism should I use to protect the memory from concurrent access ?
I want to have something like:
Kernel module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/mm.h>
#ifndef VM_RESERVED
# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
#endif
struct dentry *file;
struct mmap_info
{
char *data;
int reference;
};
void mmap_open(struct vm_area_struct *vma)
{
struct mmap_info *info = (struct mmap_info *)vma->vm_private_data;
info->reference++;
}
void mmap_close(struct vm_area_struct *vma)
{
struct mmap_info *info = (struct mmap_info *)vma->vm_private_data;
info->reference--;
}
static int mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct page *page;
struct mmap_info *info;
info = (struct mmap_info *)vma->vm_private_data;
if (!info->data)
{
printk("No data\n");
return 0;
}
page = virt_to_page(info->data);
get_page(page);
vmf->page = page;
return 0;
}
struct vm_operations_struct mmap_vm_ops =
{
.open = mmap_open,
.close = mmap_close,
.fault = mmap_fault,
};
int op_mmap(struct file *filp, struct vm_area_struct *vma)
{
vma->vm_ops = &mmap_vm_ops;
vma->vm_flags |= VM_RESERVED;
vma->vm_private_data = filp->private_data;
mmap_open(vma);
return 0;
}
int mmapfop_close(struct inode *inode, struct file *filp)
{
struct mmap_info *info = filp->private_data;
free_page((unsigned long)info->data);
kfree(info);
filp->private_data = NULL;
return 0;
}
int mmapfop_open(struct inode *inode, struct file *filp)
{
struct mmap_info *info = kmalloc(sizeof(struct mmap_info), GFP_KERNEL);
info->data = (char *)get_zeroed_page(GFP_KERNEL);
memcpy(info->data, "hello from kernel this is file: ", 32);
memcpy(info->data + 32, filp->f_dentry->d_name.name, strlen(filp->f_dentry->d_name.name));
/* assign this info struct to the file */
filp->private_data = info;
return 0;
}
static const struct file_operations mmap_fops = {
.open = mmapfop_open,
.release = mmapfop_close,
.mmap = op_mmap,
};
static int __init mmapexample_module_init(void)
{
file = debugfs_create_file("mmap_example", 0644, NULL, NULL, &mmap_fops);
return 0;
}
static void __exit mmapexample_module_exit(void)
{
debugfs_remove(file);
}
module_init(mmapexample_module_init);
module_exit(mmapexample_module_exit);
MODULE_LICENSE("GPL");
User space:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#define PAGE_SIZE 4096
int main ( int argc, char **argv )
{
int configfd;
char * address = NULL;
configfd = open("/sys/kernel/debug/mmap_example", O_RDWR);
if(configfd < 0)
{
perror("Open call failed");
return -1;
}
address = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, configfd, 0);
if (address == MAP_FAILED)
{
perror("mmap operation failed");
return -1;
}
printf("Initial message: %s\n", address);
memcpy(address + 11 , "*user*", 6);
printf("Changed message: %s\n", address);
close(configfd);
return 0;
}
but with locks.
Kernel space and user space have no shared mechanisms for concurrent access protection. If you want them, you need to implement them by yourself.
It can be some sort of mutex, implemented within you kernel module, and accessed from user space via special ioctl requests:
Kernel:
DECLARE_WAIT_QUEUE_HEAD(wq);
int my_mutex_val = 0;
/*
* Lock mutex.
*
* May be used directly by the kernel or via 'ioctl(MY_CMD_LOCK)' by user.
*/
void my_mutex_lock(void)
{
spin_lock(&wq.lock);
wait_event_interruptible_locked(&wq, my_mutex_val == 0);
my_mutex_val = 1;
spin_unlock(&wq.lock);
}
/*
* Unlock mutex.
*
* May be used directly by the kernel or via 'ioctl(MY_CMD_UNLOCK)' by user.
*/
void my_mutex_unlock(void)
{
spin_lock(&wq.lock);
my_mutex_val = 0;
wake_up(&wq);
spin_unlock(&wq.lock);
}
long unlocked_ioctl (struct file * filp, unsigned int cmd, unsigned long val)
{
switch(cmd) {
case MY_CMD_LOCK:
my_mutex_lock();
break;
case MY_CMD_UNLOCK:
my_mutex_unlock();
break;
}
}
User:
int main()
{
...
ioctl(MY_CMD_LOCK);
<read data>
ioctl(MY_CMD_UNLOCK);
...
}
It can be some sort of spinlock, which value is stored in mmap-ed area (so visible both for kernel space and user space).
In any case, kernel module should be prepared for the case, when user space application doesn't follow locking conventions. This, probably, would cancel any expectation about mmap-ed area content, generated by the kernel, but kernel module shouldn't crash in that case. [This is why standard kernel's struct mutex is not used in the code above: user space may use it incorrectly].
The problem with the ioctl is you need a kernel switch every time you want to access the share info->data. If that is okay then the ioctl is good - but then why not just do a standard character read/write file operation instead?
You can also try a lock-less mechanism. In the shared info->data area add a barrier variable. When the user needs access, it will do an atomic_compare_and_xchg on the barrier variable until it is set to 0 (unused) and then set it to 1. When the kernel needs access it will do the same but set it to 2. See the gcc atomic builtin documentation.