Kernel panics : trying to write / read on tiny tty driver - linux-kernel

I'm a beginner to the Linux programming and trying my hands on some device driver examples while practising.
The below code (a trimmed down version of tiny_tty.c) loads perfectly using insmod and I'm able to see it in /proc/tty/drivers , /proc/modules and device nodes are getting created under /dev. When I try to write to device file like echo "abcd" > /dev/ttyms0 (I hope this is fine) or read like cat /dev/ttyms0, the kernel panics with a call trace on the screen. I'm on kernel 3.5.0 under Ubuntu. Unfortunately I'm not able to capture the trace , as when it panics I'm left with no option but reboot using power button. I believe some issue with timer is here, as the trace shows a line on top saying :
"*kernel bug at /build/buildd/linux-3.5.0/kernel/timer.c:901*", then the call trace , followed by
"*EIP is at add_timer+0x18/0x20*"
Below is the full code. Any guidance is very much appreciated in anticipation.
10May2013 : I tried initializing the timer in open function and this time below is the call trace for "kernel panic - not syncing : fatal exception in interrupt panic occurred, switching back to text console":
update_sd_lb_stats+0xcd/0x4b0
find_busiest_group+0x2e/0x420
enqueue_entity+0xcb/0x510
load_balance+0x7e/0x5e0
rebalance_domains+0xed/0x150
__do_softirq+0xdb/0x180
local_bh_enable_ip+0x90/0x90
<IRQ>
copy_to_user0x41/0x60
sys_gettimeofday+0x2a/0x70
sysenter_do_call0x12/0x20
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/tty_driver.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mutex.h>
#include <linux/serial.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/termios.h>
MODULE_LICENSE("GPL");
#define MS_TTY_MAJOR 250 //test value
#define MS_TTY_NUM_DEV 2
#define DELAY_TIME HZ * 2 /* 2 seconds per character */
#define TINY_DATA_CHARACTER 't'
static int major_num;
//static int minor_num=0;
//static int num_tty_dev=2;
/* Below structure is a wrapper for device specific fields */
struct ms_tty_serial {
struct tty_struct *tty; /* pointer to the tty for this device */
int open_count; /* number of times this port has been opened */
struct semaphore sem; /* locks this structure */
struct timer_list *timer;
};
static struct ms_tty_serial *ms_tty_table[MS_TTY_NUM_DEV]; /* initially all NULL */
static void ms_tty_timer(unsigned long timer_data)
{
struct ms_tty_serial *ms_ptr = (struct ms_tty_serial *)timer_data;
struct tty_struct *tty;
char data[1] = {TINY_DATA_CHARACTER};
int data_size = 1;
if (!ms_ptr)
return;
tty = ms_ptr->tty;
tty->low_latency=1;
/* send the data to the tty layer for users to read. This doesn't
* actually push the data through unless tty->low_latency is set */
tty_buffer_request_room (tty, data_size);
tty_insert_flip_string(tty, data, data_size);
tty_flip_buffer_push(tty);
/* resubmit the timer again */
ms_ptr->timer->expires = jiffies + DELAY_TIME;
add_timer(ms_ptr->timer);
}
//// Define the open function ////
static int tty_ms_open(struct tty_struct *tty_this, struct file *file_this)
{
printk(KERN_ALERT "tty_ms driver: OPENED ...\n");
struct ms_tty_serial *ms_ptr;
struct timer_list *timer;
int index;
/* initialize the pointer in case something fails */
tty_this->driver_data = NULL;
/* get the serial object associated with this tty pointer */
index = tty_this->index;
ms_ptr = ms_tty_table[index];
if (ms_ptr == NULL) {
/* first time accessing this device, create it */
ms_ptr = kmalloc(sizeof(*ms_ptr), GFP_KERNEL);
if (!ms_ptr)
return -ENOMEM;
// init_MUTEX(&ms_ptr->sem); /* didn't work for this kernel version 3.5.0 */
#ifndef init_MUTEX /* sema_init is to be used for kernel 2.6.37 and above */
sema_init(&ms_ptr->sem,1);
#else
init_MUTEX(&ms_ptr->sem);
#endif
ms_ptr->open_count = 0;
ms_ptr->timer = NULL;
ms_tty_table[index] = ms_ptr;
}
down(&ms_ptr->sem);
/* save our structure within the tty structure */
tty_this->driver_data = ms_ptr;
ms_ptr->tty = tty_this;
ms_ptr->filp = file_this; // to be tried
++ms_ptr->open_count;
if (ms_ptr->open_count == 1) {
/* this is the first time this port is opened */
/* do any hardware initialization needed here */
/* create timer and submit it */
if (!ms_ptr->timer) {
timer = kmalloc(sizeof(*timer), GFP_KERNEL);
if (!timer) {
up(&ms_ptr->sem);
return -ENOMEM;
}
ms_ptr->timer = timer;
}
init_timer (ms_ptr->timer); // to be tried
ms_ptr->timer->data = (unsigned long )ms_ptr;
ms_ptr->timer->expires = jiffies + DELAY_TIME;
ms_ptr->timer->function = ms_tty_timer;
add_timer(ms_ptr->timer);
}
up(&ms_ptr->sem);
return 0;
}
//// Define the close function ////
static void do_close(struct ms_tty_serial *ms_ptr)
{
down(&ms_ptr->sem);
if (!ms_ptr->open_count) {
/* port was never opened */
goto exit;
}
--ms_ptr->open_count;
if (ms_ptr->open_count <= 0) {
/* The port is being closed by the last user. */
/* Do any hardware specific stuff here */
/* shut down our timer */
del_timer(ms_ptr->timer);
}
exit:
up(&ms_ptr->sem);
}
static void tty_ms_close(struct tty_struct *tty_this, struct file *file_this)
{
printk(KERN_ALERT "tty_ms driver: CLOSING ...\n");
struct ms_tty_serial *ms_ptr = tty_this->driver_data;
if (ms_ptr)
do_close(ms_ptr);
}
//// Define the write function ////
static int tty_ms_write(struct tty_struct *tty_this, const unsigned char *tty_buff, int count)
{
printk(KERN_ALERT "tty_ms driver: WRITING ...\n");
struct ms_tty_serial *ms_ptr = tty_this->driver_data;
int i;
int retval = -EINVAL;
if (!ms_ptr)
return -ENODEV;
down(&ms_ptr->sem);
if (!ms_ptr->open_count)
/* port was not opened */
{
up(&ms_ptr->sem);
return retval;
}
/* fake sending the data out a hardware port by
* writing it to the kernel debug log.
*/
printk(KERN_DEBUG "%s - ", __FUNCTION__);
for (i = 0; i < count; ++i)
printk("%02x ", tty_buff[i]);
printk("\n");
return 0;
}
// Define the operations for tty driver in tty_operations struct //
static struct tty_operations tty_ms_ops = {
.open = tty_ms_open,
.close = tty_ms_close,
.write = tty_ms_write,
//.set_termios = tty_ms_set_termios,
};
///////////////////////////////////////// Module Initialization Starts ////////////////////////////////////
static struct tty_driver *tty_ms_driver;
static int tty_ms_init(void)
{
// static int result;
static int retval,iter;
// Allocate the tty_driver struct for this driver //
tty_ms_driver = alloc_tty_driver(MS_TTY_NUM_DEV);
if (!tty_ms_driver)
return -ENOMEM; // Error NO Memory , allocation failed
else
printk(KERN_INFO "tty_driver structure allocated..!!"); //debug line
// Initialize the allocated tty_driver structure //
tty_ms_driver->magic=TTY_DRIVER_MAGIC;
tty_ms_driver->owner = THIS_MODULE;
tty_ms_driver->driver_name = "tty_ms";
tty_ms_driver->name = "ttyms";
tty_ms_driver->major = MS_TTY_MAJOR,
tty_ms_driver->type = TTY_DRIVER_TYPE_SERIAL,
tty_ms_driver->subtype = SERIAL_TYPE_NORMAL,
tty_ms_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV,
tty_ms_driver->init_termios = tty_std_termios;
tty_ms_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(tty_ms_driver, &tty_ms_ops);
printk(KERN_INFO "allocated tty_driver structure -INITIALIZED."); //debug line
//// Register this driver with the tty core ////
retval = tty_register_driver(tty_ms_driver);
if (retval) {
printk(KERN_ERR "failed to register tty_ms driver\n tty registration returned %d", retval);
put_tty_driver(tty_ms_driver);
return retval;
}
//// Register the tty devices(nodes) with the tty core ////
for (iter = 0; iter < MS_TTY_NUM_DEV ; ++iter)
tty_register_device(tty_ms_driver, iter, NULL);
return 0; // All initializations done
} // init func ends
///////////////////////////////////////// Module Initialization Ends ////////////////////////////////////
///////////////////////////////////////// Module cleanup Starts ////////////////////////////////////
static void tty_ms_terminate(void)
{
static int iter;
struct ms_tty_serial *tty_ser;
printk(KERN_ALERT "tty_ms driver: Unloading...\n");
for(iter=1;iter<=MS_TTY_NUM_DEV;iter++)
tty_unregister_device(tty_ms_driver,iter); //unregister all the devices, from tty layer
tty_unregister_driver(tty_ms_driver); // Now unregister the driver from tty layer
/* shut down all of the timers and free the memory */
for (iter = 0; iter < MS_TTY_NUM_DEV; ++iter) {
tty_ser = ms_tty_table[iter];
if (tty_ser) {
/* close the port */
while (tty_ser->open_count)
do_close(tty_ser);
/* shut down our timer and free the memory */
del_timer(tty_ser->timer);
kfree(tty_ser->timer);
kfree(tty_ser);
ms_tty_table[iter] = NULL;
}
}
dev_t devno=MKDEV(major_num,0); // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
unregister_chrdev_region(devno,MS_TTY_NUM_DEV);
}
///////////////////////////////////////// Module cleanup ends ////////////////////////////////////
module_init(tty_ms_init);
module_exit(tty_ms_terminate);

