> > 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