2016-04-21 1 views
3

Je suis en train de développer un module noyau Linux. Je veux utiliser les systèmes de fichiers mmap et proc pour partager la mémoire entre le noyau et l'espace utilisateur. J'ai implémenté certaines parties mais je ne sais pas comment le compléter.Comment utiliser la mémoire partagée mmap & proc entre le noyau et l'espace utilisateur

Je veux écrire quelque chose (sk_buff) dans le module du noyau et les lire dans l'espace utilisateur (lire le fichier proc et enregistrer le fichier). Que devrais-je faire? Je ne connais pas la signification de file_operations; devrais-je implémenter fops.write ou autre chose?

Voici mon code démo, (un module pour Linux 3.16):

#include <linux/version.h> 
#include <linux/module.h> 
#include <linux/proc_fs.h> 
#include <linux/mm.h> 
#include <linux/fs.h> 
#include <linux/seq_file.h> 

#define PROC_MEMSHARE_DIR "memshare" 
#define PROC_MEMSHARE_INFO "phymem_info" 
#define PROC_MMAP_FILE "mmap" 

/* alloc one page. 4096 bytes */ 
#define PAGE_ORDER 0 
/* this value can get from PAGE_ORDER */ 
#define PAGES_NUMBER 1 

struct proc_dir_entry *proc_memshare_dir ; 
unsigned long kernel_memaddr = 0; 
unsigned long kernel_memsize= 0; 

int proc_mmap(struct file *filp, struct vm_area_struct *vma) 
{ 
    unsigned long page; 
    page = virt_to_phys((void*)kernel_memaddr) >> PAGE_SHIFT; 

    if (remap_pfn_range(vma, vma->vm_start, page, (vma->vm_end - vma->vm_start), 
       vma->vm_page_prot)) 
    { 
     printk("remap failed..."); 
     return -1; 
    } 
    vma->vm_flags |= (VM_DONTDUMP|VM_DONTEXPAND); 
    printk("remap_pfn_rang page:[%lu] ok.\n", page); 
    return 0; 
} 

static int proc_show_meminfo(struct seq_file *m, void *v) { 
    seq_printf(m, "%08lx %lu\n",__pa(kernel_memaddr), kernel_memsize); 
    return 0; 
} 

static int proc_open_meminfo(struct inode *inode, struct file *file) { 
    return single_open(file, proc_show_meminfo, NULL); 
} 

static const struct file_operations read_phymem_info_fops = { 
    .owner = THIS_MODULE, 
    .open = proc_open_meminfo, 
    .read = seq_read, 
    .llseek = seq_lseek, 
    .release = seq_release 
}; 

static const struct file_operations proc_mmap_fops = { 
    .owner = THIS_MODULE, 
    .mmap = proc_mmap 
}; 

static int __init init(void) 
{ 
    /* build proc dir "memshare"and two proc files: phymem_addr, phymem_size in the dir */ 
    proc_memshare_dir = proc_mkdir(PROC_MEMSHARE_DIR, NULL); 
    proc_create_data(PROC_MEMSHARE_INFO, 0, proc_memshare_dir, &read_phymem_info_fops,NULL); 
    proc_create_data(PROC_MMAP_FILE, 0, proc_memshare_dir, &proc_mmap_fops,NULL); 

    /* alloc one page */ 
    kernel_memaddr =__get_free_pages(GFP_KERNEL, PAGE_ORDER); 
    if (!kernel_memaddr) { 
     printk("Allocate memory failure!/n"); 
    } else { 
     SetPageReserved(virt_to_page(kernel_memaddr)); 
     kernel_memsize = PAGES_NUMBER * PAGE_SIZE; 
     printk("Allocate memory success!. The phy mem addr=%08lx, size=%lu\n", __pa(kernel_memaddr), kernel_memsize); 
    } 
    return 0; 
} 

static void __exit fini(void) 
{ 
    printk("The content written by user is: %s\n", (unsigned char*) kernel_memaddr); 
    ClearPageReserved(virt_to_page(kernel_memaddr)); 
    free_pages(kernel_memaddr, PAGE_ORDER); 
    remove_proc_entry(PROC_MEMSHARE_INFO, proc_memshare_dir); 
    remove_proc_entry(PROC_MEMSHARE_DIR, NULL); 
    return; 
} 
module_init(init); 
module_exit(fini); 
MODULE_LICENSE("GPL"); 
MOUDLE_AUTHOR("wack"); 
MODULE_DESCRIPTION("Kernel memory share module."); 

Et voici le programme de l'espace utilisateur:

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

