L4Linux LKM

Nourhan Mohamed nourhan.abdeltawab at gmail.com
Thu Feb 4 08:34:06 CET 2016


Hello Karim,

I got it solved. Thanks for helping out

Nourhan

On Wed, Feb 3, 2016 at 3:07 PM, Nourhan Mohamed <
nourhan.abdeltawab at gmail.com> wrote:

> 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/20160204/45564563/attachment.htm>


More information about the l4-hackers mailing list