реализация символьного устройства для генерации случайных чисел

Основываясь на моем академическом проекте, моя текущая задача - сгенерировать 10 случайных чисел с использованием модуля ядра, и моя программа пользовательского пространства (программа c) должна иметь возможность отображать эти числа. Я изучал пространство ядра и программы пользовательского пространства. И я наткнулся на создание символьных устройств. Я создал устройство с помощью этой команды.

mknod /dev/my_device c 222 0

Насколько я понял, это устройство является посредником между пользовательским пространством и программами ядра. Итак, я создал модуль ядра, который регистрирует и отменяет регистрацию моего символьного устройства. Сохраненный как my_dev.c

#include<linux/module.h>
#include<linux/init.h>
#include"my_dev.h"

MODULE_AUTHOR("Krishna");
MODULE_DESCRIPTION("A simple char device");

static int r_init(void);
static void r_cleanup(void);

module_init(r_init);
module_exit(r_cleanup);


static int r_init(void)
{
printk("<1>hi\n");
if(register_chrdev(222,"my_device",&my_fops)){
    printk("<1>failed to register");
}
return 0;
}
static void r_cleanup(void)
{
printk("<1>bye\n");
unregister_chrdev(222,"my_device");
return ;
}

Мой файл Make для компиляции этого модуля

obj-m += my_dev.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Этот модуль ядра компилируется и загружается в память с помощью команды insmod.

Вот программа, которая записывает и читает некоторый текст в пользовательский буфер, сохраненный как my_dev.h.

/*
 * my device header file 
 */
#ifndef _MY_DEVICE_H
#define _MY_DEVICE_H

#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <asm/segment.h>
#include <asm/uaccess.h>

char my_data[80]="heloooo"; /* our device */

int my_open(struct inode *inode,struct file *filep);
int my_release(struct inode *inode,struct file *filep);
ssize_t my_read(struct file *filep,char *buff,size_t count,loff_t *offp );
ssize_t my_write(struct file *filep,const char *buff,size_t count,loff_t *offp );

struct file_operations my_fops={
    open: my_open,
    read: my_read,
write: my_write,
release:my_release,
};

int my_open(struct inode *inode,struct file *filep)
{  
    /*MOD_INC_USE_COUNT;*/ /* increments usage count of module */
return 0;
}

int my_release(struct inode *inode,struct file *filep)
{
/*MOD_DEC_USE_COUNT;*/ /* decrements usage count of module */
return 0;
}
ssize_t my_read(struct file *filep,char *buff,size_t count,loff_t *offp )
{
/* function to copy kernel space buffer to user space*/
if ( copy_to_user(buff,my_data,strlen(my_data)) != 0 )
    printk( "Kernel -> userspace copy failed!\n" );
return strlen(my_data);

}
ssize_t my_write(struct file *filep,const char *buff,size_t count,loff_t *offp )
{
/* function to copy user space buffer to kernel space*/
if ( copy_from_user(my_data,buff,count) != 0 )
    printk( "Userspace -> kernel copy failed!\n" );
return 0;
}
#endif

Вот моя программа пользовательского пространства acs.c, которая при запуске печатает "heloooo", читая текст из буфера ядра из вышеуказанной программы.

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

int main()
{
int fd=0,ret=0;
char buff[80]="";

fd=open("/dev/my_device",O_RDONLY);

printf("fd :%d\n",fd);

ret=read(fd,buff,10);
buff[ret]='\0';

printf("buff: %s ;length: %d bytes\n",buff,ret);
close(fd);
}

Теперь моя проблема в том, что мне нужно написать программу пользовательского пространства, которая при запуске печатает 10 случайных чисел. Но эти числа должны быть сгенерированы с помощью модуля ядра. Итак, в основном вышеуказанные три кода работают правильно и печатают "helooo". что мне нужно сделать, так это вместо "helooo" мне нужно получить случайные числа в качестве вывода.

Вот модуль памяти, который генерирует некоторые случайные числа, используя алгоритм линейного конгруэнтного генератора. LCG.c

#include <linux/module.h>   /* Needed by all modules */
#include <linux/kernel.h>   /* Needed for KERN_INFO */