int main(int argc, char *argv[]) 
{ 
    char *str ; 
    if (argc != 2) { 
     printf("Usage: %s string\n", argv[0]); 
     return 0; 
    } 

    unsigned long phymem_addr, phymem_size; 
    char *map_addr; 
    char s[256]; 
    int fd; 

    /*get the physical address & size of allocated memory in kernel*/ 
    fd = open("/proc/memshare/phymem_info", O_RDONLY); 
    if (fd < 0) { 
     printf("cannot open file /proc/memshare/phymem_info\n"); 
     return 0; 
    } 
    read(fd, s, sizeof(s)); 
    sscanf(s, "%lx %lu", &phymem_addr,&phymem_size); 
    close(fd); 

    printf("phymem_addr=%lx, phymem_size=%lu\n", phymem_addr, phymem_size); 
    /*memory map*/ 
    int map_fd = open("/proc/memshare/mmap", O_RDWR|O_SYNC); 
    if (map_fd < 0) { 
     printf("cannot open file /proc/memshare/mmap\n"); 
     return -1; 
    } 
    map_addr = mmap(NULL, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, phymem_addr); 
    if (map_addr ==MAP_FAILED) { 
     perror("mmap"); 
     printf("MAP_FAILED : %s",map_addr); 
     close(map_fd); 
     return -1; 
    } else{ 
     printf("mmap: %s \n",map_addr); 
     printf("addr: %p \n",map_addr); 
     printf("addr: %d \n",*map_addr); 
    } 
    //memcpy(map_addr, argv[1],sizeof(argv)); 
    strcpy(map_addr,argv[1]); 
    memcpy(str,map_addr,256); 
    printf("str is :%s \n",str); 
    int ret = munmap(map_addr, phymem_size); 
    if (ret) { 
     printf("munmap failed:%d \n",ret); 
    } 
    close(map_fd); 
    return 0; 
} 
+0

je pas tout à fait undestand: Vous avez déjà implémenté la lecture depuis votre fichier 'proc' (le noyau y écrit, l'utilisateur en lit). Alors, qu'est-ce qu'un problème? Voulez-vous autoriser l'utilisateur à écrire votre fichier 'proc'? – Tsyvarev

+0

Je veux écrire le fichier proc dans le module du noyau, et je ne sais pas comment faire. Ce code ne lit que le fichier mais n'écrit pas ... Pouvez-vous me dire comment exporter le message du noyau vers le fichier proc? (En effet, je veux jeter sk_buff au proc et le lire dans l'espace utilisateur) – wack

+0

'seq_file' aide seulement à la lecture à partir du fichier. Vous devez implémenter la méthode 'fops.write' pour écrire dans votre fichier proc. – Tsyvarev

Répondre

0

Le meilleur que je suis en mesure de le faire sur ma:

  • Dans ce problème, je veux écrire sk_buff à mémoire partagée et le lire à partir de l'espace utilisateur.
  • Ici, j'utilise netfilter crochet PRE_ROUTING, et dans mon crochet je peux obtenir le skb.
  • Sur la question de savoir comment écrire en mémoire partagée, comme suggéré par l'utilisateur Tsyvarev, je peux écrire la mémoire I malloc directement.

Première malloc mémoire partagée:

kernel_memaddr = __get_free_pages(GFP_KERNEL, PAGE_ORDER); //or use kmalloc vmalloc 
SetPageReserved(virt_to_page(kernel_memaddr)); 

Userspace a besoin de connaître la mémoire adresse physique (lire proc):

static int proc_show_meminfo(struct seq_file *m, void *v) { 
    seq_printf(m, "%08lx %lu\n",__pa(kernel_memaddr), kernel_memsize); 
    return 0; 
} 

En proc_mmap(), nous devons remap_pfn_range la mémoire:

int proc_mmap(struct file *filp, struct vm_area_struct *vma) 
{ 
    unsigned long page; 
    page = virt_to_phys((void *)kernel_memaddr) >> PAGE_SHIFT; 

    if(remap_pfn_range(vma, vma->vm_start, page, (vma->vm_end - vma->vm_start), 
     vma->vm_page_prot)) 
    { 
     printk("remap failed..."); 
     return -1; 
    } 
    vma->vm_flags |= (VM_DONTDUMP|VM_DONTEXPAND); 
    printk("remap_pfn_rang page:[%lu] ok.\n", page); 
    return 0; 
} 

Lorsque nous voulons écrire des données sur la mémoire partagée, juste le copier:

memcpy((void *)(memaddr + offset),data, dataLen); //data is what you want to write 

Et dans l'espace utilisateur, après que nous obtenons kernel_memaddr, nous utilisons mmap() pour obtenir l'adresse

map_addr = mmap(NULL, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, phymem_addr); 
memcpy(str,map_addr,256);