[etherlab-dev] mmap process data to user-space
Thomas Bitsky Jr
tbj at automateddesign.com
Tue Jul 16 19:03:00 CEST 2013
Hello,
I have the master up and running and can connect from a kernel module. I'm trying to mmap a customer struct in the kernel-space to the user-space to exchange process data. I've been trying for days, but can't get it to work.
Everything seems to go fine in kernel-space and the user-space program can open the mmap'd file, but the data is absolute garbage. I must not be allocating the memory properly or something else fundamentally wrong. I've spent days reading on the Internet, but I always get the same result. Can someone tell me what I'm doing wrong?
Thanks in advance,
Tom
////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
// for kfree, kmalloc
#include <linux/slab.h>
// for mmap
#include <linux/mm.h>
#include "CtsSharedData.h"
#include "ProcessData.h"
#include "globals.h"
/////////////////////////////////////////////////////////////////
// Private variables
//////////////////////////////////////////////////////////////////
//
// Pointer to the file in debugfs RAM file system
static struct dentry* _ocFile;
//
// keep track of how often the item is mapped
//
void
mmap_open(struct vm_area_struct* vma)
{
CtsProcessData* info = (CtsProcessData*)vma->vm_private_data;
info->reference += 1;
}
//
// keep track of how often the item is mapped
//
void
mmap_close(struct vm_area_struct* vma)
{
CtsProcessData* info = (CtsProcessData*)vma->vm_private_data;
info->reference -= 1;
}
int
mmap_fault(struct vm_area_struct* vma, struct vm_fault *vmf)
{
unsigned long offset = vmf->pgoff << PAGE_SHIFT;
CtsProcessData* priv = (CtsProcessData*) vma->vm_private_data;
struct page *page;
page = virt_to_page(priv + offset);
if (!page)
return VM_FAULT_SIGBUS;
get_page(page);
vmf->page = page;
priv->reference = 98765;
PRINTF(CTSMSG_INFO "Vma fault, virtual_address = %p,"
" offset = %lu, page = %p\n", vmf->virtual_address, offset, page);
return 0;
}
static struct vm_operations_struct mmap_vm_ops =
{
.open = mmap_open,
.close = mmap_close,
.fault = mmap_fault,
};
//
// Initilize the vm_area_struct to point to the mmap functions specific to
// our implementation.
//
int
ocMapPdTable(struct file* filp, struct vm_area_struct* vma)
{
PRINTF(CTSMSG_INFO": BEGIN: ocMapPdTable \n");
//
// The operations table describes the specific methods
// that can operate on this particular instance of the object.
//
vma->vm_ops = &mmap_vm_ops;
vma->vm_flags |= VM_RESERVED;
vma->vm_private_data = filp->private_data;
mmap_open(vma);
PRINTF(CTSMSG_INFO": END: ocMapPdTable \n");
return 0;
}
//
// Frees the shared data table.
//
int
ocClosePdTable(struct inode* inode, struct file* filp)
{
CtsProcessData* info = filp->private_data;
PRINTF(CTSMSG_INFO": BEGIN: ocClosePdTable \n");
kfree(info);
filp->private_data = NULL;
PRINTF(CTSMSG_INFO": END: ocClosePdTable \n");
return 0;
}
//
// Allocate the shared memory
//
int
ocOpenPdTable(struct inode* inode, struct file* filp)
{
CtsProcessData* info;
// unsigned long virt_addr;
PRINTF(CTSMSG_INFO": BEGIN ocOpenPdTable\n");
//
// Create the process data in the kernel's memory
//
info = kmalloc(sizeof(CtsProcessData), GFP_KERNEL);
/* round it up to the page bondary */
// kmalloc_area = (int *)((((unsigned long)kmalloc_ptr) + PAGE_SIZE - 1) & PAGE_MASK);
//
// initialize the process data instance
//
memset(info, 0, sizeof(CtsProcessData));
info->rawData = (CtsRawData*)kmalloc(sizeof(CtsRawData) * 1000, GFP_KERNEL);
if (info->rawData == NULL)
{
PRINTF("Failed to allocate memory for raw data!");
}
else
{
memset(info->rawData, 0, (sizeof(CtsRawData) * 1000));
//
// FOR TESTING ONLY! Delete!
FPSET_16_16(info->rawData[0].load, 12, 0);
FPSET_16_16(info->rawData[0].position, 99, 0);
info->rawData[0].ticks = 54321;
}
filp->private_data = info;
PRINTF(CTSMSG_INFO": END ocOpenPdTable\n");
return 0;
}
static const struct file_operations oc_fops =
{
.open = ocOpenPdTable,
.release = ocClosePdTable,
.mmap = ocMapPdTable,
};
//////////////////////////////////////////////////
// PUBLIC INTERFACE FUNCTIONS
//////////////////////////////////////////////////
//
// Create the file in the debugfs RAM file system, which will trigger
// mapping the memory
//
int
ctsSharedTableCreate(void)
{
BOOL ret = FALSE;
PRINTF(CTSMSG_INFO": BEGIN ocSharedTableCreate\n");
_ocFile = debugfs_create_file(
CTSRT_DEBUGFS_SHAREDTABLE, // a pointer to a string containing the name of
// the file to create.
0644, // the permission that the file should have
NULL, // a pointer to the parent entry for this file.
// This should be a directory dentry if set.
// If this paramater is NULL, then the file will be created in the
// root of the debugfs filesystem.
NULL, // a pointer to something that the caller will want to get to later
// on. The inode.i_private pointer will point to this
// value on the open call.
&oc_fops); // a pointer to a struct file_operations that should be used
// for this file.
if (_ocFile == NULL)
{
//
// Most likely, the kernel module crashed on exit and the file already
// exists. We don't have any way of deletlying it. The computer will
// need to be restarted.
//
PRINTF(CTSMSG_INFO": ctsSharedTableCreate failed to create debugfs file!\n");
}
else if ((int)_ocFile == -ENODEV)
{
PRINTF(CTSMSG_INFO": ctsSharedTableCreate failed because of ENODEV!\n");
}
else
{
PRINTF(CTSMSG_INFO": ctsSharedTableCreate succeeded.\n");
ret = TRUE;
}
return ret;
}
//
// Close and delete the shared table and all associated memory.
//
void
ctsSharedTableClose(void)
{
debugfs_remove(_ocFile);
}
Thomas C. Bitsky Jr. | Lead Developer
ADC | automateddesign.com<http://automateddesign.com/>
P: 630-783-1150 F: 630-783-1159 M: 630-632-6679
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.etherlab.org/pipermail/etherlab-dev/attachments/20130716/97d75b6e/attachment-0001.htm>
More information about the etherlab-dev
mailing list