内核模块与sys_call交互

时间:2013-12-02 22:06:02

标签: c linux linux-kernel system-calls

我是stackoverflow的新手,至少作为一个提问者。首先,我想为我的拼写语言道歉,因为这不是我的母语,坦率地说,我已经忘记了很久了。

我正在为Debian 6(内核2.6.39.4)编写内核模块,该模块与我对系统的调用进行交互。它们都很简单,因为我是在学习目的。 Syscall看起来像是在工作,并向用户输出一个功能,允许插入一个条目列表并注册这两个函数,一个读取,另一个写入。

模块只是一个计数器,其读写功能是计数器值的补充和当前计数器值的参考。如果一切正常,则写入函数会向计数器添加一个,并且read函数会将计数器返回给缓冲区。当我使用makefile时会出现问题,然后我收到这条消息(西班牙语中的所有内容都被字面翻译)

 make -C /lib/modules/2.6.39.4.mikernel/build M=/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs modules 
make[1]: acess to the directory `/usr/src/linux-headers-2.6.39.4.mikernel' 
Building modules, stage 2. 
MODPOST 1 modules 
WARNING: "create_kifs_entry" [/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs/ModuloUsaKifs.ko] undefined! 
WARNING: "remove_kifs_entry" [/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs/ModuloUsaKifs.ko] undefined! 
make[1]: get out of the directory `/usr/src/linux-headers-2.6.39.4.mikernel'

我不知道为什么不支持创建和删除功能。 “kifs”系统调用是(我认为)正确实现的(包括.h和.c,修改了调度,添加到syscall表,内核编译,调试,并用程序测试)我只证明了“sys_kifs”系统调用,但不是.h函数。这是我使用的makefile。

obj-m = ModuloUsaKifs.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

这就是模块。我很抱歉缺少文档,因为内核消息是西班牙语。我觉得人们进入我未清洁的厕所。我有一些额外的包括我将在以后删除。 ModuloUsaKifs.c

#define PROC_ENTRY "mymodule" 
#ifdef __KERNEL__ 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/proc_fs.h> 
#include <linux/string.h> 
#include <linux/vmalloc.h> 
#include <linux/string.h> 
#include <linux/kifs.h> 
#include <asm-generic/errno-base.h> 
#include <asm-generic/errno.h> 
#include <asm-generic/uaccess.h> 
MODULE_LICENSE("GPL"); 
MODULE_DESCRIPTION("List Kernel Module para DSO"); 
MODULE_AUTHOR("Kaostias"); 
MODULE_LICENSE("GPL"); 
#else 
//#include <iostream> 
//#include <linux/list.h> 
#include <string.h> 
#include "list.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include "kifs.h" 
#endif 
int counter; 
//typedef   int (*read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data); 
//typedef   int (*write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data); 


/**********************/ 
/* módulo en sí mismo */ 
/**********************/ 

int sum(char *user_buffer, unsigned int maxchars, void *data){ 
   char str [256]; 
   if (copy_from_user(str, user_buffer, maxchars)) { 
       return -EFAULT; 
   } 
   counter++; 
   return maxchars; 
} 
int lect(const char *user_buffer, unsigned int maxchars, void *data){ 
   char buf[32]; 
   int len=sprintf(buf,"%d\n",counter); 
   if (len> maxchars) 
   { 
      return -EINVAL; 
   } 
   if(copy_to_user(buf, user_buffer, len)){ 
      printk(KERN_INFO "problemas en lect"); 
      return -EINVAL; 
    } 
   return len; 

} 

int metodoInicial(void){ 

   counter = 0; 

   if(create_kifs_entry("counter",sum,lect,NULL) != NULL) 
   { 
      counter = 0; 
      printk(KERN_INFO "modulo abierto correctamente"); 
      return 0; 
   } 
   printk(KERN_INFO "Error, módulo counter incorrectamente agregado a kifs"); 
   return -EINVAL; 
} 

void metodoFinal(void){ 

   if(remove_kifs_entry("counter")){ 
      printk(KERN_INFO "modulo cerrado correctamente"); 
   } 
   printk(KERN_INFO "Error, módulo counter incorrectamente borrado de kifs"); 
} 

/*********************************/ 
/* Registra el init y el cleanup */ 
/*********************************/ 
module_init(metodoInicial); 
module_exit(metodoFinal);

这是“kifs”的标题

#ifndef KIFS_H 
#define KIFS_H 
#include <linux/list.h> /* list_head */ 

#define MAX_KIFS_ENTRY_NAME_SIZE 50 

/* Callback prototypes for kifs entries */ 
typedef   int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data); 
typedef   int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data); 


/* Descriptor interface for the entries */ 
typedef struct 
{ 
   char entryname[MAX_KIFS_ENTRY_NAME_SIZE]; 
   read_kifs_t *read_kifs; 
   write_kifs_t *write_kifs; 
   void *data; 
   struct list_head links;   /* Set of links in kifs */ 
}kifs_entry_t; 

enum { 
   KIFS_READ_OP=0, 
   KIFS_WRITE_OP, 
   KIFS_NR_OPS}; 


