Реализация символьного устройства для генерации случайных чисел
Основываясь на моем академическом проекте, моя текущая задача состоит в том, чтобы сгенерировать 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 ;
}
Мой файл Ma ke для заполнения этого модуля
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.ci, нужно получить вывод модуля памяти LCG.c
используя символьное устройство. Пожалуйста, помогите мне найти решение.
1 ответ
Попробуйте с этими изменениями, я только что добавил изменения:
Refactor 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.