L4Linux LKM

Nourhan Mohamed nourhan.abdeltawab at gmail.com
Wed Feb 3 15:07:49 CET 2016


Hello Karim,

Here is the kernel dmesg and source code of the driver and a test .c file:

DMESG:

/ # chmod 777 testn ebbchar1.ko

/ # insmod ebbchar1.ko

EBBChar: Initializing the EBBChar LKM

EBBChar: registered correctly with major number 254

EBBChar: device class registered correctly

EBBChar: device class created correctly

/ #

/ # cd dev

/dev # mknod ebbchar c 254 0

/dev # chmod 777 ebbchar

/dev # cd ../

/ # ./testn

Starting device test code example...

EBBChar: Device has been opened 1 time(s)

Type in a short string to send to the kernel module:

test

Writing message to the device [test].

Non-resolvable page fault at bfaedc21, ip 21e8c54.

Page fault (non-resolved): pfa=bfaedc21 pc=21e8c54

Non-resolvable page fault at bfaedc21, ip 21e8c54.

 .... (too many exact lines here)

Page fault (non-resolved): pfa=bfaedc21 pc=21e8c54

Non-resolvable page fault at 3, ip 200b9d8.

Page fault (non-resolved): pfa=3 pc=200b9d8

^[[5~^[[5~^[[5~^[[6~^[[6~^[[6~^[[6~INFO: task testn:85 blocked for more
than 120 seconds.

     Tainted: G           O    4.3.0-l4 #4

"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.

testn           D 023492a0     0    85     72 0x00000000

[<023492a0>] (__schedule) from [<023496f4>] (schedule+0x34/0x98)

[<023496f4>] (schedule) from [<0234ca70>]
(rwsem_down_read_failed+0xec/0x128)

[<0234ca70>] (rwsem_down_read_failed) from [<02013914>]
(do_page_fault+0x134/0x288)

[<02013914>] (do_page_fault) from [<0200b844>]
(l4x_vcpu_entry_kern+0x240/0xdb4)

[<0200b844>] (l4x_vcpu_entry_kern) from [<0200da60>]
(l4x_vcpu_entry_c+0x16a8/0x2668)

[<0200da60>] (l4x_vcpu_entry_c) from [<020138c0>] (do_page_fault+0xe0/0x288)

[<020138c0>] (do_page_fault) from [<00000000>] (  (null))


TEST.C:



/**

* @file   testebbchar.c

* @author Derek Molloy

* @date   7 April 2015

* @version 0.1

* @brief  A Linux user space program that communicates with the ebbchar.c
LKM. It passes a

* string to the LKM and reads the response from the LKM. For this example
to work the device

* must be called /dev/ebbchar.

* @see http://www.derekmolloy.ie/ for a full description and follow-up
descriptions.

*/

#include<stdio.h>

#include<stdlib.h>

#include<errno.h>

#include<fcntl.h>

#include<string.h>

#define BUFFER_LENGTH 256               ///< The buffer length (crude but
fine)

static char receive[BUFFER_LENGTH];     ///< The receive buffer from the LKM

int main(){

  int ret, fd;

  char stringToSend[BUFFER_LENGTH];

  printf("Starting device test code example...\n");

  fd = open("/dev/ebbchar", O_RDWR);             // Open the device with
read/write access

  if (fd < 0){

     perror("Failed to open the device...");

     return errno;

  }

  printf("Type in a short string to send to the kernel module:\n");

  scanf("%[^\n]%*c", stringToSend);                // Read in a string
(with spaces)

  printf("Writing message to the device [%s].\n", stringToSend);

  ret = write(fd, stringToSend, strlen(stringToSend)); // Send the string
to the LKM

  if (ret < 0){

     perror("Failed to write the message to the device.");

     return errno;

  }

  printf("Press ENTER to read back from the device...\n");

  getchar();

  printf("Reading from the device...\n");

  ret = read(fd, receive, BUFFER_LENGTH);        // Read the response from
the LKM

  if (ret < 0){

     perror("Failed to read the message from the device.");

     return errno;

  }

  printf("The received message is: [%s]\n", receive);

  printf("End of the program\n");

  return 0;

}


MODULE: EBBCHAR.C:


/**

* @file   ebbchar.c

* @author Derek Molloy

* @date   7 April 2015

* @version 0.1

* @brief   An introductory character driver to support the second article
of my series on

* Linux loadable kernel module (LKM) development. This module maps to
/dev/ebbchar and

* comes with a helper C program that can be run in Linux user space to
communicate with

* this the LKM.

* @see http://www.derekmolloy.ie/ for a full description and follow-up
descriptions.

*/

#include <linux/init.h>           // Macros used to mark up functions e.g.
__init __exit

#include <linux/module.h>         // Core header for loading LKMs into the
kernel

#include <linux/device.h>         // Header to support the kernel Driver
Model

#include <linux/kernel.h>         // Contains types, macros, functions for
the kernel

#include <linux/fs.h>             // Header for the Linux file system
support

#include <asm/uaccess.h>          // Required for the copy to user function

#define  DEVICE_NAME "ebbchar"    ///< The device will appear at
/dev/ebbchar using this value

#define  CLASS_NAME  "ebb"        ///< The device class -- this is a
character device driver

MODULE_LICENSE("GPL");            ///< The license type -- this affects
available functionality

MODULE_AUTHOR("Derek Molloy");    ///< The author -- visible when you use
modinfo

MODULE_DESCRIPTION("A simple Linux char driver for the BBB");  ///< The
description -- see modinfo

MODULE_VERSION("0.1");            ///< A version number to inform users

static int    majorNumber;                  ///< Stores the device number
-- determined automatically

static char   message[256] = {0};           ///< Memory for the string that
is passed from userspace

static short  size_of_message;              ///< Used to remember the size
of the string stored

static int    numberOpens = 0;              ///< Counts the number of times
the device is opened

static struct class*  ebbcharClass  = NULL; ///< The device-driver class
struct pointer

static struct device* ebbcharDevice = NULL; ///< The device-driver device
struct pointer

// The prototype functions for the character driver -- must come before the
struct definition

static int     dev_open(struct inode *, struct file *);

static int     dev_release(struct inode *, struct file *);

static ssize_t dev_read(struct file *, char *, size_t, loff_t *);

static ssize_t dev_write(struct file *, const char *, size_t, loff_t *);

/** @brief Devices are represented as file structure in the kernel. The
file_operations structure from

*  /linux/fs.h lists the callback functions that you wish to associated
with your file operations

*  using a C99 syntax structure. char devices usually implement open, read,
write and release calls

*/

static struct file_operations fops =

{

  .open = dev_open,

  .read = dev_read,

  .write = dev_write,

  .release = dev_release,

  .owner = THIS_MODULE,

};

/** @brief The LKM initialization function

*  The static keyword restricts the visibility of the function to within
this C file. The __init

*  macro means that for a built-in driver (not a LKM) the function is only
used at initialization

*  time and that it can be discarded and its memory freed up after that
point.

*  @return returns 0 if successful

*/

static int __init ebbchar_init(void){

  printk(KERN_INFO "EBBChar: Initializing the EBBChar LKM\n");

  // Try to dynamically allocate a major number for the device -- more
difficult but worth it

  majorNumber = register_chrdev(0, DEVICE_NAME, &fops);

  if (majorNumber<0){

     printk(KERN_ALERT "EBBChar failed to register a major number\n");

     return majorNumber;

  }

  printk(KERN_INFO "EBBChar: registered correctly with major number %d\n",
majorNumber);

  // Register the device class

  ebbcharClass = class_create(THIS_MODULE, CLASS_NAME);

  if (IS_ERR(ebbcharClass)){                // Check for error and clean up
if there is

     unregister_chrdev(majorNumber, DEVICE_NAME);

     printk(KERN_ALERT "Failed to register device class\n");

     return PTR_ERR(ebbcharClass);          // Correct way to return an
error on a pointer

  }

  printk(KERN_INFO "EBBChar: device class registered correctly\n");

  // Register the device driver

  ebbcharDevice = device_create(ebbcharClass, NULL, MKDEV(majorNumber, 0),
NULL, DEVICE_NAME);

  if (IS_ERR(ebbcharDevice)){               // Clean up if there is an error

     class_destroy(ebbcharClass);           // Repeated code but the
alternative is goto statements

     unregister_chrdev(majorNumber, DEVICE_NAME);

     printk(KERN_ALERT "Failed to create the device\n");

     return PTR_ERR(ebbcharDevice);

  }

  printk(KERN_INFO "EBBChar: device class created correctly\n"); // Made
it! device was initialized

  return 0;

}

/** @brief The LKM cleanup function

*  Similar to the initialization function, it is static. The __exit macro
notifies that if this

*  code is used for a built-in driver (not a LKM) that this function is not
required.

*/

static void __exit ebbchar_exit(void){

  device_destroy(ebbcharClass, MKDEV(majorNumber, 0));     // remove the
device

  class_unregister(ebbcharClass);                          // unregister
the device class

  class_destroy(ebbcharClass);                             // remove the
device class

  unregister_chrdev(majorNumber, DEVICE_NAME);             // unregister
the major number

  printk(KERN_INFO "EBBChar: Goodbye from the LKM!\n");

}

/** @brief The device open function that is called each time the device is
opened

*  This will only increment the numberOpens counter in this case.

*  @param inodep A pointer to an inode object (defined in linux/fs.h)

*  @param filep A pointer to a file object (defined in linux/fs.h)

*/

static int dev_open(struct inode *inodep, struct file *filep){

  numberOpens++;

  printk(KERN_INFO "EBBChar: Device has been opened %d time(s)\n",
numberOpens);

  return 0;

}

/** @brief This function is called whenever device is being read from user
space i.e. data is

*  being sent from the device to the user. In this case is uses the
copy_to_user() function to

*  send the buffer string to the user and captures any errors.

*  @param filep A pointer to a file object (defined in linux/fs.h)

*  @param buffer The pointer to the buffer to which this function writes
the data

*  @param len The length of the b

*  @param offset The offset if required

*/

static ssize_t dev_read(struct file *filep, char *buffer, size_t len,
loff_t *offset){

  int error_count = 0;

  // copy_to_user has the format ( * to, *from, size) and returns 0 on
success

  error_count = copy_to_user(buffer, message, size_of_message);

  if (error_count==0){            // if true then have success

     printk(KERN_INFO "EBBChar: Sent %d characters to the user\n",
size_of_message);

     return (size_of_message=0);  // clear the position to the start and
return 0

  }

  else {

     printk(KERN_INFO "EBBChar: Failed to send %d characters to the
user\n", error_count);

     return -EFAULT;              // Failed -- return a bad address message
(i.e. -14)

  }

}

/** @brief This function is called whenever the device is being written to
from user space i.e.

*  data is sent to the device from the user. The data is copied to the
message[] array in this

*  LKM using the sprintf() function along with the length of the string.

*  @param filep A pointer to a file object

*  @param buffer The buffer to that contains the string to write to the
device

*  @param len The length of the array of data that is being passed in the
const char buffer

*  @param offset The offset if required

*/

static ssize_t dev_write(struct file *filep, const char *buffer, size_t
len, loff_t *offset){

  sprintf(message, "%s(%d letters)", buffer, len);   // appending received
string with its length

  size_of_message = strlen(message);                 // store the length of
the stored message

  printk(KERN_INFO "EBBChar: Received %d characters from the user\n", len);

  return len;

}

/** @brief The device release function that is called whenever the device
is closed/released by

*  the userspace program

*  @param inodep A pointer to an inode object (defined in linux/fs.h)

*  @param filep A pointer to a file object (defined in linux/fs.h)

*/

static int dev_release(struct inode *inodep, struct file *filep){

  printk(KERN_INFO "EBBChar: Device successfully closed\n");

  return 0;

}

/** @brief A module must use the module_init() module_exit() macros from
linux/init.h, which

*  identify the initialization function at insertion time and the cleanup
function (as

*  listed above)

*/

module_init(ebbchar_init);
module_exit(ebbchar_exit);

Thanks,
Nourhan

On Wed, Feb 3, 2016 at 2:57 PM, karim.allah.ahmed at gmail.com <
karim.allah.ahmed at gmail.com> wrote:

> Hello Nourhan,
>
> You have to post kernel dmesg + the character device source code.
>
> Regards.
>
> On Wed, Feb 3, 2016 at 2:24 PM, Nourhan Mohamed
> <nourhan.abdeltawab at gmail.com> wrote:
> > Hi Karim,
> >
> > Worked really fine Thank you!
> >
> > I can use "open" to open the device. However I get a page fault whenever
> I
> > attempt to write to the device. The device works properly on my ubuntu
> > machine so I can't guess what can be the problem. Would really help if
> you
> > have any suggestions.
> >
> > Thank you again
> > BR,
> > Nourhan
> >
> > On Wed, Feb 3, 2016 at 12:00 PM, karim.allah.ahmed at gmail.com
> > <karim.allah.ahmed at gmail.com> wrote:
> >>
> >> Hello Nourhan,
> >>
> >> On Wed, Feb 3, 2016 at 11:47 AM, Nourhan Mohamed
> >> <nourhan.abdeltawab at gmail.com> wrote:
> >> > Dear all,
> >> >
> >> > I wanted to create a simple character device on L4Linux. I managed to
> >> > cross-compile the module and run it on L4Linux on Versatile Express
> >> > Realview
> >> > Cortex-A15 ARM machine using the following command:
> >> >
> >> > make -C ~/l4re/obj/l4linux/arm-mp/ M=$PWD
> >> > CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- L4ARCH=arm CONFIG_TCG_TPM=m
> >> > modules V=1
> >> >
> >> > When I try to insert the module using the insmod command I get the
> >> > following
> >> > printed out from the module:
> >> > chardev: registered correctly with major number 254
> >> > chardev: device class registered correctly
> >> > chardev: device class created correctly
> >> >
> >> > With no failures in initializing the device printed at all. Also lsmod
> >> > displays the device in the module list with status live.
> >> >
> >> > However, the device doesn't appear in the /dev/ directory and hence I
> >> > can
> >> > not access it using the file operations. Any ideas where is the device
> >> > located or how can it be accessed on L4Linux?
> >>
> >> In linux systems, device nodes are not necessarily automatically
> >> generated under /dev/.
> >>
> >> Use 'mknod' command-line to create a device node in user space that's
> >> connected to this character device.
> >>
> >> Regards.
> >>
> >> >
> >> >
> >> > _______________________________________________
> >> > l4-hackers mailing list
> >> > l4-hackers at os.inf.tu-dresden.de
> >> > http://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
> >> >
> >>
> >>
> >>
> >> --
> >> Karim Allah Ahmed.
> >
> >
>
>
>
> --
> Karim Allah Ahmed.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://os.inf.tu-dresden.de/pipermail/l4-hackers/attachments/20160203/d53e2024/attachment.htm>


More information about the l4-hackers mailing list