Related

kprobe modules cannot work after execute "echo 0 > /proc/sys/kernel/ftrace_enabled "

Just do some research of ftrace.
TCP echo program is running between two host.
When I shutdown the big switch(echo 0 > /proc/sys/kernel/ftrace_enabled ), my own kprobe module cannot work also. The printk message cannot be seen in the kernel log file. Also, The pkt modify operation failed and the pkt can be received successfully.
It really confused me a lot.
My test kprobe module is here:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/skbuff.h>
#include <linux/inet.h>
/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {
.symbol_name = "ip_rcv",
};
/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
struct sk_buff * skb = (struct sk_buff *)(regs->di);
u16 dst_port;
dst_port = ntohs(*((u16*)(skb->head + skb->transport_header + 2)));
if(dst_port == 50000){ //50000 is the TCP port
printk(KERN_INFO "post handler addr 0x%p skb is 0x%d\n",p->addr, regs->di);
// modify one byte to make TCP checksum wrong and drop the pkt.
*((u8*)(skb->head + skb->network_header +7))=0xab;
}
return 0;
}
/* kprobe post_handler: called after the probed instruction is executed */
static void handler_post(struct kprobe *p, struct pt_regs *regs,
unsigned long flags)
{
//printk(KERN_INFO "post handler addr 0x%p skb is 0x%d\n",p->addr, regs->di);
}
/*
* fault_handler: this is called if an exception is generated for any
* instruction within the pre- or post-handler, or when Kprobes
* single-steps the probed instruction.
*/
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",
p->addr, trapnr);
/* Return 0 because we don't handle the fault. */
return 0;
}
static int __init kprobe_init(void)
{
int ret;
kp.pre_handler = handler_pre;
kp.post_handler = handler_post;
kp.fault_handler = handler_fault;
ret = register_kprobe(&kp);
if (ret < 0) {
printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
return ret;
}
printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);
return 0;
}
static void __exit kprobe_exit(void)
{
unregister_kprobe(&kp);
printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
}
module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");
Question Closed.
Actually in sys/kernel/debug/kprobes/list we can get the list of registered kprobe. And I get this xxxxxxxxxxx k ip_rcv+0x0 [FTRACE], it means that the this kprobe is ftrace-based. ftrace-based kprobe cannot work if disable the ftrace.

