Re: L4Linux LKM
Nourhan Mohamed <[email protected]>
| Newsgroups | gmane.comp.micro-kernel.l4.devel |
|---|---|
| Message-ID | <CAAOhFMYe9fjF8NF5cUHKMavi=71o0Uv-tAJQ4v1N+H7Y29Bmmg@mail.gmail.com> |
Hello Karim, I got it solved. Thanks for helping out Nourhan On Wed, Feb 3, 2016 at 3:07 PM, Nourhan Mohamed < [email protected]> 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, [email protected] < > [email protected]> 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 >> <[email protected]> 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, [email protected] >> > <[email protected]> wrote: >> >> >> >> Hello Nourhan, >> >> >> >> On Wed, Feb 3, 2016 at 11:47 AM, Nourhan Mohamed >> >> <[email protected]> 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 >> >> > [email protected] >> >> > http://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers >> >> > >> >> >> >> >> >> >> >> -- >> >> Karim Allah Ahmed. >> > >> > >> >> >> >> -- >> Karim Allah Ahmed. >> > > _______________________________________________ l4-hackers mailing list [email protected] http://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers