2007-07-26 10:41:02 -07:00
/*P:300 The I/O mechanism in lguest is simple yet flexible, allowing the Guest
* to talk to the Launcher or directly to another Guest . It uses familiar
* concepts of DMA and interrupts , plus some neat code stolen from
* futexes . . . : */
/* Copyright (C) 2006 Rusty Russell IBM Corporation
2007-07-19 01:49:23 -07:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <linux/types.h>
# include <linux/futex.h>
# include <linux/jhash.h>
# include <linux/mm.h>
# include <linux/highmem.h>
# include <linux/uaccess.h>
# include "lg.h"
2007-07-26 10:41:03 -07:00
/*L:300
* I / O
*
* Getting data in and out of the Guest is quite an art . There are numerous
* ways to do it , and they all suck differently . We try to keep things fairly
* close to " real " hardware so our Guest ' s drivers don ' t look like an alien
* visitation in the middle of the Linux code , and yet make sure that Guests
* can talk directly to other Guests , not just the Launcher .
*
* To do this , the Guest gives us a key when it binds or sends DMA buffers .
* The key corresponds to a " physical " address inside the Guest ( ie . a virtual
* address inside the Launcher process ) . We don ' t , however , use this key
* directly .
*
* We want Guests which share memory to be able to DMA to each other : two
* Launchers can mmap memory the same file , then the Guests can communicate .
* Fortunately , the futex code provides us with a way to get a " union
* futex_key " corresponding to the memory lying at a virtual address: if the
* two processes share memory , the " union futex_key " for that memory will match
* even if the memory is mapped at different addresses in each . So we always
* convert the keys to " union futex_key " s to compare them .
*
* Before we dive into this though , we need to look at another set of helper
* routines used throughout the Host kernel code to access Guest memory .
: */
2007-07-19 01:49:23 -07:00
static struct list_head dma_hash [ 61 ] ;
2007-07-26 10:41:03 -07:00
/* An unfortunate side effect of the Linux double-linked list implementation is
* that there ' s no good way to statically initialize an array of linked
* lists . */
2007-07-19 01:49:23 -07:00
void lguest_io_init ( void )
{
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( dma_hash ) ; i + + )
INIT_LIST_HEAD ( & dma_hash [ i ] ) ;
}
/* FIXME: allow multi-page lengths. */
static int check_dma_list ( struct lguest * lg , const struct lguest_dma * dma )
{
unsigned int i ;
for ( i = 0 ; i < LGUEST_MAX_DMA_SECTIONS ; i + + ) {
if ( ! dma - > len [ i ] )
return 1 ;
if ( ! lguest_address_ok ( lg , dma - > addr [ i ] , dma - > len [ i ] ) )
goto kill ;
if ( dma - > len [ i ] > PAGE_SIZE )
goto kill ;
/* We could do over a page, but is it worth it? */
if ( ( dma - > addr [ i ] % PAGE_SIZE ) + dma - > len [ i ] > PAGE_SIZE )
goto kill ;
}
return 1 ;
kill :
kill_guest ( lg , " bad DMA entry: %u@%#lx " , dma - > len [ i ] , dma - > addr [ i ] ) ;
return 0 ;
}
2007-07-26 10:41:03 -07:00
/*L:330 This is our hash function, using the wonderful Jenkins hash.
*
* The futex key is a union with three parts : an unsigned long word , a pointer ,
* and an int " offset " . We could use jhash_2words ( ) which takes three u32s .
* ( Ok , the hash functions are great : the naming sucks though ) .
*
* It ' s nice to be portable to 64 - bit platforms , so we use the more generic
* jhash2 ( ) , which takes an array of u32 , the number of u32s , and an initial
* u32 to roll in . This is uglier , but breaks down to almost the same code on
* 32 - bit platforms like this one .
*
* We want a position in the array , so we modulo ARRAY_SIZE ( dma_hash ) ( ie . 61 ) .
*/
2007-07-19 01:49:23 -07:00
static unsigned int hash ( const union futex_key * key )
{
return jhash2 ( ( u32 * ) & key - > both . word ,
( sizeof ( key - > both . word ) + sizeof ( key - > both . ptr ) ) / 4 ,
key - > both . offset )
% ARRAY_SIZE ( dma_hash ) ;
}
2007-07-26 10:41:03 -07:00
/* This is a convenience routine to compare two keys. It's a much bemoaned C
* weakness that it doesn ' t allow ' = = ' on structures or unions , so we have to
* open - code it like this . */
2007-07-19 01:49:23 -07:00
static inline int key_eq ( const union futex_key * a , const union futex_key * b )
{
return ( a - > both . word = = b - > both . word
& & a - > both . ptr = = b - > both . ptr
& & a - > both . offset = = b - > both . offset ) ;
}
2007-07-26 10:41:03 -07:00
/*L:360 OK, when we need to actually free up a Guest's DMA array we do several
* things , so we have a convenient function to do it .
*
* The caller must hold a read lock on dmainfo owner ' s current - > mm - > mmap_sem
* for the drop_futex_key_refs ( ) . */
2007-07-19 01:49:23 -07:00
static void unlink_dma ( struct lguest_dma_info * dmainfo )
{
2007-07-26 10:41:03 -07:00
/* You locked this too, right? */
2007-07-19 01:49:23 -07:00
BUG_ON ( ! mutex_is_locked ( & lguest_lock ) ) ;
2007-07-26 10:41:03 -07:00
/* This is how we know that the entry is free. */
2007-07-19 01:49:23 -07:00
dmainfo - > interrupt = 0 ;
2007-07-26 10:41:03 -07:00
/* Remove it from the hash table. */
2007-07-19 01:49:23 -07:00
list_del ( & dmainfo - > list ) ;
2007-07-26 10:41:03 -07:00
/* Drop the references we were holding (to the inode or mm). */
2007-07-19 01:49:23 -07:00
drop_futex_key_refs ( & dmainfo - > key ) ;
}
2007-07-26 10:41:03 -07:00
/*L:350 This is the routine which we call when the Guest asks to unregister a
* DMA array attached to a given key . Returns true if the array was found . */
2007-07-19 01:49:23 -07:00
static int unbind_dma ( struct lguest * lg ,
const union futex_key * key ,
unsigned long dmas )
{
int i , ret = 0 ;
2007-07-26 10:41:03 -07:00
/* We don't bother with the hash table, just look through all this
* Guest ' s DMA arrays . */
2007-07-19 01:49:23 -07:00
for ( i = 0 ; i < LGUEST_MAX_DMA ; i + + ) {
2007-07-26 10:41:03 -07:00
/* In theory it could have more than one array on the same key,
* or one array on multiple keys , so we check both */
2007-07-19 01:49:23 -07:00
if ( key_eq ( key , & lg - > dma [ i ] . key ) & & dmas = = lg - > dma [ i ] . dmas ) {
unlink_dma ( & lg - > dma [ i ] ) ;
ret = 1 ;
break ;
}
}
return ret ;
}
2007-07-26 10:41:03 -07:00
/*L:340 BIND_DMA: this is the hypercall which sets up an array of "struct
* lguest_dma " for receiving I/O.
*
* The Guest wants to bind an array of " struct lguest_dma " s to a particular key
* to receive input . This only happens when the Guest is setting up a new
* device , so it doesn ' t have to be very fast .
*
* It returns 1 on a successful registration ( it can fail if we hit the limit
* of registrations for this Guest ) .
*/
2007-07-19 01:49:23 -07:00
int bind_dma ( struct lguest * lg ,
unsigned long ukey , unsigned long dmas , u16 numdmas , u8 interrupt )
{
unsigned int i ;
int ret = 0 ;
union futex_key key ;
2007-07-26 10:41:03 -07:00
/* Futex code needs the mmap_sem. */
2007-07-19 01:49:23 -07:00
struct rw_semaphore * fshared = & current - > mm - > mmap_sem ;
2007-07-26 10:41:03 -07:00
/* Invalid interrupt? (We could kill the guest here). */
2007-07-19 01:49:23 -07:00
if ( interrupt > = LGUEST_IRQS )
return 0 ;
2007-07-26 10:41:03 -07:00
/* We need to grab the Big Lguest Lock, because other Guests may be
* trying to look through this Guest ' s DMAs to send something while
* we ' re doing this . */
2007-07-19 01:49:23 -07:00
mutex_lock ( & lguest_lock ) ;
down_read ( fshared ) ;
if ( get_futex_key ( ( u32 __user * ) ukey , fshared , & key ) ! = 0 ) {
kill_guest ( lg , " bad dma key %#lx " , ukey ) ;
goto unlock ;
}
2007-07-26 10:41:03 -07:00
/* We want to keep this key valid once we drop mmap_sem, so we have to
* hold a reference . */
2007-07-19 01:49:23 -07:00
get_futex_key_refs ( & key ) ;
2007-07-26 10:41:03 -07:00
/* If the Guest specified an interrupt of 0, that means they want to
* unregister this array of " struct lguest_dma " s . */
2007-07-19 01:49:23 -07:00
if ( interrupt = = 0 )
ret = unbind_dma ( lg , & key , dmas ) ;
else {
2007-07-26 10:41:03 -07:00
/* Look through this Guest's dma array for an unused entry. */
2007-07-19 01:49:23 -07:00
for ( i = 0 ; i < LGUEST_MAX_DMA ; i + + ) {
2007-07-26 10:41:03 -07:00
/* If the interrupt is non-zero, the entry is already
* used . */
2007-07-19 01:49:23 -07:00
if ( lg - > dma [ i ] . interrupt )
continue ;
2007-07-26 10:41:03 -07:00
/* OK, a free one! Fill on our details. */
2007-07-19 01:49:23 -07:00
lg - > dma [ i ] . dmas = dmas ;
lg - > dma [ i ] . num_dmas = numdmas ;
lg - > dma [ i ] . next_dma = 0 ;
lg - > dma [ i ] . key = key ;
lg - > dma [ i ] . guestid = lg - > guestid ;
lg - > dma [ i ] . interrupt = interrupt ;
2007-07-26 10:41:03 -07:00
/* Now we add it to the hash table: the position
* depends on the futex key that we got . */
2007-07-19 01:49:23 -07:00
list_add ( & lg - > dma [ i ] . list , & dma_hash [ hash ( & key ) ] ) ;
2007-07-26 10:41:03 -07:00
/* Success! */
2007-07-19 01:49:23 -07:00
ret = 1 ;
goto unlock ;
}
}
2007-07-26 10:41:03 -07:00
/* If we didn't find a slot to put the key in, drop the reference
* again . */
2007-07-19 01:49:23 -07:00
drop_futex_key_refs ( & key ) ;
unlock :
2007-07-26 10:41:03 -07:00
/* Unlock and out. */
2007-07-19 01:49:23 -07:00
up_read ( fshared ) ;
mutex_unlock ( & lguest_lock ) ;
return ret ;
}
2007-07-26 10:41:03 -07:00
/*L:385 Note that our routines to access a different Guest's memory are called
* lgread_other ( ) and lgwrite_other ( ) : these names emphasize that they are only
* used when the Guest is * not * the current Guest .
*
* The interface for copying from another process ' s memory is called
* access_process_vm ( ) , with a final argument of 0 for a read , and 1 for a
* write .
*
* We need lgread_other ( ) to read the destination Guest ' s " struct lguest_dma "
* array . */
2007-07-19 01:49:23 -07:00
static int lgread_other ( struct lguest * lg ,
void * buf , u32 addr , unsigned bytes )
{
if ( ! lguest_address_ok ( lg , addr , bytes )
| | access_process_vm ( lg - > tsk , addr , buf , bytes , 0 ) ! = bytes ) {
memset ( buf , 0 , bytes ) ;
kill_guest ( lg , " bad address in registered DMA struct " ) ;
return 0 ;
}
return 1 ;
}
2007-07-26 10:41:03 -07:00
/* "lgwrite()" to another Guest: used to update the destination "used_len" once
* we ' ve transferred data into the buffer . */
2007-07-19 01:49:23 -07:00
static int lgwrite_other ( struct lguest * lg , u32 addr ,
const void * buf , unsigned bytes )
{
if ( ! lguest_address_ok ( lg , addr , bytes )
| | ( access_process_vm ( lg - > tsk , addr , ( void * ) buf , bytes , 1 )
! = bytes ) ) {
kill_guest ( lg , " bad address writing to registered DMA " ) ;
return 0 ;
}
return 1 ;
}
2007-07-26 10:41:03 -07:00
/*L:400 This is the generic engine which copies from a source "struct
* lguest_dma " from this Guest into another Guest's " struct lguest_dma " . The
* destination Guest ' s pages have already been mapped , as contained in the
* pages array .
*
* If you ' re wondering if there ' s a nice " copy from one process to another "
* routine , so was I . But Linux isn ' t really set up to copy between two
* unrelated processes , so we have to write it ourselves .
*/
2007-07-19 01:49:23 -07:00
static u32 copy_data ( struct lguest * srclg ,
const struct lguest_dma * src ,
const struct lguest_dma * dst ,
struct page * pages [ ] )
{
unsigned int totlen , si , di , srcoff , dstoff ;
void * maddr = NULL ;
2007-07-26 10:41:03 -07:00
/* We return the total length transferred. */
2007-07-19 01:49:23 -07:00
totlen = 0 ;
2007-07-26 10:41:03 -07:00
/* We keep indexes into the source and destination "struct lguest_dma",
* and an offset within each region . */
2007-07-19 01:49:23 -07:00
si = di = 0 ;
srcoff = dstoff = 0 ;
2007-07-26 10:41:03 -07:00
/* We loop until the source or destination is exhausted. */
2007-07-19 01:49:23 -07:00
while ( si < LGUEST_MAX_DMA_SECTIONS & & src - > len [ si ]
& & di < LGUEST_MAX_DMA_SECTIONS & & dst - > len [ di ] ) {
2007-07-26 10:41:03 -07:00
/* We can only transfer the rest of the src buffer, or as much
* as will fit into the destination buffer . */
2007-07-19 01:49:23 -07:00
u32 len = min ( src - > len [ si ] - srcoff , dst - > len [ di ] - dstoff ) ;
2007-07-26 10:41:03 -07:00
/* For systems using "highmem" we need to use kmap() to access
* the page we want . We often use the same page over and over ,
* so rather than kmap ( ) it on every loop , we set the maddr
* pointer to NULL when we need to move to the next
* destination page . */
2007-07-19 01:49:23 -07:00
if ( ! maddr )
maddr = kmap ( pages [ di ] ) ;
2007-07-26 10:41:03 -07:00
/* Copy directly from (this Guest's) source address to the
* destination Guest ' s kmap ( ) ed buffer . Note that maddr points
* to the start of the page : we need to add the offset of the
* destination address and offset within the buffer . */
/* FIXME: This is not completely portable. I looked at
* copy_to_user_page ( ) , and some arch ' s seem to need special
* flushes . x86 is fine . */
2007-07-19 01:49:23 -07:00
if ( copy_from_user ( maddr + ( dst - > addr [ di ] + dstoff ) % PAGE_SIZE ,
2007-07-20 16:10:24 +01:00
( void __user * ) src - > addr [ si ] , len ) ! = 0 ) {
2007-07-26 10:41:03 -07:00
/* If a copy failed, it's the source's fault. */
2007-07-19 01:49:23 -07:00
kill_guest ( srclg , " bad address in sending DMA " ) ;
totlen = 0 ;
break ;
}
2007-07-26 10:41:03 -07:00
/* Increment the total and src & dst offsets */
2007-07-19 01:49:23 -07:00
totlen + = len ;
srcoff + = len ;
dstoff + = len ;
2007-07-26 10:41:03 -07:00
/* Presumably we reached the end of the src or dest buffers: */
2007-07-19 01:49:23 -07:00
if ( srcoff = = src - > len [ si ] ) {
2007-07-26 10:41:03 -07:00
/* Move to the next buffer at offset 0 */
2007-07-19 01:49:23 -07:00
si + + ;
srcoff = 0 ;
}
if ( dstoff = = dst - > len [ di ] ) {
2007-07-26 10:41:03 -07:00
/* We need to unmap that destination page and reset
* maddr ready for the next one . */
2007-07-19 01:49:23 -07:00
kunmap ( pages [ di ] ) ;
maddr = NULL ;
di + + ;
dstoff = 0 ;
}
}
2007-07-26 10:41:03 -07:00
/* If we still had a page mapped at the end, unmap now. */
2007-07-19 01:49:23 -07:00
if ( maddr )
kunmap ( pages [ di ] ) ;
return totlen ;
}
2007-07-26 10:41:03 -07:00
/*L:390 This is how we transfer a "struct lguest_dma" from the source Guest
* ( the current Guest which called SEND_DMA ) to another Guest . */
2007-07-19 01:49:23 -07:00
static u32 do_dma ( struct lguest * srclg , const struct lguest_dma * src ,
struct lguest * dstlg , const struct lguest_dma * dst )
{
int i ;
u32 ret ;
struct page * pages [ LGUEST_MAX_DMA_SECTIONS ] ;
2007-07-26 10:41:03 -07:00
/* We check that both source and destination "struct lguest_dma"s are
* within the bounds of the source and destination Guests */
2007-07-19 01:49:23 -07:00
if ( ! check_dma_list ( dstlg , dst ) | | ! check_dma_list ( srclg , src ) )
return 0 ;
2007-07-26 10:41:03 -07:00
/* We need to map the pages which correspond to each parts of
* destination buffer . */
2007-07-19 01:49:23 -07:00
for ( i = 0 ; i < LGUEST_MAX_DMA_SECTIONS ; i + + ) {
if ( dst - > len [ i ] = = 0 )
break ;
2007-07-26 10:41:03 -07:00
/* get_user_pages() is a complicated function, especially since
* we only want a single page . But it works , and returns the
* number of pages . Note that we ' re holding the destination ' s
* mmap_sem , as get_user_pages ( ) requires . */
2007-07-19 01:49:23 -07:00
if ( get_user_pages ( dstlg - > tsk , dstlg - > mm ,
dst - > addr [ i ] , 1 , 1 , 1 , pages + i , NULL )
! = 1 ) {
2007-07-26 10:41:03 -07:00
/* This means the destination gave us a bogus buffer */
2007-07-19 01:49:23 -07:00
kill_guest ( dstlg , " Error mapping DMA pages " ) ;
ret = 0 ;
goto drop_pages ;
}
}
2007-07-26 10:41:03 -07:00
/* Now copy the data until we run out of src or dst. */
2007-07-19 01:49:23 -07:00
ret = copy_data ( srclg , src , dst , pages ) ;
drop_pages :
while ( - - i > = 0 )
put_page ( pages [ i ] ) ;
return ret ;
}
2007-07-26 10:41:03 -07:00
/*L:380 Transferring data from one Guest to another is not as simple as I'd
* like . We ' ve found the " struct lguest_dma_info " bound to the same address as
* the send , we need to copy into it .
*
* This function returns true if the destination array was empty . */
2007-07-19 01:49:23 -07:00
static int dma_transfer ( struct lguest * srclg ,
unsigned long udma ,
struct lguest_dma_info * dst )
{
struct lguest_dma dst_dma , src_dma ;
struct lguest * dstlg ;
u32 i , dma = 0 ;
2007-07-26 10:41:03 -07:00
/* From the "struct lguest_dma_info" we found in the hash, grab the
* Guest . */
2007-07-19 01:49:23 -07:00
dstlg = & lguests [ dst - > guestid ] ;
2007-07-26 10:41:03 -07:00
/* Read in the source "struct lguest_dma" handed to SEND_DMA. */
2007-07-19 01:49:23 -07:00
lgread ( srclg , & src_dma , udma , sizeof ( src_dma ) ) ;
2007-07-26 10:41:03 -07:00
/* We need the destination's mmap_sem, and we already hold the source's
* mmap_sem for the futex key lookup . Normally this would suggest that
* we could deadlock if the destination Guest was trying to send to
* this source Guest at the same time , which is another reason that all
* I / O is done under the big lguest_lock . */
2007-07-19 01:49:23 -07:00
down_read ( & dstlg - > mm - > mmap_sem ) ;
2007-07-26 10:41:03 -07:00
/* Look through the destination DMA array for an available buffer. */
2007-07-19 01:49:23 -07:00
for ( i = 0 ; i < dst - > num_dmas ; i + + ) {
2007-07-26 10:41:03 -07:00
/* We keep a "next_dma" pointer which often helps us avoid
* looking at lots of previously - filled entries . */
2007-07-19 01:49:23 -07:00
dma = ( dst - > next_dma + i ) % dst - > num_dmas ;
if ( ! lgread_other ( dstlg , & dst_dma ,
dst - > dmas + dma * sizeof ( struct lguest_dma ) ,
sizeof ( dst_dma ) ) ) {
goto fail ;
}
if ( ! dst_dma . used_len )
break ;
}
2007-07-26 10:41:03 -07:00
/* If we found a buffer, we do the actual data copy. */
2007-07-19 01:49:23 -07:00
if ( i ! = dst - > num_dmas ) {
unsigned long used_lenp ;
unsigned int ret ;
ret = do_dma ( srclg , & src_dma , dstlg , & dst_dma ) ;
2007-07-26 10:41:03 -07:00
/* Put used length in the source "struct lguest_dma"'s used_len
* field . It ' s a little tricky to figure out where that is ,
* though . */
2007-07-19 01:49:23 -07:00
lgwrite_u32 ( srclg ,
udma + offsetof ( struct lguest_dma , used_len ) , ret ) ;
2007-07-26 10:41:03 -07:00
/* Tranferring 0 bytes is OK if the source buffer was empty. */
2007-07-19 01:49:23 -07:00
if ( ret = = 0 & & src_dma . len [ 0 ] ! = 0 )
goto fail ;
2007-07-26 10:41:03 -07:00
/* The destination Guest might be running on a different CPU:
* we have to make sure that it will see the " used_len " field
* change to non - zero * after * it sees the data we copied into
* the buffer . Hence a write memory barrier . */
2007-07-19 01:49:23 -07:00
wmb ( ) ;
2007-07-26 10:41:03 -07:00
/* Figuring out where the destination's used_len field for this
* " struct lguest_dma " in the array is also a little ugly . */
2007-07-19 01:49:23 -07:00
used_lenp = dst - > dmas
+ dma * sizeof ( struct lguest_dma )
+ offsetof ( struct lguest_dma , used_len ) ;
lgwrite_other ( dstlg , used_lenp , & ret , sizeof ( ret ) ) ;
2007-07-26 10:41:03 -07:00
/* Move the cursor for next time. */
2007-07-19 01:49:23 -07:00
dst - > next_dma + + ;
}
up_read ( & dstlg - > mm - > mmap_sem ) ;
2007-07-26 10:41:03 -07:00
/* We trigger the destination interrupt, even if the destination was
* empty and we didn ' t transfer anything : this gives them a chance to
* wake up and refill . */
2007-07-19 01:49:23 -07:00
set_bit ( dst - > interrupt , dstlg - > irqs_pending ) ;
2007-07-26 10:41:03 -07:00
/* Wake up the destination process. */
2007-07-19 01:49:23 -07:00
wake_up_process ( dstlg - > tsk ) ;
2007-07-26 10:41:03 -07:00
/* If we passed the last "struct lguest_dma", the receive had no
* buffers left . */
2007-07-19 01:49:23 -07:00
return i = = dst - > num_dmas ;
fail :
up_read ( & dstlg - > mm - > mmap_sem ) ;
return 0 ;
}
2007-07-26 10:41:03 -07:00
/*L:370 This is the counter-side to the BIND_DMA hypercall; the SEND_DMA
* hypercall . We find out who ' s listening , and send to them . */
2007-07-19 01:49:23 -07:00
void send_dma ( struct lguest * lg , unsigned long ukey , unsigned long udma )
{
union futex_key key ;
int empty = 0 ;
struct rw_semaphore * fshared = & current - > mm - > mmap_sem ;
again :
mutex_lock ( & lguest_lock ) ;
down_read ( fshared ) ;
2007-07-26 10:41:03 -07:00
/* Get the futex key for the key the Guest gave us */
2007-07-19 01:49:23 -07:00
if ( get_futex_key ( ( u32 __user * ) ukey , fshared , & key ) ! = 0 ) {
kill_guest ( lg , " bad sending DMA key " ) ;
goto unlock ;
}
2007-07-26 10:41:03 -07:00
/* Since the key must be a multiple of 4, the futex key uses the lower
* bit of the " offset " field ( which would always be 0 ) to indicate a
* mapping which is shared with other processes ( ie . Guests ) . */
2007-07-19 01:49:23 -07:00
if ( key . shared . offset & 1 ) {
struct lguest_dma_info * i ;
2007-07-26 10:41:03 -07:00
/* Look through the hash for other Guests. */
2007-07-19 01:49:23 -07:00
list_for_each_entry ( i , & dma_hash [ hash ( & key ) ] , list ) {
2007-07-26 10:41:03 -07:00
/* Don't send to ourselves. */
2007-07-19 01:49:23 -07:00
if ( i - > guestid = = lg - > guestid )
continue ;
if ( ! key_eq ( & key , & i - > key ) )
continue ;
2007-07-26 10:41:03 -07:00
/* If dma_transfer() tells us the destination has no
* available buffers , we increment " empty " . */
2007-07-19 01:49:23 -07:00
empty + = dma_transfer ( lg , udma , i ) ;
break ;
}
2007-07-26 10:41:03 -07:00
/* If the destination is empty, we release our locks and
* give the destination Guest a brief chance to restock . */
2007-07-19 01:49:23 -07:00
if ( empty = = 1 ) {
/* Give any recipients one chance to restock. */
up_read ( & current - > mm - > mmap_sem ) ;
mutex_unlock ( & lguest_lock ) ;
2007-07-26 10:41:03 -07:00
/* Next time, we won't try again. */
2007-07-19 01:49:23 -07:00
empty + + ;
goto again ;
}
} else {
2007-07-26 10:41:03 -07:00
/* Private mapping: Guest is sending to its Launcher. We set
* the " dma_is_pending " flag so that the main loop will exit
* and the Launcher ' s read ( ) from / dev / lguest will return . */
2007-07-19 01:49:23 -07:00
lg - > dma_is_pending = 1 ;
lg - > pending_dma = udma ;
lg - > pending_key = ukey ;
}
unlock :
up_read ( fshared ) ;
mutex_unlock ( & lguest_lock ) ;
}
2007-07-26 10:41:03 -07:00
/*:*/
2007-07-19 01:49:23 -07:00
void release_all_dma ( struct lguest * lg )
{
unsigned int i ;
BUG_ON ( ! mutex_is_locked ( & lguest_lock ) ) ;
down_read ( & lg - > mm - > mmap_sem ) ;
for ( i = 0 ; i < LGUEST_MAX_DMA ; i + + ) {
if ( lg - > dma [ i ] . interrupt )
unlink_dma ( & lg - > dma [ i ] ) ;
}
up_read ( & lg - > mm - > mmap_sem ) ;
}
2007-07-26 10:41:05 -07:00
/*M:007 We only return a single DMA buffer to the Launcher, but it would be
* more efficient to return a pointer to the entire array of DMA buffers , which
* it can cache and choose one whenever it wants .
*
* Currently the Launcher uses a write to / dev / lguest , and the return value is
* the address of the DMA structure with the interrupt number placed in
* dma - > used_len . If we wanted to return the entire array , we need to return
* the address , array size and interrupt number : this seems to require an
* ioctl ( ) . : */
2007-07-26 10:41:03 -07:00
/*L:320 This routine looks for a DMA buffer registered by the Guest on the
* given key ( using the BIND_DMA hypercall ) . */
2007-07-19 01:49:23 -07:00
unsigned long get_dma_buffer ( struct lguest * lg ,
unsigned long ukey , unsigned long * interrupt )
{
unsigned long ret = 0 ;
union futex_key key ;
struct lguest_dma_info * i ;
struct rw_semaphore * fshared = & current - > mm - > mmap_sem ;
2007-07-26 10:41:03 -07:00
/* Take the Big Lguest Lock to stop other Guests sending this Guest DMA
* at the same time . */
2007-07-19 01:49:23 -07:00
mutex_lock ( & lguest_lock ) ;
2007-07-26 10:41:03 -07:00
/* To match between Guests sharing the same underlying memory we steal
* code from the futex infrastructure . This requires that we hold the
* " mmap_sem " for our process ( the Launcher ) , and pass it to the futex
* code . */
2007-07-19 01:49:23 -07:00
down_read ( fshared ) ;
2007-07-26 10:41:03 -07:00
/* This can fail if it's not a valid address, or if the address is not
* divisible by 4 ( the futex code needs that , we don ' t really ) . */
2007-07-19 01:49:23 -07:00
if ( get_futex_key ( ( u32 __user * ) ukey , fshared , & key ) ! = 0 ) {
kill_guest ( lg , " bad registered DMA buffer " ) ;
goto unlock ;
}
2007-07-26 10:41:03 -07:00
/* Search the hash table for matching entries (the Launcher can only
* send to its own Guest for the moment , so the entry must be for this
* Guest ) */
2007-07-19 01:49:23 -07:00
list_for_each_entry ( i , & dma_hash [ hash ( & key ) ] , list ) {
if ( key_eq ( & key , & i - > key ) & & i - > guestid = = lg - > guestid ) {
unsigned int j ;
2007-07-26 10:41:03 -07:00
/* Look through the registered DMA array for an
* available buffer . */
2007-07-19 01:49:23 -07:00
for ( j = 0 ; j < i - > num_dmas ; j + + ) {
struct lguest_dma dma ;
ret = i - > dmas + j * sizeof ( struct lguest_dma ) ;
lgread ( lg , & dma , ret , sizeof ( dma ) ) ;
if ( dma . used_len = = 0 )
break ;
}
2007-07-26 10:41:03 -07:00
/* Store the interrupt the Guest wants when the buffer
* is used . */
2007-07-19 01:49:23 -07:00
* interrupt = i - > interrupt ;
break ;
}
}
unlock :
up_read ( fshared ) ;
mutex_unlock ( & lguest_lock ) ;
return ret ;
}
2007-07-26 10:41:03 -07:00
/*:*/
2007-07-19 01:49:23 -07:00
2007-07-26 10:41:03 -07:00
/*L:410 This really has completed the Launcher. Not only have we now finished
* the longest chapter in our journey , but this also means we are over halfway
* through !
*
* Enough prevaricating around the bush : it is time for us to dive into the
* core of the Host , in " make Host " .
*/