Shared Memory between Kernel and User

I am currently working on a kernel module for a RaspberryPi 3 and am new to this area. This should generate an interrupt on a rising or falling edge. In the corresponding ISR, a time stamp is set and a signal is generated to notify a user application.
I have taken the signaling for the sake of the code.
My goal is now to write the value of the time stamp into a shared memory and the user application can read it out after an incoming signal in order to measure the latency between the interrupt and the signal received in the user application. I have already researched but found no solution. How do I map the virtual kernel address of the allocated memory into the user application and what steps are necessary?
Thanks in advance.
Kernel Code:
/****************************************************************************/
/* Kernelmodul Shared Memory */
/****************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
// kmalloc
#include <linux/slab.h>
// ioremap
#include <asm/io.h>
/****************************************************************************/
/* Define block */
/****************************************************************************/
#define DriverAuthor ""
#define DriverDescription "Shared Memory"
#define InterruptPin 26
#define GPIO_PIN_DEV_STR "PIN"
#define GPIO_PIN_STR "Timestamp"
unsigned int * timerAddr;
unsigned int time = 0;
unsigned int * SHMvirtual = 0;
/****************************************************************************/
/* Module params declaration block */
/****************************************************************************/
static short int gpio_pin = InterruptPin;
/****************************************************************************/
/* Interrupts variables block */
/****************************************************************************/
short int irq_gpio_pin = InterruptPin;
short int irq_enabled = 0; // this is only a flag
/****************************************************************************/
/* IRQ handler */
/****************************************************************************/
static irqreturn_t ISR(int irq, void *dev_id, struct pt_regs *regs) {
unsigned long flags;
// disable hard interrupts (remember them in flag 'flags')
local_irq_save(flags);
time = timerAddr[1];
*SHMvirtual = time;
// restore hard interrupts
local_irq_restore(flags);
return IRQ_HANDLED;
}
/****************************************************************************/
/* This function configures interrupts. */
/****************************************************************************/
void configInterrupts(void) {
if (gpio_request(gpio_pin, GPIO_PIN_STR))
{
printk(KERN_INFO "GPIO request faiure %d\n", gpio_pin);
return;
}
if ( (irq_gpio_pin = gpio_to_irq(gpio_pin)) < 0 )
{
printk(KERN_INFO "GPIO to IRQ mapping faiure %d\n", gpio_pin);
return;
}
printk(KERN_INFO "Mapped int %d\n", irq_gpio_pin);
if (request_irq(irq_gpio_pin, (irq_handler_t ) ISR, (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING), GPIO_PIN_STR,
GPIO_PIN_DEV_STR))
{
printk("Interrupt Request failure\n");
return;
}
return;
}
/****************************************************************************/
/* This function releases interrupts. */
/****************************************************************************/
void releaseInterrupt(void) {
free_irq(irq_gpio_pin, GPIO_PIN_DEV_STR);
gpio_free(gpio_pin);
return;
}
/****************************************************************************/
/* Module init / cleanup block. */
/****************************************************************************/
int initModule(void) {
printk(KERN_INFO "Hello\n");
configInterrupts();
timerAddr = ioremap(0x3F003000, 0x20);
SHMvirtual = (unsigned int *)kmalloc(sizeof(time),GFP_USER);
return 0;
}
void cleanupModule(void) {
printk(KERN_INFO "Goodbye\n");
releaseInterrupt();
kfree(SHMvirtual);
return;
}
module_init(initModule);
module_exit(cleanupModule);
/****************************************************************************/
/* Module licensing/description block. */
/****************************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DriverAuthor);
MODULE_DESCRIPTION(DriverDescription);

User space netlink socket receives empty messages from kernel space

Disclaimer - I have to admit that it's the 1'st time I'm using this kernel interface (socket).
I'm currently working on a design of a kernel module that is based on a netlink socket .
I'm using Ubuntu14.04 and linux kernel 4.
As a starter, I wanted to make sure that I can use the netlink socket in both directions.
I've written an application that does the following:
1) User send a message to kernel via the netlink socket.
2) Kernel, upon receiving the message – sends "ABCD" string message to a workqueue.
3) When the "ABCD" message is received by the workqueue, it calls a function (named - my_wq_function) which send it back to the user space via netlink socket.
4) In the user space I'm using a recvmsg function (blocking until a message is received) and displays the "ABCD" message.
My problem is that the return value from the recvmsg function is 20 (instead of 4), and the data itself (i.e. NLMSG_DATA) is empty.
During the debug I tried to change the message to "ABCD1234" and got a return value of 24 bytes, however the data is still empty.
I also verified that my entire path until the point of sending the "ABCD" from kernel to the socket is OK.
Not sure what I'm doing wrong here & will highly appreciate your help.
Thanks in advance, MotiC.
my code example can be found below:
User space code:
printf("netlink receiver thread started...\n");
nlh_rcv = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
while(true) //endless loop on netlink socket
{
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_base = (void *)nlh_rcv;
iov_rcv.iov_len = nlh_rcv->nlmsg_len;
msg_rcv.msg_name = (void *)&dest_addr;
msg_rcv.msg_namelen = sizeof(dest_addr);
msg_rcv.msg_iov = &iov;
msg_rcv.msg_iovlen = 1;
ret=recvmsg(sock_fd, &msg_rcv, 0);
printf("errno=%i bytes=%i message from kernel: %s\n",errno, ret, (char*)NLMSG_DATA(nlh_rcv));
uint8_t mymsg[100];
memcpy(mymsg, NLMSG_DATA(nlh_rcv), 100);
printf("message from kernel: %s\n",mymsg);
}
Kernel space code:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
#include "rf_Kdriver_main.h"
//------ definitions ------------------------------------------------------------------------------------------------------------
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sock *nl_sk = NULL;
struct nlmsghdr *nlh;
struct nlmsghdr *nlh_out;
struct sk_buff *skb_out;
char buf_to_user[100];
int pid;
//------------------------------------------------------------------------------------------------------------------------------
struct workqueue_struct *my_wq;
typedef struct {
struct work_struct my_work;
uint8_t msg_to_pc[128];
uint8_t msg_len;
} my_work_t;
my_work_t *work, *work2;
//-----------------------------------------------------------------------------------------------------------------------------
static void my_wq_function( struct work_struct *work)
{
int res;
my_work_t *my_work = (my_work_t *)work;
skb_out = nlmsg_new(my_work->msg_len,0);
if (!skb_out)
{
printk("Failed to allocate new skb\n");
return;
}
nlh_out = nlmsg_put(skb_out, 0, 0, NLMSG_DONE,my_work->msg_len, 0);
NETLINK_CB(skb_out).dst_group = 0;
memcpy((char*)NLMSG_DATA(nlh_out), my_work->msg_to_pc , my_work->msg_len);
printk( "dequeue message to pc=%s len=%i\n", (char*)NLMSG_DATA(nlh_out), (int)strlen((char*)NLMSG_DATA(nlh_out)));
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res<0)
printk("Failed to send message from kernel to user\n");
kfree( (void *)work );
return;
}
//-----------------------------------------------------------------------------------------------------------------------------
int send_up_msg_to_workque(uint8_t msg_to_pc[], uint8_t msg_len)
{
int ret=0;
work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);
if (work) {
INIT_WORK( (struct work_struct *)work, my_wq_function );
memcpy(work->msg_to_pc, msg_to_pc, msg_len);
work->msg_len = msg_len;
ret = queue_work( my_wq, /*(struct work_struct *)RR*/work );
printk("kuku ret=%i msg=%s\n",ret,work->msg_to_pc);
}
return ret;
}
//------------------------------------------------------------------------------------------------------------------------------
static void netlink_recv_msg(struct sk_buff *skb)
{
char *msg = "ABCD1234";
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
nlh=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink at kernel received msg payload: %s\n",(char*)NLMSG_DATA(nlh));
//rr
pid = nlh->nlmsg_pid;
send_up_msg_to_workque((uint8_t*) msg, strlen(msg));
}
//-------------------------------------------------------------------------------------------------------------------------------------
struct netlink_kernel_cfg cfg = {
.input = netlink_recv_msg,
};
static int __init rf_driver_start(void)
{
printk(KERN_INFO "Loading RF Driver module1...\n");
my_wq = create_workqueue("my_queue");
if (!my_wq)
{
printk("Failed to create work queue\n");
}
printk("Entering: %s\n",__FUNCTION__);
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
if(!nl_sk)
{
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
return 0;
}
//--------------------------------------------------------------------------------------------------------------
static void __exit rf_driver_end(void)
{
netlink_kernel_release(nl_sk);
flush_workqueue(my_wq);
destroy_workqueue(my_wq);
printk(KERN_INFO "RF Driver exit...\n");
}
module_init(rf_driver_start);
module_exit(rf_driver_end);
Update,
I changed my user space function to:
char buf[100];
ret=recv(sock_fd, buf, 100, 0);
instead of:
ret=recvmsg(sock_fd, &msg_rcv, 0);
and it works...
does anyone have an idea regarding this strange behavior ?
Thanks.
Can you please paste complete userspace code.
I guess 'len' int this code is the issue:
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_len = nlh_rcv->nlmsg_len; << check to what value is it getting initialized.

What is the modern version of `procfs1.c` for Linux 2.6.x kernels?

I have been following the Linux 2.6 Kernel Module Programming Guide, when I ran into the first example from Chapter 5, called procfs1.c.
It would not compile out of the box, and after checking various related questions, it still took me quite some time to figure out the correct changes to make it compile and work as intended.
Therefore, I am posting my updated code for people in the future. I am running kernel 2.6.32-279.el6.x86_64.
Here is an updated version of the example that works with kernel version 2.6.32-279.el6.x86_64.
/*
* procfs1.c - create a "file" in /proc
*
*/
#include <linux/module.h> /* Specifically, a module */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
#define procfs_name "helloworld"
/**
* This structure hold information about the /proc file
*
*/
struct proc_dir_entry *Our_Proc_File;
static ssize_t procfile_read(struct file *filp,
char *buffer,
size_t length,
loff_t * offset)
{
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name);
if (*offset > 0) {
/* we have finished to read, return 0 */
ret = 0;
} else {
/* fill the buffer, return the buffer size */
ret = sprintf(buffer, "HelloWorld!\n");
*offset = ret;
}
return ret;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = procfile_read,
};
int init_module()
{
Our_Proc_File = proc_create(procfs_name, S_IFREG | S_IRUGO, NULL, &fops);
if (Our_Proc_File == NULL) {
remove_proc_entry(procfs_name, NULL);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
procfs_name);
return -ENOMEM;
}
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk(KERN_INFO "/proc/%s created\n", procfs_name);
return 0; /* everything is ok */
}
void cleanup_module()
{
remove_proc_entry(procfs_name, NULL);
printk(KERN_INFO "/proc/%s removed\n", procfs_name);
}

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 dont correctly?
The following is the readout from terminal:
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
The following is the code from apps layer:
read(fd, read_buf, sizeof(read_buf));
for(i=0;i<=(BUFF_SIZE / sizeof(int));i+=5)
printf(" 0x%x 0x%x 0x%x 0x%x 0x%x \n",
read_buf[i],read_buf[i+1],read_buf[i+2],
read_buf[i+3],read_buf[i+4]);
break;
and the following is my driver code:
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#ifdef MODVERSIONS
# include <linux/modversions.h>
#endif
#include <asm/io.h>
#include <asm/uaccess.h> // required for copy_from and copy_to user
/* character device structures */
static dev_t mmap_dev;
static struct cdev mmap_cdev;
/* 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;
#define NPAGES 1//16
#define BUFF_SIZE 64 // bytes
/* character device open method */
static int mmap_open(struct inode *inode, struct file *filp)
{
return 0;
}
/* character device last close method */
static int mmap_release(struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t read(struct file *filp, int *buff, size_t count, loff_t *offp)
{
unsigned long bytes_left;
printk("Inside read \n");
bytes_left = copy_to_user(buff, vmalloc_area , count);
if(bytes_left<0)
bytes_left = -EFAULT;
return bytes_left;
}
/* 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;
out_unalloc_region:
unregister_chrdev_region(mmap_dev, 1);
out_vfree:
if(vmalloc_area)
vfree(vmalloc_area);
return ret;
}
/* module unload */
static void __exit mmap_exit(void)
{
if(vmalloc_area)
vfree(vmalloc_area);
/* remove the character deivce */
cdev_del(&mmap_cdev);
unregister_chrdev_region(mmap_dev, 1);
printk(KERN_ERR "#mmap_exit\n");
}
module_init(membuff_init);
module_exit(mmap_exit);
MODULE_DESCRIPTION("trying out copy_to_user");
MODULE_LICENSE("Dual BSD/GPL");

Resources