/ # 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);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@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@gmail.com
> <karim.allah.ahmed@gmail.com> wrote:
>>
>> Hello Nourhan,
>>
>> On Wed, Feb 3, 2016 at 11:47 AM, Nourhan Mohamed
>> <nourhan.abdeltawab@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@os.inf.tu-dresden.de
>> > http://os.inf.tu-dresden.de/mailman/listinfo/l4-hackers
>> >
>>
>>
>>
>> --
>> Karim Allah Ahmed.
>
>
Karim Allah Ahmed.