代码之家  ›  专栏  ›  技术社区  ›  Krishna

用于生成随机数的字符设备实现

  •  2
  • Krishna  · 技术社区  · 13 年前

    根据我的accademic项目,我目前的任务是使用内核模块生成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的用户bufer写入和读取一些文本。

    /*
     * 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公司 通过使用字符设备。请帮我找到解决方案。

    1 回复  |  直到 13 年前
        1
  •  1
  •   Tuxdude    13 年前

    尝试这些更改,我刚刚添加了更改:

    重构器 LCG.C 以便随机数生成器是一个单独的函数,并确保该函数 非静态的 。您还需要导出此SYMBOL。

    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调用此函数并返回输出,需要进行以下更改:

    我的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;                                                     
    }
    

    在里面 我的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打印字符串时,您可能还需要额外的检查来检查缓冲区溢出。