/* This function must ensure that no entry will be created as long as another entry with the same name already exists. 
 * == Return Value == 
 * NULL Entry name already exists or No space is availables 
 * Pointer to the kifs entry 
 * */ 
kifs_entry_t* create_kifs_entry(const char* entryname, 
            read_kifs_t *read_kifs, 
            write_kifs_t *write_kifs, 
            void* data); 


/* Remove kifs entry 
 * == Return Value == 
 * -1 Entry does not exist 
 *  0 success 
 * */ 
int remove_kifs_entry(const char* entry_name); 

/*  Implementation of kifs() system call 
 * == Return Value == 
 * -EINVAL Unsupported operation (NULL callback) or Entry not exists 
 * -EFAULT Any other error (e.g: copy_from_user(), copy_to_user(),...) 
 * otherwise: Number of chars read/written (Usually maxchars value) 
 */ 
asmlinkage long sys_kifs(const char* entry_name,unsigned int op_mode, char* user_buffer,unsigned int maxchars); 

/* KIFS's global initialization */ 
void init_kifs_entry_set(void); 


#endif

这是kifs.c本身

//#include "list.h"
#include <linux/kifs.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm-generic/errno-base.h>
#include <asm-generic/errno.h>
#include <asm-generic/uaccess.h>
/*
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Modulo KIFS para DSO");
MODULE_AUTHOR("Ismel Gonjal Montero");
*/
/* Callback prototypes for kifs entries */

/*
typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
*/

/*     Valores de lectura y escritura */

/*
enum {
    KIFS_READ_OP=0,
    KIFS_WRITE_OP,
    KIFS_NR_OPS};
*/
/***********************************/
/*      Declaraciones de kifs      */
/***********************************/
#define MAX_KIFS_ENTRIES 10
LIST_HEAD(entry_list);
LIST_HEAD(free_list);
kifs_entry_t pool[MAX_KIFS_ENTRIES];

/***********************************/
/*   Declaraciones de clipboard    */
/***********************************/
#define MAX_KIFS_CHARS 512
char clipboard[MAX_KIFS_CHARS];
/************************************/
/*    Declaracion de funciones      */
/************************************/
int read_list (char *user_buffer, unsigned int maxchars, void *data);


/******************************************************************************/
/*                           CLIPBOARD                                        */
/******************************************************************************/


int read_clipboard (char *user_buffer, unsigned int maxchars, void *data){
    int total = strlen(clipboard);

    if (total>maxchars)
    {   
        return  -EINVAL;
    }

    if (copy_to_user(user_buffer, clipboard, total))
    {
        printk(KERN_ALERT "Fallo en copy_to_user()");
        return  -EINVAL;
    }
    return total;
}

int write_clipboard (const char *user_buffer, unsigned int maxchars, void *data){

    if (maxchars>MAX_KIFS_CHARS-1)
    {
        printk(KERN_ALERT "Excede tamanio");
        return  -EINVAL;
    }

    if (copy_from_user(clipboard, user_buffer, maxchars))
    {
        printk(KERN_ALERT "Fallo en copy_from_user()");
        return  -EINVAL;
    }
    clipboard[maxchars]='\0';

    return  maxchars;
}



/****************************************************/
/*           Código de KIFS             */
/****************************************************/


/* KIFS's global initialization */
void init_kifs_entry_set(void){
    int i = 0;
    //añade a la lista todas las entradas de freelist
    for(i =0; i<MAX_KIFS_ENTRIES;i++){
        list_add_tail(&pool[i].links,&free_list);
    }
    clipboard[0]='\0';
    create_kifs_entry("list", read_list,NULL,NULL);
    create_kifs_entry("clipboard", read_clipboard,write_clipboard ,NULL);
    printk(KERN_ALERT "Inicializado kifs");
}

/*
 * Recibe un buffer de usuario, que llenará con una lista de las entradas
 * de la lista entry_list
 */
int read_list (char *user_buffer, unsigned int maxchars, void *data){
    int total = 0;
    char buf[512];
    struct list_head* pos = entry_list.next;
    kifs_entry_t* item;

    printk(KERN_ALERT "Entra en read_list");

    list_for_each(pos, &entry_list){
        item = list_entry(pos, kifs_entry_t, links);
        total+= sprintf(&buf[total],"%s\n",item->entryname);
    }

    if (copy_to_user(user_buffer,buf,total))
    {
        printk(KERN_ALERT "Fallo en copy_to_user()");
        return -EINVAL;
    }

    printk(KERN_ALERT "Sale de read_list por las buenas");
    return total;
}

/* This function must ensure that no entry will be created as long as another entry with the same name already exists.
 * == Return Value ==
 * NULL Entry name already exists or No space is availables
 * Pointer to the kifs entry
 * */
