diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index a755a67127b6..08c28f909431 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -182,6 +182,19 @@ Permit Xen to use "Always Running APIC Timer" support on compatible hardware in combination with cpuidle. This option is only expected to be useful for developers wishing Xen to fall back to older timing methods on newer hardware. +### argo +> `= ` + +> Default: `false` + +Enable the Argo hypervisor-mediated interdomain communication mechanism. + +Only available if Xen is compiled with `CONFIG_ARGO` enabled. + +This allows domains access to the Argo hypercall, which supports registration +of memory rings with the hypervisor to receive messages, sending messages to +other domains by hypercall and querying the ring status of other domains. + ### asid (x86) > `= ` diff --git a/xen/common/Makefile b/xen/common/Makefile index 8c65c6f0527c..88b9b2f0464b 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -70,7 +70,7 @@ obj-y += xmalloc_tlsf.o obj-bin-$(CONFIG_X86) += $(foreach n,decompress bunzip2 unxz unlzma unlzo unlz4 earlycpio,$(n).init.o) -obj-$(CONFIG_COMPAT) += $(addprefix compat/,domain.o kernel.o memory.o multicall.o xlat.o) +obj-$(CONFIG_COMPAT) += $(addprefix compat/,argo.o domain.o kernel.o memory.o multicall.o xlat.o) tmem-y := tmem.o tmem_xen.o tmem_control.o tmem-$(CONFIG_COMPAT) += compat/tmem_xen.o diff --git a/xen/common/argo.c b/xen/common/argo.c index 6f782f7e1f90..1958fdc8e428 100644 --- a/xen/common/argo.c +++ b/xen/common/argo.c @@ -16,8 +16,223 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include +#include #include +#include #include +#include +#include +#include + +#include + +DEFINE_XEN_GUEST_HANDLE(xen_argo_addr_t); +DEFINE_XEN_GUEST_HANDLE(xen_argo_ring_t); + +/* Xen command line option to enable argo */ +static bool __read_mostly opt_argo_enabled; +boolean_param("argo", opt_argo_enabled); + +typedef struct argo_ring_id +{ + xen_argo_port_t aport; + domid_t partner_id; + domid_t domain_id; +} argo_ring_id; + +/* Data about a domain's own ring that it has registered */ +struct argo_ring_info +{ + /* next node in the hash, protected by rings_L2 */ + struct hlist_node node; + /* this ring's id, protected by rings_L2 */ + struct argo_ring_id id; + /* L3, the ring_info lock: protects the members of this struct below */ + spinlock_t L3_lock; + /* length of the ring, protected by L3 */ + unsigned int len; + /* number of pages translated into mfns, protected by L3 */ + unsigned int nmfns; + /* cached tx pointer location, protected by L3 */ + unsigned int tx_ptr; + /* mapped ring pages protected by L3 */ + void **mfn_mapping; + /* list of mfns of guest ring, protected by L3 */ + mfn_t *mfns; + /* list of struct pending_ent for this ring, protected by L3 */ + struct hlist_head pending; + /* number of pending entries queued for this ring, protected by L3 */ + unsigned int npending; +}; + +/* Data about a single-sender ring, held by the sender (partner) domain */ +struct argo_send_info +{ + /* next node in the hash, protected by send_L2 */ + struct hlist_node node; + /* this ring's id, protected by send_L2 */ + struct argo_ring_id id; +}; + +/* A space-available notification that is awaiting sufficient space */ +struct pending_ent +{ + /* List node within argo_ring_info's pending list */ + struct hlist_node node; + /* + * List node within argo_domain's wildcard_pend_list. Only used if the + * ring is one with a wildcard partner (ie. that any domain may send to) + * to enable cancelling signals on wildcard rings on domain destroy. + */ + struct hlist_node wildcard_node; + /* + * Pointer to the ring_info that this ent pertains to. Used to ensure that + * ring_info->npending is decremented when ents for wildcard rings are + * cancelled for domain destroy. + * Caution: Must hold the correct locks before accessing ring_info via this. + */ + struct argo_ring_info *ring_info; + /* minimum ring space available that this signal is waiting upon */ + unsigned int len; + /* domain to be notified when space is available */ + domid_t domain_id; +}; + +/* + * The value of the argo element in a struct domain is + * protected by L1_global_argo_rwlock + */ +#define ARGO_HTABLE_SIZE 32 +struct argo_domain +{ + /* rings_L2 */ + rwlock_t rings_L2_rwlock; + /* + * Hash table of argo_ring_info about rings this domain has registered. + * Protected by rings_L2. + */ + struct hlist_head ring_hash[ARGO_HTABLE_SIZE]; + /* Counter of rings registered by this domain. Protected by rings_L2. */ + unsigned int ring_count; + + /* send_L2 */ + spinlock_t send_L2_lock; + /* + * Hash table of argo_send_info about rings other domains have registered + * for this domain to send to. Single partner, non-wildcard rings. + * Protected by send_L2. + */ + struct hlist_head send_hash[ARGO_HTABLE_SIZE]; + + /* wildcard_L2 */ + spinlock_t wildcard_L2_lock; + /* + * List of pending space-available signals for this domain about wildcard + * rings registered by other domains. Protected by wildcard_L2. + */ + struct hlist_head wildcard_pend_list; +}; + +/* + * Locking is organized as follows: + * + * Terminology: R() means taking a read lock on the specified lock; + * W() means taking a write lock on it. + * + * == L1 : The global read/write lock: L1_global_argo_rwlock + * Protects the argo elements of all struct domain *d in the system. + * It does not protect any of the elements of d->argo, only their + * addresses. + * + * By extension since the destruction of a domain with a non-NULL + * d->argo will need to free the d->argo pointer, holding W(L1) + * guarantees that no domains pointers that argo is interested in + * become invalid whilst this lock is held. + */ + +static DEFINE_RWLOCK(L1_global_argo_rwlock); /* L1 */ + +/* + * == rings_L2 : The per-domain ring hash lock: d->argo->rings_L2_rwlock + * + * Holding a read lock on rings_L2 protects the ring hash table and + * the elements in the hash_table d->argo->ring_hash, and + * the node and id fields in struct argo_ring_info in the + * hash table. + * Holding a write lock on rings_L2 protects all of the elements of all the + * struct argo_ring_info belonging to this domain. + * + * To take rings_L2 you must already have R(L1). W(L1) implies W(rings_L2) and + * L3. + * + * == L3 : The individual ring_info lock: ring_info->L3_lock + * + * Protects all the fields within the argo_ring_info, aside from the ones that + * rings_L2 already protects: node, id, lock. + * + * To acquire L3 you must already have R(rings_L2). W(rings_L2) implies L3. + * + * == send_L2 : The per-domain single-sender partner rings lock: + * d->argo->send_L2_lock + * + * Protects the per-domain send hash table : d->argo->send_hash + * and the elements in the hash table, and the node and id fields + * in struct argo_send_info in the hash table. + * + * To take send_L2, you must already have R(L1). W(L1) implies send_L2. + * Do not attempt to acquire a rings_L2 on any domain after taking and while + * holding a send_L2 lock -- acquire the rings_L2 (if one is needed) beforehand. + * + * == wildcard_L2 : The per-domain wildcard pending list lock: + * d->argo->wildcard_L2_lock + * + * Protects the per-domain list of outstanding signals for space availability + * on wildcard rings. + * + * To take wildcard_L2, you must already have R(L1). W(L1) implies wildcard_L2. + * No other locks are acquired after obtaining wildcard_L2. + */ + +/* + * Lock state validations macros + * + * These macros encode the logic to verify that the locking has adhered to the + * locking discipline above. + * eg. On entry to logic that requires holding at least R(rings_L2), this: + * ASSERT(LOCKING_Read_rings_L2(d)); + * + * checks that the lock state is sufficient, validating that one of the + * following must be true when executed: R(rings_L2) && R(L1) + * or: W(rings_L2) && R(L1) + * or: W(L1) + */ + +/* RAW macros here are only used to assist defining the other macros below */ +#define RAW_LOCKING_Read_L1 (rw_is_locked(&L1_global_argo_rwlock)) +#define RAW_LOCKING_Read_rings_L2(d) \ + (rw_is_locked(&d->argo->rings_L2_rwlock) && RAW_LOCKING_Read_L1) + +/* The LOCKING macros defined below here are for use at verification points */ +#define LOCKING_Write_L1 (rw_is_write_locked(&L1_global_argo_rwlock)) +#define LOCKING_Read_L1 (RAW_LOCKING_Read_L1 || LOCKING_Write_L1) + +#define LOCKING_Write_rings_L2(d) \ + ((RAW_LOCKING_Read_L1 && rw_is_write_locked(&d->argo->rings_L2_rwlock)) || \ + LOCKING_Write_L1) + +#define LOCKING_Read_rings_L2(d) \ + ((RAW_LOCKING_Read_L1 && rw_is_locked(&d->argo->rings_L2_rwlock)) || \ + LOCKING_Write_rings_L2(d) || LOCKING_Write_L1) + +#define LOCKING_L3(d, r) \ + ((RAW_LOCKING_Read_rings_L2(d) && spin_is_locked(&r->L3_lock)) || \ + LOCKING_Write_rings_L2(d) || LOCKING_Write_L1) + +#define LOCKING_send_L2(d) \ + ((RAW_LOCKING_Read_L1 && spin_is_locked(&d->argo->send_L2_lock)) || \ + LOCKING_Write_L1) /* Change this to #define ARGO_DEBUG here to enable more debug messages */ #undef ARGO_DEBUG @@ -28,10 +243,365 @@ #define argo_dprintk(format, ... ) ((void)0) #endif +/* + * FIXME for 4.12: + * * Replace this hash function to get better distribution across buckets. + * * Don't use casts in the replacement function. + * * Drop the use of array_index_nospec. + */ +/* + * This hash function is used to distribute rings within the per-domain + * hash tables (d->argo->ring_hash and d->argo_send_hash). The hash table + * will provide a struct if a match is found with a 'argo_ring_id' key: + * ie. the key is a (domain id, argo port, partner domain id) tuple. + * Since argo port number varies the most in expected use, and the Linux driver + * allocates at both the high and low ends, incorporate high and low bits to + * help with distribution. + * Apply array_index_nospec as a defensive measure since this operates + * on user-supplied input and the array size that it indexes into is known. + */ +static unsigned int +hash_index(const struct argo_ring_id *id) +{ + unsigned int hash; + + hash = (uint16_t)(id->aport >> 16); + hash ^= (uint16_t)id->aport; + hash ^= id->domain_id; + hash ^= id->partner_id; + hash &= (ARGO_HTABLE_SIZE - 1); + + return array_index_nospec(hash, ARGO_HTABLE_SIZE); +} + +static struct argo_ring_info * +find_ring_info(const struct domain *d, const struct argo_ring_id *id) +{ + unsigned int ring_hash_index; + struct hlist_node *node; + struct argo_ring_info *ring_info; + + ASSERT(LOCKING_Read_rings_L2(d)); + + ring_hash_index = hash_index(id); + + argo_dprintk("d->argo=%p, d->argo->ring_hash[%u]=%p id=%p\n", + d->argo, ring_hash_index, + d->argo->ring_hash[ring_hash_index].first, id); + argo_dprintk("id.aport=%x id.domain=vm%u id.partner_id=vm%u\n", + id->aport, id->domain_id, id->partner_id); + + hlist_for_each_entry(ring_info, node, &d->argo->ring_hash[ring_hash_index], + node) + { + const struct argo_ring_id *cmpid = &ring_info->id; + + if ( cmpid->aport == id->aport && + cmpid->domain_id == id->domain_id && + cmpid->partner_id == id->partner_id ) + { + argo_dprintk("ring_info=%p\n", ring_info); + return ring_info; + } + } + argo_dprintk("no ring_info found\n"); + + return NULL; +} + +static void +ring_unmap(const struct domain *d, struct argo_ring_info *ring_info) +{ + unsigned int i; + + ASSERT(LOCKING_L3(d, ring_info)); + + if ( !ring_info->mfn_mapping ) + return; + + for ( i = 0; i < ring_info->nmfns; i++ ) + { + if ( !ring_info->mfn_mapping[i] ) + continue; + if ( ring_info->mfns ) + argo_dprintk(XENLOG_ERR "argo: unmapping page %"PRI_mfn" from %p\n", + mfn_x(ring_info->mfns[i]), + ring_info->mfn_mapping[i]); + unmap_domain_page_global(ring_info->mfn_mapping[i]); + ring_info->mfn_mapping[i] = NULL; + } +} + +static void +wildcard_pending_list_remove(domid_t domain_id, struct pending_ent *ent) +{ + struct domain *d = get_domain_by_id(domain_id); + + if ( !d ) + return; + + ASSERT(LOCKING_Read_L1); + + if ( d->argo ) + { + spin_lock(&d->argo->wildcard_L2_lock); + hlist_del(&ent->wildcard_node); + spin_unlock(&d->argo->wildcard_L2_lock); + } + put_domain(d); +} + +static void +pending_remove_all(const struct domain *d, struct argo_ring_info *ring_info) +{ + struct hlist_node *node, *next; + struct pending_ent *ent; + + ASSERT(LOCKING_L3(d, ring_info)); + + hlist_for_each_entry_safe(ent, node, next, &ring_info->pending, node) + { + if ( ring_info->id.partner_id == XEN_ARGO_DOMID_ANY ) + wildcard_pending_list_remove(ent->domain_id, ent); + hlist_del(&ent->node); + xfree(ent); + } + ring_info->npending = 0; +} + +static void +wildcard_rings_pending_remove(struct domain *d) +{ + struct hlist_node *node, *next; + struct pending_ent *ent; + + ASSERT(LOCKING_Write_L1); + + hlist_for_each_entry_safe(ent, node, next, &d->argo->wildcard_pend_list, + node) + { + /* + * The ent->node deleted here, and the npending value decreased, + * belong to the ring_info of another domain, which is why this + * function requires holding W(L1): + * it implies the L3 lock that protects that ring_info struct. + */ + ent->ring_info->npending--; + hlist_del(&ent->node); + hlist_del(&ent->wildcard_node); + xfree(ent); + } +} + +static void +ring_remove_mfns(const struct domain *d, struct argo_ring_info *ring_info) +{ + unsigned int i; + + ASSERT(LOCKING_Write_rings_L2(d)); + + if ( !ring_info->mfns ) + return; + + if ( !ring_info->mfn_mapping ) + { + ASSERT_UNREACHABLE(); + return; + } + + ring_unmap(d, ring_info); + + for ( i = 0; i < ring_info->nmfns; i++ ) + if ( !mfn_eq(ring_info->mfns[i], INVALID_MFN) ) + put_page_and_type(mfn_to_page(ring_info->mfns[i])); + + ring_info->nmfns = 0; + XFREE(ring_info->mfns); + XFREE(ring_info->mfn_mapping); +} + +static void +ring_remove_info(const struct domain *d, struct argo_ring_info *ring_info) +{ + ASSERT(LOCKING_Write_rings_L2(d)); + + pending_remove_all(d, ring_info); + hlist_del(&ring_info->node); + ring_remove_mfns(d, ring_info); + xfree(ring_info); +} + +static void +domain_rings_remove_all(struct domain *d) +{ + unsigned int i; + + ASSERT(LOCKING_Write_rings_L2(d)); + + for ( i = 0; i < ARGO_HTABLE_SIZE; ++i ) + { + struct hlist_node *node, *next; + struct argo_ring_info *ring_info; + + hlist_for_each_entry_safe(ring_info, node, next, + &d->argo->ring_hash[i], node) + ring_remove_info(d, ring_info); + } + d->argo->ring_count = 0; +} + +/* + * Tear down all rings of other domains where src_d domain is the partner. + * (ie. it is the single domain that can send to those rings.) + * This will also cancel any pending notifications about those rings. + */ +static void +partner_rings_remove(struct domain *src_d) +{ + unsigned int i; + + ASSERT(LOCKING_Write_L1); + + for ( i = 0; i < ARGO_HTABLE_SIZE; ++i ) + { + struct hlist_node *node, *next; + struct argo_send_info *send_info; + + hlist_for_each_entry_safe(send_info, node, next, + &src_d->argo->send_hash[i], node) + { + struct argo_ring_info *ring_info; + struct domain *dst_d; + + dst_d = get_domain_by_id(send_info->id.domain_id); + if ( dst_d ) + { + ring_info = find_ring_info(dst_d, &send_info->id); + if ( ring_info ) + { + ring_remove_info(dst_d, ring_info); + dst_d->argo->ring_count--; + } + + put_domain(dst_d); + } + + hlist_del(&send_info->node); + xfree(send_info); + } + } +} + long do_argo_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg1, XEN_GUEST_HANDLE_PARAM(void) arg2, unsigned long arg3, unsigned long arg4) { - return -ENOSYS; + long rc = -EFAULT; + + argo_dprintk("->do_argo_op(%u,%p,%p,%lu,0x%lx)\n", cmd, + (void *)arg1.p, (void *)arg2.p, arg3, arg4); + + if ( unlikely(!opt_argo_enabled) ) + return -EOPNOTSUPP; + + switch (cmd) + { + default: + rc = -EOPNOTSUPP; + break; + } + + argo_dprintk("<-do_argo_op(%u)=%ld\n", cmd, rc); + + return rc; +} + +static void +argo_domain_init(struct argo_domain *argo) +{ + unsigned int i; + + rwlock_init(&argo->rings_L2_rwlock); + spin_lock_init(&argo->send_L2_lock); + spin_lock_init(&argo->wildcard_L2_lock); + argo->ring_count = 0; + + for ( i = 0; i < ARGO_HTABLE_SIZE; ++i ) + { + INIT_HLIST_HEAD(&argo->ring_hash[i]); + INIT_HLIST_HEAD(&argo->send_hash[i]); + } + INIT_HLIST_HEAD(&argo->wildcard_pend_list); +} + +int +argo_init(struct domain *d) +{ + struct argo_domain *argo; + + if ( !opt_argo_enabled ) + { + argo_dprintk("argo disabled, domid: %u\n", d->domain_id); + return 0; + } + + argo_dprintk("init: domid: %u\n", d->domain_id); + + argo = xzalloc(struct argo_domain); + if ( !argo ) + return -ENOMEM; + + argo_domain_init(argo); + + write_lock(&L1_global_argo_rwlock); + + d->argo = argo; + + write_unlock(&L1_global_argo_rwlock); + + return 0; +} + +void +argo_destroy(struct domain *d) +{ + BUG_ON(!d->is_dying); + + write_lock(&L1_global_argo_rwlock); + + argo_dprintk("destroy: domid %u d->argo=%p\n", d->domain_id, d->argo); + + if ( d->argo ) + { + domain_rings_remove_all(d); + partner_rings_remove(d); + wildcard_rings_pending_remove(d); + XFREE(d->argo); + } + write_unlock(&L1_global_argo_rwlock); +} + +void +argo_soft_reset(struct domain *d) +{ + write_lock(&L1_global_argo_rwlock); + + argo_dprintk("soft reset d=%u d->argo=%p\n", d->domain_id, d->argo); + + if ( d->argo ) + { + domain_rings_remove_all(d); + partner_rings_remove(d); + wildcard_rings_pending_remove(d); + + /* + * Since opt_argo_enabled cannot change at runtime, if d->argo is true + * then opt_argo_enabled must be true, and we can assume that init + * is allowed to proceed again here. + */ + argo_domain_init(d->argo); + } + + write_unlock(&L1_global_argo_rwlock); } diff --git a/xen/common/compat/argo.c b/xen/common/compat/argo.c new file mode 100644 index 000000000000..8edb9e851e22 --- /dev/null +++ b/xen/common/compat/argo.c @@ -0,0 +1,23 @@ +/****************************************************************************** + * Argo : Hypervisor-Mediated data eXchange + * + * Copyright (c) 2018, BAE Systems + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include + +#include + +CHECK_argo_addr; +CHECK_argo_ring; diff --git a/xen/common/domain.c b/xen/common/domain.c index c623daec5675..bd344e5a9c4e 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -277,6 +278,8 @@ static void _domain_destroy(struct domain *d) xfree(d->pbuf); + argo_destroy(d); + rangeset_domain_destroy(d); free_cpumask_var(d->dirty_cpumask); @@ -445,6 +448,9 @@ struct domain *domain_create(domid_t domid, goto fail; init_status |= INIT_gnttab; + if ( (err = argo_init(d)) != 0 ) + goto fail; + err = -ENOMEM; d->pbuf = xzalloc_array(char, DOMAIN_PBUF_SIZE); @@ -694,6 +700,9 @@ int rcu_lock_live_remote_domain_by_id(domid_t dom, struct domain **d) return 0; } +/* + * FIXME for 4.12: since argo_destroy is in _domain_destroy, remove it below. + */ int domain_kill(struct domain *d) { int rc = 0; @@ -717,6 +726,7 @@ int domain_kill(struct domain *d) if ( d->is_dying != DOMDYING_alive ) return domain_kill(d); d->is_dying = DOMDYING_dying; + argo_destroy(d); evtchn_destroy(d); gnttab_release_mappings(d); tmem_destroy(d->tmem_client); @@ -1175,6 +1185,8 @@ int domain_soft_reset(struct domain *d) grant_table_warn_active_grants(d); + argo_soft_reset(d); + for_each_vcpu ( d, v ) { set_xen_guest_handle(runstate_guest(v), NULL); diff --git a/xen/include/Makefile b/xen/include/Makefile index f7895e4d4e46..3d14532dbd7e 100644 --- a/xen/include/Makefile +++ b/xen/include/Makefile @@ -5,6 +5,7 @@ ifneq ($(CONFIG_COMPAT),) compat-arch-$(CONFIG_X86) := x86_32 headers-y := \ + compat/argo.h \ compat/callback.h \ compat/elfnote.h \ compat/event_channel.h \ diff --git a/xen/include/public/argo.h b/xen/include/public/argo.h new file mode 100644 index 000000000000..530bb82c6200 --- /dev/null +++ b/xen/include/public/argo.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * Argo : Hypervisor-Mediated data eXchange + * + * Derived from v4v, the version 2 of v2v. + * + * Copyright (c) 2010, Citrix Systems + * Copyright (c) 2018-2019, BAE Systems + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef __XEN_PUBLIC_ARGO_H__ +#define __XEN_PUBLIC_ARGO_H__ + +#include "xen.h" + +#define XEN_ARGO_DOMID_ANY DOMID_INVALID + +/* Fixed-width type for "argo port" number. Nothing to do with evtchns. */ +typedef uint32_t xen_argo_port_t; + +typedef struct xen_argo_addr +{ + xen_argo_port_t aport; + domid_t domain_id; + uint16_t pad; +} xen_argo_addr_t; + +typedef struct xen_argo_ring +{ + /* Guests should use atomic operations to access rx_ptr */ + uint32_t rx_ptr; + /* Guests should use atomic operations to access tx_ptr */ + uint32_t tx_ptr; + /* + * Header space reserved for later use. Align the start of the ring to a + * multiple of the message slot size. + */ + uint8_t reserved[56]; +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + uint8_t ring[]; +#elif defined(__GNUC__) + uint8_t ring[0]; +#endif +} xen_argo_ring_t; + +#endif diff --git a/xen/include/xen/argo.h b/xen/include/xen/argo.h new file mode 100644 index 000000000000..2ba7e5c0c0a9 --- /dev/null +++ b/xen/include/xen/argo.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * Argo : Hypervisor-Mediated data eXchange + * + * Copyright (c) 2018, BAE Systems + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __XEN_ARGO_H__ +#define __XEN_ARGO_H__ + +#include + +#ifdef CONFIG_ARGO + +int argo_init(struct domain *d); +void argo_destroy(struct domain *d); +void argo_soft_reset(struct domain *d); + +#else /* !CONFIG_ARGO */ + +static inline int argo_init(struct domain *d) +{ + return 0; +} + +static inline void argo_destroy(struct domain *d) +{ +} + +static inline void argo_soft_reset(struct domain *d) +{ +} + +#endif + +#endif diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 4956a7716ca8..6e69afaa35cf 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -490,6 +490,11 @@ struct domain unsigned int guest_request_enabled : 1; unsigned int guest_request_sync : 1; } monitor; + +#ifdef CONFIG_ARGO + /* Argo interdomain communication support */ + struct argo_domain *argo; +#endif }; /* Protect updates/reads (resp.) of domain_list and domain_hash. */ diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst index 527332054af8..9f616e4cba34 100644 --- a/xen/include/xlat.lst +++ b/xen/include/xlat.lst @@ -148,3 +148,5 @@ ? flask_setenforce xsm/flask_op.h ! flask_sid_context xsm/flask_op.h ? flask_transition xsm/flask_op.h +? argo_addr argo.h +? argo_ring argo.h