@ -78,24 +78,39 @@ uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq)
* @ vaddr : Translated IOVA addresses
* @ vaddr : Translated IOVA addresses
* @ iovec : Source qemu ' s VA addresses
* @ iovec : Source qemu ' s VA addresses
* @ num : Length of iovec and minimum length of vaddr
* @ num : Length of iovec and minimum length of vaddr
* @ gpas : Descriptors ' GPAs , if backed by guest memory
*/
*/
static bool vhost_svq_translate_addr ( const VhostShadowVirtqueue * svq ,
static bool vhost_svq_translate_addr ( const VhostShadowVirtqueue * svq ,
hwaddr * addrs , const struct iovec * iovec ,
hwaddr * addrs , const struct iovec * iovec ,
size_t num )
size_t num , const hwaddr * gpas )
{
{
if ( num = = 0 ) {
if ( num = = 0 ) {
return true ;
return true ;
}
}
for ( size_t i = 0 ; i < num ; + + i ) {
for ( size_t i = 0 ; i < num ; + + i ) {
DMAMap needle = {
. translated_addr = ( hwaddr ) ( uintptr_t ) iovec [ i ] . iov_base ,
. size = iovec [ i ] . iov_len ,
} ;
Int128 needle_last , map_last ;
Int128 needle_last , map_last ;
size_t off ;
size_t off ;
const DMAMap * map ;
DMAMap needle ;
/* Check if the descriptor is backed by guest memory */
if ( gpas ) {
/* Search the GPA->IOVA tree */
needle = ( DMAMap ) {
. translated_addr = gpas [ i ] ,
. size = iovec [ i ] . iov_len ,
} ;
map = vhost_iova_tree_find_gpa ( svq - > iova_tree , & needle ) ;
} else {
/* Search the IOVA->HVA tree */
needle = ( DMAMap ) {
. translated_addr = ( hwaddr ) ( uintptr_t ) iovec [ i ] . iov_base ,
. size = iovec [ i ] . iov_len ,
} ;
map = vhost_iova_tree_find_iova ( svq - > iova_tree , & needle ) ;
}
const DMAMap * map = vhost_iova_tree_find_iova ( svq - > iova_tree , & needle ) ;
/*
/*
* Map cannot be NULL since iova map contains all guest space and
* Map cannot be NULL since iova map contains all guest space and
* qemu already has a physical address mapped
* qemu already has a physical address mapped
@ -130,6 +145,7 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq,
* @ sg : Cache for hwaddr
* @ sg : Cache for hwaddr
* @ iovec : The iovec from the guest
* @ iovec : The iovec from the guest
* @ num : iovec length
* @ num : iovec length
* @ addr : Descriptors ' GPAs , if backed by guest memory
* @ more_descs : True if more descriptors come in the chain
* @ more_descs : True if more descriptors come in the chain
* @ write : True if they are writeable descriptors
* @ write : True if they are writeable descriptors
*
*
@ -137,7 +153,8 @@ static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq,
*/
*/
static bool vhost_svq_vring_write_descs ( VhostShadowVirtqueue * svq , hwaddr * sg ,
static bool vhost_svq_vring_write_descs ( VhostShadowVirtqueue * svq , hwaddr * sg ,
const struct iovec * iovec , size_t num ,
const struct iovec * iovec , size_t num ,
bool more_descs , bool write )
const hwaddr * addr , bool more_descs ,
bool write )
{
{
uint16_t i = svq - > free_head , last = svq - > free_head ;
uint16_t i = svq - > free_head , last = svq - > free_head ;
unsigned n ;
unsigned n ;
@ -149,7 +166,7 @@ static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
return true ;
return true ;
}
}
ok = vhost_svq_translate_addr ( svq , sg , iovec , num ) ;
ok = vhost_svq_translate_addr ( svq , sg , iovec , num , addr ) ;
if ( unlikely ( ! ok ) ) {
if ( unlikely ( ! ok ) ) {
return false ;
return false ;
}
}
@ -174,8 +191,9 @@ static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
static bool vhost_svq_add_split ( VhostShadowVirtqueue * svq ,
static bool vhost_svq_add_split ( VhostShadowVirtqueue * svq ,
const struct iovec * out_sg , size_t out_num ,
const struct iovec * out_sg , size_t out_num ,
const hwaddr * out_addr ,
const struct iovec * in_sg , size_t in_num ,
const struct iovec * in_sg , size_t in_num ,
unsigned * head )
const hwaddr * in_addr , unsigned * head )
{
{
unsigned avail_idx ;
unsigned avail_idx ;
vring_avail_t * avail = svq - > vring . avail ;
vring_avail_t * avail = svq - > vring . avail ;
@ -191,13 +209,14 @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
return false ;
return false ;
}
}
ok = vhost_svq_vring_write_descs ( svq , sgs , out_sg , out_num , in_num > 0 ,
ok = vhost_svq_vring_write_descs ( svq , sgs , out_sg , out_num , out_addr ,
false ) ;
in_num > 0 , false ) ;
if ( unlikely ( ! ok ) ) {
if ( unlikely ( ! ok ) ) {
return false ;
return false ;
}
}
ok = vhost_svq_vring_write_descs ( svq , sgs , in_sg , in_num , false , true ) ;
ok = vhost_svq_vring_write_descs ( svq , sgs , in_sg , in_num , in_addr , false ,
true ) ;
if ( unlikely ( ! ok ) ) {
if ( unlikely ( ! ok ) ) {
return false ;
return false ;
}
}
@ -247,8 +266,9 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq)
* Return - EINVAL if element is invalid , - ENOSPC if dev queue is full
* Return - EINVAL if element is invalid , - ENOSPC if dev queue is full
*/
*/
int vhost_svq_add ( VhostShadowVirtqueue * svq , const struct iovec * out_sg ,
int vhost_svq_add ( VhostShadowVirtqueue * svq , const struct iovec * out_sg ,
size_t out_num , const struct iovec * in_sg , size_t in_num ,
size_t out_num , const hwaddr * out_addr ,
VirtQueueElement * elem )
const struct iovec * in_sg , size_t in_num ,
const hwaddr * in_addr , VirtQueueElement * elem )
{
{
unsigned qemu_head ;
unsigned qemu_head ;
unsigned ndescs = in_num + out_num ;
unsigned ndescs = in_num + out_num ;
@ -258,7 +278,8 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
return - ENOSPC ;
return - ENOSPC ;
}
}
ok = vhost_svq_add_split ( svq , out_sg , out_num , in_sg , in_num , & qemu_head ) ;
ok = vhost_svq_add_split ( svq , out_sg , out_num , out_addr , in_sg , in_num ,
in_addr , & qemu_head ) ;
if ( unlikely ( ! ok ) ) {
if ( unlikely ( ! ok ) ) {
return - EINVAL ;
return - EINVAL ;
}
}
@ -274,8 +295,8 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
static int vhost_svq_add_element ( VhostShadowVirtqueue * svq ,
static int vhost_svq_add_element ( VhostShadowVirtqueue * svq ,
VirtQueueElement * elem )
VirtQueueElement * elem )
{
{
return vhost_svq_add ( svq , elem - > out_sg , elem - > out_num , elem - > in_sg ,
return vhost_svq_add ( svq , elem - > out_sg , elem - > out_num , elem - > out_addr ,
elem - > in_num , elem ) ;
elem - > in_sg , elem - > in_ num , elem - > in_addr , elem ) ;
}
}
/**
/**