On Thu, Jan 15, 2009 at 01:22:18PM -0600, Gerry Weaver wrote:
> _____
>
> From: Alexej Sokolov [mailto:[email protected]]
> To: Gerry Weaver [mailto:[email protected]]
> Cc: [email protected]
> Sent: Thu, 15 Jan 2009 12:31:00 -0600
> Subject: Re: How to access kernel memory from user space
>
>
>
>
> 2008/12/23 Gerry Weaver <[email protected]>
> 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
> _______________________________________________
> [email protected] mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
> To unsubscribe, send any mail to "[email protected]"
> 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 <[email protected]>
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[email protected]"