On Thu, Jan 15, 2009 at 01:22:18PM -0600, Gerry Weaver wrote:
> _____  
> 
> From: Alexej Sokolov [mailto:bsd.qu...@googlemail.com]
> To: Gerry Weaver [mailto:ger...@compvia.com]
> Cc: freebsd-hackers@freebsd.org
> Sent: Thu, 15 Jan 2009 12:31:00 -0600
> Subject: Re: How to access kernel memory from user space
> 
> 
> 
> 
> 2008/12/23 Gerry Weaver <ger...@compvia.com>
>   Hello All,
>   
>   I am working on a driver that collects various network statistics via pfil. 
> I have a simple array of structures that I use to store the statistics. I 
> also have a user space process that needs to collect these statistics every 
> second or so. A copy operation from kernel to user space would be too 
> expensive. Is there a mechanism that would allow me to gain direct access to 
> my kernel array from user space? The user process would only need read 
> access. It seems like maybe this could be done with mmap, but since this is 
> not a character driver, there is no device file etc.. I'm a newbie, so I 
> apologize if this is something that should be obvious.
>     
>   
>   Thanks in advance,
>   Gerry
>   _______________________________________________
>   freebsd-hackers@freebsd.org mailing list
>   http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
>   To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"
>   Hi, 
> some times ago I solve this task. That's my solution in a system call 
> (whithout cdev). 
> Thanx in advance for founded mistakes and possible bugs (-:
> 
> 
> #include <sys/param.h>
>   #include <sys/proc.h>
> #include <sys/conf.h>
> #include <sys/module.h>
> #include <sys/sysent.h>
> #include <sys/kernel.h>
> #include <sys/systm.h>
> #include <sys/sysproto.h>
>   #include <sys/resourcevar.h>
>  
> #include <vm/vm.h>
> #include <vm/pmap.h>
> #include <vm/vm_map.h>
> #include <vm/vm_param.h>
> #include <vm/vm_kern.h>
> #include <vm/vm_object.h>
>    
>  
> /* Arguments for syscall */
> struct args {
>  
>         /* Pointer to allocated Buffer */
>         unsigned int  *p;
> }; 
>  
> /* String to be located in maped buffer */
> const char *str = "BSD IS SEXY";
>    
> /* Syscall func */
> static int 
> syscf(struct thread *td, void *sa)
> {
>         int error;
>         struct args *uap;   
>         vm_offset_t addr;          /* Kernel space address */
>         vm_offset_t user_addr;  /* User space address  */
>    
>         struct proc *procp = (struct proc *)td->td_proc;
>  
>         struct vmspace *vms = procp->p_vmspace;                 
>  
>         uap = (struct args *)sa;  
> 
>         PROC_LOCK(procp);
>         user_addr = round_page((vm_offset_t)vms->vm_daddr + 
>                           lim_max(procp, RLIMIT_DATA));
>         PROC_UNLOCK(procp);
>  
>         MALLOC(addr, vm_offset_t, PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
>  
>         vm_map_entry_t  myentry;
>         vm_object_t     myobject;
>           vm_pindex_t     mypindex;
>         vm_prot_t       myprot;
>         boolean_t       mywired;
>         vm_ooffset_t    objoffset;
> 
>         vm_map_lookup(&kmem_map, addr, VM_PROT_ALL,
>                         &myentry, &myobject, &mypindex, &myprot, &mywired); 
> /* OUT */
>           vm_map_lookup_done(kmem_map, myentry);
>  
>         printf("---> Syscall: hint for allocating space = 0x%X\n", addr);
>   
>         if (myobject == kmem_object){
>                 printf("---> Syscall: Yes, it is kmem_obj! \n");
>           }
>  
>         /* Offset in vm_object */   
>         objoffset = addr - myentry->start + myentry->offset;
>  
>         printf("------> Syscall: Object offset = 0x%X \n", (unsigned 
> int)objoffset);
>    
>         /*
>          * Try to map kernel buffer to user space  
>          */
>         vm_object_reference(myobject); /* NEEDED Increment vm_obj references 
> */
>         error = vm_map_find(&vms->vm_map, myobject, objoffset, (vm_offset_t 
> *)&user_addr, 
>                           PAGE_SIZE, TRUE, VM_PROT_RW, VM_PROT_RW, 
>                         MAP_ENTRY_NOFAULT);
>  
>         if (error == KERN_SUCCESS) {
>         /* copy string using kernel address */
>                 size_t len;
>                   copystr(str, (void *)addr, 12, &len); 
>  
>                 /* 
>                  * Tell to user process it's  user space address 
>                  */
>                 *uap->p = user_addr;
>    
>                 /* 
>                  * Try to read the string using user space address
>                  */     
>                 printf("String: %s\n", (char *)*uap->p); 
>  
>                 printf("---> Syscall: user_addr for allocating space = 
> 0x%X\n", user_addr);
>           }
>  
>         return (0);
> }
>  
> /* Sysent entity for syscall */
> static struct sysent sc_sysent = {
>         1,                                              /* Number of 
> arguments */
>         syscf                                   /* Syscall function    */
>   };
>  
> /* Offset in sysent[] */
> static int offset = NO_SYSCALL;
>  
> /* Loader */
> static int
> load (struct module *m, int cmd, void *something)
> {
>         int error = 0;
>         switch(cmd){
>                 case MOD_LOAD:
>                           printf("Module with sysc loaded. Offset = %d \n", 
> offset);
>                         break;
>  
>                 case MOD_UNLOAD:
>                         printf("Module with sysc unloaded. Offset = %d \n", 
> offset);
>                           break;
>  
>                 default:
>                         error = EOPNOTSUPP;
>                         break;
>         }
>         return (error);
> }
>  
> /* Syscall macro*/
> SYSCALL_MODULE(fiveg_sysc, &offset, &sc_sysent, load, NULL);
>   
> If needed, I can post user space program. 
> Hi,
> 
> This looks like a very nice solution. I would like to see the user space code 
> very much.
> I really appreciate your help!
> 
> Thanks Again,
> Gerry
User space program: 

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/module.h>
 
int
main(int argc, char *argv[])
{
        int sysc_num, error; 
        struct module_stat mstat;
 
        /* This Variable will save the addres of remapped buffer */
        unsigned int  some_var;
 
        /* Pointer to pointer to remapped buffer */
        unsigned int  *p = &some_var;
 
        printf("USER: Pointer   = %p \n", p);
 
        /* Search module with system call */
        mstat.version = sizeof(mstat);
        if ( !(modstat(modfind("fiveg_sysc"), &mstat)) ){
                /* Our module */
                sysc_num = mstat.data.intval;
                printf("USER: Module found! Syscall number = %d \n",
sysc_num);
 
                /* make system call */
                error = syscall(sysc_num, p);
 
                /* Read the string from remapped buffer */
                printf("USER: String = %s\n", (char *)*p);
 
 
        } else {
                printf("USER: Module seems to be not loaded! \n");
        }
 
        return(0);
}

-- 
Alexej Sokolov <bsd.qu...@googlemail.com>
_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"

Reply via email to