kifs_entry_t* create_kifs_entry(const char* entryname,
                read_kifs_t *read_kifs,
                write_kifs_t *write_kifs,
                void* data){
    kifs_entry_t* item;
    struct list_head* pos = entry_list.next;
    kifs_entry_t* itemFound = NULL;

    printk(KERN_ALERT "Creando entrada %s en Kifs",entryname);

    //Si la lista no está vacía
    list_for_each(pos, &entry_list){
        item = list_entry(pos, kifs_entry_t, links);
        if (strcmp(item->entryname,entryname) ==0){
            itemFound = item;
            break;          
        }
    }
    if (itemFound != NULL) {
        printk(KERN_ALERT "El item existe");
        return NULL;
    }

    //No hay espacio
    if(free_list.next == &free_list) {
        printk(KERN_ALERT "Error, lista llena");
        return NULL;
    }
    pos = free_list.next;
    item = list_entry(pos, kifs_entry_t, links);
    item->read_kifs = read_kifs;
    item->write_kifs = write_kifs;
    item->data = NULL;
    strcpy(item->entryname, entryname);

    list_del(pos);
    list_add_tail(pos,&entry_list);
    printk(KERN_ALERT "Entrada %s creada correctamente", entryname);
    return item;
}


/*  Implementation of kifs() system call
 * == Return Value ==
 * -EINVAL Unsupported operation (NULL callback) or Entry not exists
 * -EFAULT Any other error (e.g: copy_from_user(), copy_to_user(),...)
 * otherwise: Number of chars read/written (Usually maxchars value)
 */

asmlinkage long sys_kifs(const char* entry_name,unsigned int op_mode, char* user_buffer,unsigned int maxchars){

    struct list_head* pos;// = entry_list.next;
    kifs_entry_t* item;// = list_entry(pos, kifs_entry_t, links);
    kifs_entry_t* itemFound = NULL; 
    int ret = 0;
    //char usrBfr[512];

    printk(KERN_ALERT "Entrado a sys_kifs");
    /* Se comprueba que la llamada has sido correcta */
    list_for_each(pos, &entry_list){
        item = list_entry(pos, kifs_entry_t, links);
        if (strcmp(item->entryname,entry_name) ==0){
            itemFound = item;
            break;          
        }
    }

    if (itemFound == NULL){
        printk(KERN_ALERT "La entrada %s no existe", entry_name);
        return -EINVAL;
    }

/*  copy_from_user(usrBfr, user_buffer, maxchars);
    usrBfr[maxchars]='\0';

    printk(KERN_ALERT "Se ha copiado el parametro %s de la entrada %s",usrBfr, entry_name);

    printk(KERN_ALERT "Hay items en la lista");
*/
    /* llamadas que dependen del valor de lectura/escritura */
    if(op_mode == KIFS_READ_OP &&  item->read_kifs!=NULL ){
        ret = itemFound->read_kifs(user_buffer,maxchars,NULL);
        //printk(KERN_ALERT "El item utilizado es %s, en el método de lectura",user_buffer);
    }else if(op_mode == KIFS_WRITE_OP &&  item->write_kifs!=NULL ){ 
        ret = itemFound->write_kifs(user_buffer,maxchars,NULL); //No sé qué pasar de valor aquí
        //printk(KERN_ALERT "El item utilizado es %s, en el método de escritura",usrBfr);
    }else{
        ret=-EINVAL;
        printk(KERN_ALERT "Algo va mal");
    }
    return ret;
}

/* Remove kifs entry
 * == Return Value ==
 * -1 Entry does not exist
 *  0 success
 * */
int remove_kifs_entry(const char* entry_name){

    struct list_head* pos = entry_list.next;
    kifs_entry_t* item = list_entry(pos, kifs_entry_t, links);
    kifs_entry_t* itemFound = NULL; 
    printk(KERN_ALERT "Intentando eliminar entrada de Kifs");

    list_for_each(pos, &entry_list){
        item = list_entry(pos, kifs_entry_t, links);
        if (strcmp(item->entryname,entry_name) ==0){
            itemFound = item;
            break;          
        }
    }
    if (itemFound == NULL) {
        printk(KERN_ALERT "La lista de kifs está vacía");
        return -EINVAL;
    }

    list_del(pos);
    item->data = NULL;
    strcpy(item->entryname,"");
    item->read_kifs = NULL;
    item->write_kifs = NULL;
    list_add_tail(pos,&free_list);
    printk(KERN_ALERT "Entrada eliminada correctamente");
    return 0;
}

如果有必要将dmesg的结果与此问题联系起来

[ 1818.076342] ModuloUsaKifs: Unknown symbol remove_kifs_entry (err 0) 
[ 1818.076590] ModuloUsaKifs: Unknown symbol create_kifs_entry (err 0)

1 个答案:

答案 0 :(得分:1)

从评论到问题:

您需要使用EXPORT_SYMBOL导出函数名称,以便内核的其他部分调用这些函数。导出这些符号将在符号表中创建一个条目,从中查找其他模块/内核代码。如果只有您的模块使用这些功能,则无需导出。

在您的情况下,这些函数在一个模块中定义,并在另一个模块中使用。所以:

只需添加EXPORT_SYMBOL(create_kifs_entry);和EXPORT_SYMBOL(remove_kifs_entry);到你的代码