> > write() doesn't exist in the kernel.  The simple answer is "you're
> > going to have to read what the send() syscall does and emulate it".
> > First, though, you need to answer the question "why do I want to do
> > this in the kernel?"
> 
> it actually exists, however the problem is that copyin and friends 
> assume a seperate address space, I wonder if one could do some trick
> to alias the seperate address space on top of the kernel, that should
> allow copyin and friends to work on pointers into the kernel's address
> space.

Solaris does this by passing a tag into it's driver calls.  The tag 
is given to ddi_copy{in,out}() which DTRT.  When a kernel wants to 
open a file, it does a layered open (lyr_open() or some such) which 
results in an opaque handle with which you can do other lyr_* calls 
such as lyr_ioctl().  The driver has to declare itself as being 
capable of doing layered opens (via the d_flag bit of it's devsw), 
meaning that it uses ddi_copy{in,out} rather than copy{in,out}.

> > > 3. How I can copy a pointer string ( character array ) from user space to
> > >    kernel space using copyin() without the following problem (I can't
> > >    pass the length the explicitly from user land):
> > >
> > > struct    MySystemCall_args {
> > >   char *  address;
> > > };
> > >
> > > int MySystemCall( p,uap)
> > >   struct proc *p;
> > >   register struct  MySystemCall_args *uap;
> > > {
> > >   char *the_address;
> > >
> > >   printf(" ---> uap->address : %s\n", uap->address );
> > >   printf(" ---> (strlen (uap->address) * sizeof(char)) : %d \n",
> > >   (strlen (uap->address) * sizeof(char)) );
> > >   copyin(uap->address, the_address, (strlen (uap->address) * sizeof(char))
> > > );
> > >   printf("the_address: %s \n", the_address );
> > >   printf("strlen (the_address): %d \n", strlen (the_address) );
> > >
> > > When this code run in mode kernel:
> > >   ---> uap->address : 127.0.0.1
> > >   ---> (strlen (uap->address) * sizeof(char)) : 9
> > >   the_address : 127.0.0.1\M-"\M-Y\M-GX\M-p+\M-@@\M-_\M-*\M-@
> > >   strlen (the_address): 20
> > >
> > > This crash the kernel later...
> > 
> > You've forgotten the terminating \0.  Add one to the length.
> 
> You can't call kernel strlen on a userland address, you must do
> something like this:
> 
> /*
>  * return number of characters in a userland address string
>  * or -1 if an illegal access occurs.
>  */
> int
> user_strlen(uaddr)
>       char *uaddr;
> {
>       int ret;
> 
>       ret = -1;
>       do {
>               ch = fubyte(uaddr);
>               ret++;
>       } while (ch != 0 && ch != -1);
> 
>       return (ch == -1 ? -1 : ret);
> }

Have a look at the digi driver in -current where I did this.  The 
caveat is that the kernel code looks ugly.  From the driver's ioctl 
routine:

                case DIGIIO_IDENT:
                        return (copyout(sc->name, *(char **)data,
                            strlen(sc->name) + 1));

and from digiio.h:

#define DIGIIO_IDENT            _IOW('e', 'E', char *)

and from userland (digictl.c):

        char namedata[256], *name = namedata;
        ....
                        } else if (ioctl(fd, DIGIIO_IDENT, &name) != 0) {


> -- 
> -Alfred Perlstein [[EMAIL PROTECTED]]
> Ok, who wrote this damn function called '??'?
> And why do my programs keep crashing in it?

-- 
Brian <[EMAIL PROTECTED]>                <[EMAIL PROTECTED]>
      http://www.freebsd-services.com/        <brian@[uk.]FreeBSD.org>
Don't _EVER_ lose your sense of humour !      <brian@[uk.]OpenBSD.org>



To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message

Reply via email to