bzs@world.std.com (Barry Shein) (11/08/90)
>When the kernel gets the interrupt how can it find the user buffer again >(assuming it has been locked into memory) to do the next transfer? The >buffer may no longer be mapped into the kernel's virtual address space >since at the time of the interrupt some other user process may be running. >How can the kernel even find the original user process (to, say, send a >SIGIO to it)? Does it have to search the process table looking for it? >It can't search physical RAM looking for the buffer since the buffer may >be segmented into many chunks of RAM. Well, one way to handle this is to just use a temp buffer to DMA between and use copyin() and/or copyout() to move the data, but it sounds like you're trying very hard to avoid that, ok. Depending on how much info you really have to keep around you could certainly declare a structure specific to the device with the items you want to know latter, use rmalloc() or similar to create one for each transfer and have the buffer struct point at it when you start. Being as the buf struct is handed back to you at interrupt time you could just snoop in there for the info you saved previously. So the obvious thing would be: struct mydevinfo { pid_t user_pid; caddr_t user_buffer; }; and then when you set up the transfer something like: struct mydevinfo *myp; myp = (struct mydevinfo *)rmalloc(sizeof(struct mydevinfo)); myp->user_pid = pid; myp->user_buffer = buffer; bp->b_un.b_addr = (caddr_t)myp; and in the interrupt handler: struct mydevinfo *myp; myp = (struct mydevinfo *)bp->b_un.b_addr; and so on. sort of disgusting but it would do the job. Maybe I'm missing something here... gee, an internals question...imagine...I just had to *try* to answer, but I'd suggest you wait until people pick apart my suggestion before taking the advice. -- -Barry Shein Software Tool & Die | {xylogics,uunet}!world!bzs | bzs@world.std.com Purveyors to the Trade | Voice: 617-739-0202 | Login: 617-739-WRLD
sramtrc@windy.dsir.govt.nz (11/08/90)
Suppose I have a UNIX version which maps a user program into the kernel virtual space. Then accessing a user buffer by the kernel is easy since the buffer has an address in the kernel virtual space. Suppose the kernel wants to send the user buffer to a device in several transfers. This is easy because the kernel tells the device the address of the buffer, starts the transfer, and waits for an interrupt from the device. When the kernel gets the interrupt how can it find the user buffer again (assuming it has been locked into memory) to do the next transfer? The buffer may no longer be mapped into the kernel's virtual address space since at the time of the interrupt some other user process may be running. How can the kernel even find the original user process (to, say, send a SIGIO to it)? Does it have to search the process table looking for it? It can't search physical RAM looking for the buffer since the buffer may be segmented into many chunks of RAM. Thanks, Tony Cooper sramtrc@albert.dsir.govt.nz
thorinn@rimfaxe.diku.dk (Lars Henrik Mathiesen) (11/08/90)
sramtrc@windy.dsir.govt.nz writes: >Suppose I have a UNIX version which maps a user program into the kernel >virtual space. Then accessing a user buffer by the kernel is easy since >the buffer has an address in the kernel virtual space. Suppose the kernel >wants to send the user buffer to a device in several transfers. >When the kernel gets the interrupt how can it find the user buffer again >(assuming it has been locked into memory) to do the next transfer? [Many >problems described] This is probably why even those UNIX versions where user programs are mapped for the kernel (such as any UNIX on a VAX) often don't use this direct approach. Rather, the driver asks a support routine (physio in 4.3BSD) to take as large a chunk of the user buffer as the driver can handle and make it ``look like'' a kernel cache buffer. Usually that involves locking the pages incore and allocating a buffer header and some kernel virtual address space to map the chunk. Physio then calls the device strategy routine, frees up everything and repeats the process for the next chunk. It is physio that keeps context between chunks (such as user virtual address and location of the user page map). If your UNIX has physio or an equivalent, you're probably better off using it. -- Lars Mathiesen, DIKU, U of Copenhagen, Denmark [uunet!]mcsun!diku!thorinn Institute of Datalogy -- we're scientists, not engineers. thorinn@diku.dk
bzs@world.std.com (Barry Shein) (11/09/90)
Yeah, physio(), don't you have to call mapin() to lock down the pages first? Anyhow, that seems like the right advice that Lars just gave. -- -Barry Shein Software Tool & Die | {xylogics,uunet}!world!bzs | bzs@world.std.com Purveyors to the Trade | Voice: 617-739-0202 | Login: 617-739-WRLD
hue@island.uu.net (Jon Hue - "Bo knows windsurfing?") (11/09/90)
In article <18747.27394289@windy.dsir.govt.nz>, sramtrc@windy.dsir.govt.nz writes: > the buffer has an address in the kernel virtual space. Suppose the kernel > wants to send the user buffer to a device in several transfers. This is > easy because the kernel tells the device the address of the buffer, starts > the transfer, and waits for an interrupt from the device. > > When the kernel gets the interrupt how can it find the user buffer again > (assuming it has been locked into memory) to do the next transfer? The Unless I'm missing something here, you should try to write your driver so you can use physio(). physio() will handle breaking up the transfer into chunks the device can deal with, pin down the memory, and then call your strategy routine to perform the I/O operation. Are you under some sort of real-time contraint which requires you to start the next I/O operation from the interrupt level? It's much simpler if you can just wakeup the sleeping process from the interrupt level, and wait for it to start running (still inside physio()) again. Jonathan Hue Island Graphics Corp. uunet!island!hue hue@island.com
boyd@necisa.ho.necisa.oz (Boyd Roberts) (11/09/90)
In article <18747.27394289@windy.dsir.govt.nz> sramtrc@albert.dsir.govt.nz writes: >Suppose I have a UNIX version which maps a user program into the kernel >virtual space. Then accessing a user buffer by the kernel is easy since >the buffer has an address in the kernel virtual space. Suppose the kernel >wants to send the user buffer to a device in several transfers. This is >easy because the kernel tells the device the address of the buffer, starts >the transfer, and waits for an interrupt from the device. > >When the kernel gets the interrupt how can it find the user buffer again >(assuming it has been locked into memory) to do the next transfer? Usually the user data is copied into a kernel mode data structure* with copyin() [iomove() in the read()/write() case]. The copy is done precisely to avoid the problem of being able to reference the data when the process's context is not available for reference. This approach is usually ok, but sometimes you want to DMA straight to the process's address space. To do that I've often cheated by getting physio() to do the hard work. My character based driver has a `dummy' strategy routine et al and it's called from physio(). The driver calls physio() and physio() locks down the process and does all the foul machine dependent mapping and calls the strategy routine until the I/O is complete. The process is unlocked, the DMA done. Of course, your kernel may not do exactly what I described. There may be other hooks to validate pages, lock them down and provide a kernel mapping to them. Then again, there may be none that suit your application. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...'' * How you get that data structure is your problem and is specific to the driver and kernel. Just make sure it's in context when you want to reference it. The kernel stack is just a no-no.
sramtrc@windy.dsir.govt.nz (11/09/90)
PS - I should add that what I want to do is copy directly from user space to a device. Physio is supposed to do this and it does. But my physio cheats. It uses copyin/copyout to move the user data into kernel data space. That's the copy I would like to avoid. I noticed that Sun's physio does not do a copy. But I guess it uses a different mechanism for accessing user space. Tony Cooper sramtrc@albert.dsir.govt.nz