Date: Fri, 13 Jul 2001 15:52:29 +0100 From: Brian Somers <brian@Awfulhak.org> To: Alfred Perlstein <bright@sneakerz.org> Cc: Greg Lehey <grog@FreeBSD.ORG>, y-carden@uniandes.edu.co, FreeBSD Hackers <hackers@FreeBSD.ORG>, brian@Awfulhak.org Subject: Re: Some questions about kernel programming Message-ID: <200107131452.f6DEqTW59861@hak.lan.Awfulhak.org> In-Reply-To: Message from Alfred Perlstein <bright@sneakerz.org> of "Thu, 12 Jul 2001 21:28:09 CDT." <20010712212809.F6664@sneakerz.org>
next in thread | previous in thread | raw e-mail | index | archive | help
> > 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 [alfred@freebsd.org] > Ok, who wrote this damn function called '??'? > And why do my programs keep crashing in it? -- Brian <brian@freebsd-services.com> <brian@Awfulhak.org> 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 majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200107131452.f6DEqTW59861>