int init_module(void)
{
int M = 8;  //Modulus,    M>0
    int a = 9;  //Multiplier, 0 <= a < M.
    int c = 3;  //Increment,  0 <= c < M.
    int X = 1;  //seed value, 0 <= X(0) < M
    int i;      //iterator,   i < M 
    for(i=0; i<8; i++)
    {
            X = (a * X + c) % M;
            printk(KERN_INFO "%d\n",X);

    }
    return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Task Done ! :D.\n");
}

У меня есть все коды. Но я не знаю, как разместить этот код генератора случайных чисел в моем коде вызова устройства charecter. Когда я запускаю программу acs.c, мне нужно получить вывод модуля памяти LCG.c, используя символьное устройство. Пожалуйста, помогите мне найти решение.


person Krishna    schedule 05.04.2013    source источник
comment
ret=read(fd,buff); read() принимает 3 параметра, вы забываете последний (nbytes)   -  person David Ranieri    schedule 05.04.2013
comment
Но эта программа работает и без третьего параметра.   -  person Krishna    schedule 06.04.2013
comment
Вы уверены? Не компилируется: error: array initializer must be an initializer list int buff[80]="";   -  person David Ranieri    schedule 06.04.2013
comment
Я немного отредактировал код. не могли бы вы попробовать сейчас   -  person Krishna    schedule 06.04.2013


Ответы (1)


Попробуйте внести эти изменения, я только что добавил изменения:

Выполните рефакторинг LCG.C, чтобы генератор случайных чисел был отдельной функцией, и убедитесь, что эта функция не статическая. Вам также необходимо экспортировать этот СИМВОЛ.

void generate_random_lcg(char* output_str)
{
    static const int M = 8;  //Modulus,    M>0
    static const int a = 9;  //Multiplier, 0 <= a < M.
    static const int c = 3;  //Increment,  0 <= c < M.
    static int X = 1;  //seed value, 0 <= X(0) < M

    int i;      //iterator,   i < M 
    ssize_t index = 0;
    for(i=0; i<8; i++)
    {
        X = (a * X + c) % M;
        index += sprintf(output_str + index, "%d\n", X);
    }
    output_str[index] = '\0';
}

EXPORT_SYMBOL(generate_random_lcg);

Таким образом, функция может быть вызвана непосредственно модулем LCG, а также извне.

Теперь, чтобы вызвать эту функцию из вашего модуля my_dev и вернуть результат, вам потребуются следующие изменения:

my_dev.c:

static int r_init(void)
{                                                                 
    printk("<1>hi\n");
    if(register_chrdev(222,"my_device",&my_fops)){                
            printk("<1>failed to register");                      
    }  

    memset(output_str, 0, MAX_SIZE);                              

    return 0;                                                     
}

В my_dev.h

extern void generate_random_lcg(char* output_str);

#define MAX_SIZE 1024
static char output_str[MAX_SIZE];

ssize_t my_read(struct file *filep,char *buff,size_t count,loff_t *offp )
{
    ssize_t output_str_size = 0;
    generate_random_lcg(output_str);
    output_str_size = strlen(output_str);
    /* function to copy kernel space buffer to user space*/
    if (copy_to_user(buff,output_str,output_str_size) != 0 )
    {
        printk( "Kernel -> userspace copy failed!\n" );
        return 0;
    }   
    return output_str_size;
}

Несколько вещей, о которых следует помнить:

  • Измените значение MAX_SIZE в соответствии с вашими потребностями. Если число становится действительно большим, вы можете подумать об использовании kmalloc вместо этого для получения памяти.
  • Определение реализации функций в файлах .h, за исключением встроенных функций, - действительно плохая практика.
  • Когда copy_from_user или copy_to_user не удается вернуть 0 вместо вывода из strlen.

Вышеупомянутое - это всего лишь очень грубая реализация, вам также могут потребоваться дополнительные проверки для проверки переполнения буфера при печати строки с помощью sprintf.

person Tuxdude    schedule 06.04.2013
comment
Большое спасибо. Это было так полезно :) - person Krishna; 04.05.2013