Linux kernel copy_to_user to user space display different result
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Linux kernel copy_to_user to user space display different result
There some bugs reading from the user space with this application. Is my copy_to_user method not correct?
The following is the readout from terminalwhich is wrong)
Press r to read from device or w to write the device r
0x-1075024108 0x15123440 0xe70401 0xe6f8dc 0xe73524
0x0 0x15037588 0xbfec6f14 0xe57612 0xbfec6f34
0x15037140 0x2 0xe57334 0xc6d690 0xd696910
0x-1075024080 0x15071734 0xc737c9 0x804835a 0x2
/* methods of the character device */
static int mmap_open(struct inode *inode, struct file *filp);
static int mmap_release(struct inode *inode, struct file *filp);
/* the file operations, i.e. all character device methods */
static struct file_operations mmap_fops = {
.open = mmap_open,
.release= mmap_release,
.owner = THIS_MODULE,
};
static int *vmalloc_area;
/* module initialization - called at module load time */
static int __init membuff_init(void)
{
int ret = 0, i =0;
printk(KERN_ERR "@membuff_init\n");
/* allocate a memory area with vmalloc. */
if ((vmalloc_area = vmalloc(BUFF_SIZE)) == NULL) {
ret = -ENOMEM;
goto out_vfree;
}
/* get the major number of the character device */
if( (ret = alloc_chrdev_region(&mmap_dev, 0, 1, "mmap")) < 0) {
printk(KERN_ERR "@membuff_init could not allocate major number for mmap\n");
goto out_vfree;
}
printk(KERN_ERR "@membuff_init Major number for mmap: %d\n",MAJOR(mmap_dev));
/* initialize the device structure and register the device with the kernel */
cdev_init(&mmap_cdev, &mmap_fops);
if ((ret = cdev_add(&mmap_cdev, mmap_dev, 1)) < 0) {
printk(KERN_ERR "@membuff_init could not allocate chrdev for mmap\n");
goto out_unalloc_region;
}
for (i = 0; i < (BUFF_SIZE / sizeof(int)); i +=1) {
vmalloc_area[i] = i;
printk(KERN_ERR "@membuff_init: %d\n",vmalloc_area[i]);
}
return ret;
It is very difficult to read your code; please, use [CODE]...[/CODE] tags around your code.
That said, your read() function always returns the start of your vmalloc_area buffer.
Try this instead:
Code:
ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
char *source = (char *)vmalloc_area;
size_t length = BUFF_SIZE;
/* Past end of data? */
if (*offp >= length)
return 0;
/* Calculate the desired data region. */
length -= (size_t)(*offp);
source += (size_t)(*offp);
/* Limit to the amount the user requested. */
if (count > length)
length = count;
/* Copy the desired part to userspace */
if (copy_to_user(buff, source, length))
return -EFAULT; /* invalid pointer */
/* Update the file pointer */
*offp += (loff_t)length;
/* Return the number of bytes read */
return (ssize_t)length;
}
The fact that you use an int pointer for vmalloc_area makes pointer calculations difficult (as adding 1 to the pointer moves it by one int). To avoid that, I use a temporary pointer.
You might also wish to implement the llseek method,
Code:
loff_t llseek(struct file *filp, loff_t off, int whence)
{
loff_t pos = filp->f_pos;
switch (whence) {
case 0: /* SEEK_SET */
pos = off;
break;
case 1: /* SEEK_CUR */
pos += off;
break;
case 2: /* SEEK_END */
pos = (loff_t)BUFF_SIZE + off;
break;
default: /* Invalid, should never happen */
return -EINVAL;
}
if (pos < (loff_t)0)
return -EINVAL;
filp->f_pos = pos;
return pos;
}
so that you can use lseek(), fseek(), ftell() and rewind() with the device too.
The above code is untested. I'm very interested to know if it solves your problem -- you didn't exactly tell us what your problem was, just that you have a problem.
1st seem like when I do read() for 100bytes at the kernel side it is read as len=1.
terminal dump:
[ 4280.825279] @membuff_init Major number for mmap: 250
[ 4288.045512] Inside read
[ 4288.045530] @membuff_init len: 1
[ 4288.045543] @membuff_init input_msg[0]: 0
also the output from buffer at application layer:
The data in the device is
no:0 0
no:1 75
no:2 113
no:3 -73
no:4 46
no:5 78
no:6 61
no:7 -10
no:8 0
....
Since buffer is a char pointer, sizeof (buffer) == sizeof (char *) which evaluates to 4 on 32-bit platforms, and to 8 on 64-bit platforms. This is not the cause of this problem, but please fix this or it will bite you later on.
Just use 100 as the size instead, or use size_t bufferlen = 100; buffer = (char *)malloc(bufferlen); to keep the actual size, also supplying bufferlen as the third parameter to the write() function.
"your read() function always returns the start of your vmalloc_area buffer."
On application code if I do following it will only return the input_msg[0] only?
Isnt that by telling the function sizeof(buffer) will indicate how much need to be call from the kernel memory? say like from location 0 -100th?
buffer = malloc(bufferlen); // I tried this too
read(fd, buffer, sizeof(buffer)); //then this one, so it is still the same 4 bytes only it is seeing char
buffer = (char *)malloc(bufferlen); ===(equal)==== buffer = malloc(bufferlen); // is this the same meaning?
from my current understanding "char *buffer;" actually indicates that the location memory refers are in 4 bytes.
Same goes (char *)malloc(bufferlen) also make the memory referencing to be in 4bytes.
size_t bufferlen;
char *buffer;
ssize_t bytes;
/* Decide you want 25 ints. */
bufferlen = 25 * sizeof(int);
/* Allocate buffer. */
buffer = malloc(bufferlen);
if (!buffer) {
/* Out of memory, abort */
}
/* Read buffer full of data. */
bytes = read(descriptor, buffer, bufferlen);
if (bytes > (ssize_t)0) {
/* Okay, got (bytes / sizeof(int)) ints in buffer,
* int k being ((int *)buffer)[k] */
}
Or, since you work on ints, perhaps
Code:
int int_count = 5; /* Do 5 ints. */
int *buffer;
int i, got_ints;
ssize_t n;
buffer = malloc(sizeof(int) * (size_t)int_count);
if (!buffer) {
fprintf(stderr, "Out of memory.\n");
exit(1);
}
n = read(descriptor, buffer, sizeof(int) * (size_t)int_count);
if (n > (ssize_t)0) {
got_ints = n / sizeof(int);
for (i = 0; i < got_ints; i++)
printf("Int %d = %d\n", i, buffer[i]);
}
As to the malloc() function, since it returns an untyped pointer (void *, also called void pointer), you do not need to cast the result. No matter what kind of a pointer buffer is (char * or int * or anything else), you can always do
Code:
buffer = malloc(number_of_bytes_to_allocate);
Since the count is in bytes, and sizeof(char)==1 , to allocate say 47 time_t values you need to do
Code:
buffer = malloc(47 * sizeof(time_t));
The malloc() does not care what kind of pointer you use to store the result to, it only looks at its own parameter (for the number of bytes/chars to allocate).
Hi everyone I am working on educational project on mini6410 device.I have to access ADC port and I have and driver source code as team3adc.c below ,but at the end of compile this source code node didn't opened under /dev .Please ,help me!!!! This is very urgent.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.