[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH 2/5] ioreq-server: create basic ioreq server abstraction.
Collect together data structures concerning device emulation together into a new struct hvm_ioreq_server. Code that deals with the shared and buffered ioreq pages is extracted from functions such as hvm_domain_initialise, hvm_vcpu_initialise and do_hvm_op and consolidated into a set of hvm_ioreq_server_XXX functions. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- xen/arch/x86/hvm/hvm.c | 318 ++++++++++++++++++++++++++------------ xen/include/asm-x86/hvm/domain.h | 9 +- xen/include/asm-x86/hvm/vcpu.h | 2 +- 3 files changed, 229 insertions(+), 100 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 71a44db..a0eaadb 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -345,16 +345,16 @@ void hvm_migrate_pirqs(struct vcpu *v) spin_unlock(&d->event_lock); } -static ioreq_t *get_ioreq(struct vcpu *v) +static ioreq_t *get_ioreq(struct hvm_ioreq_server *s, int id) { - struct domain *d = v->domain; - shared_iopage_t *p = d->arch.hvm_domain.ioreq.va; - ASSERT((v == current) || spin_is_locked(&d->arch.hvm_domain.ioreq.lock)); - return p ? &p->vcpu_ioreq[v->vcpu_id] : NULL; + shared_iopage_t *p = s->ioreq.va; + ASSERT(p != NULL); + return &p->vcpu_ioreq[id]; } void hvm_do_resume(struct vcpu *v) { + struct hvm_ioreq_server *s; ioreq_t *p; check_wakeup_from_wait(); @@ -362,10 +362,14 @@ void hvm_do_resume(struct vcpu *v) if ( is_hvm_vcpu(v) ) pt_restore_timer(v); - /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */ - if ( !(p = get_ioreq(v)) ) + s = v->arch.hvm_vcpu.ioreq_server; + v->arch.hvm_vcpu.ioreq_server = NULL; + + if ( !s ) goto check_inject_trap; + /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */ + p = get_ioreq(s, v->vcpu_id); while ( p->state != STATE_IOREQ_NONE ) { switch ( p->state ) @@ -375,7 +379,7 @@ void hvm_do_resume(struct vcpu *v) break; case STATE_IOREQ_READY: /* IOREQ_{READY,INPROCESS} -> IORESP_READY */ case STATE_IOREQ_INPROCESS: - wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port, + wait_on_xen_event_channel(p->vp_eport, (p->state != STATE_IOREQ_READY) && (p->state != STATE_IOREQ_INPROCESS)); break; @@ -398,7 +402,6 @@ void hvm_do_resume(struct vcpu *v) static void hvm_init_ioreq_page( struct domain *d, struct hvm_ioreq_page *iorp) { - memset(iorp, 0, sizeof(*iorp)); spin_lock_init(&iorp->lock); domain_pause(d); } @@ -541,6 +544,167 @@ static int handle_pvh_io( return X86EMUL_OKAY; } +static int hvm_init_ioreq_server(struct domain *d) +{ + struct hvm_ioreq_server *s; + int i; + + s = xzalloc(struct hvm_ioreq_server); + if ( !s ) + return -ENOMEM; + + s->domain = d; + + for ( i = 0; i < MAX_HVM_VCPUS; i++ ) + s->ioreq_evtchn[i] = -1; + s->buf_ioreq_evtchn = -1; + + hvm_init_ioreq_page(d, &s->ioreq); + hvm_init_ioreq_page(d, &s->buf_ioreq); + + d->arch.hvm_domain.ioreq_server = s; + return 0; +} + +static void hvm_deinit_ioreq_server(struct domain *d) +{ + struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; + + hvm_destroy_ioreq_page(d, &s->ioreq); + hvm_destroy_ioreq_page(d, &s->buf_ioreq); + + xfree(s); +} + +static void hvm_update_ioreq_server_evtchn(struct hvm_ioreq_server *s) +{ + struct domain *d = s->domain; + + if ( s->ioreq.va != NULL ) + { + shared_iopage_t *p = s->ioreq.va; + struct vcpu *v; + + for_each_vcpu ( d, v ) + p->vcpu_ioreq[v->vcpu_id].vp_eport = s->ioreq_evtchn[v->vcpu_id]; + } +} + +static int hvm_ioreq_server_add_vcpu(struct hvm_ioreq_server *s, struct vcpu *v) +{ + int rc; + + /* Create ioreq event channel. */ + rc = alloc_unbound_xen_event_channel(v, s->domid, NULL); + if ( rc < 0 ) + goto done; + + /* Register ioreq event channel. */ + s->ioreq_evtchn[v->vcpu_id] = rc; + + if ( v->vcpu_id == 0 ) + { + /* Create bufioreq event channel. */ + rc = alloc_unbound_xen_event_channel(v, s->domid, NULL); + if ( rc < 0 ) + goto done; + + s->buf_ioreq_evtchn = rc; + } + + hvm_update_ioreq_server_evtchn(s); + rc = 0; + +done: + return rc; +} + +static void hvm_ioreq_server_remove_vcpu(struct hvm_ioreq_server *s, struct vcpu *v) +{ + if ( v->vcpu_id == 0 ) + { + if ( s->buf_ioreq_evtchn >= 0 ) + { + free_xen_event_channel(v, s->buf_ioreq_evtchn); + s->buf_ioreq_evtchn = -1; + } + } + + if ( s->ioreq_evtchn[v->vcpu_id] >= 0 ) + { + free_xen_event_channel(v, s->ioreq_evtchn[v->vcpu_id]); + s->ioreq_evtchn[v->vcpu_id] = -1; + } +} + +static int hvm_replace_event_channel(struct vcpu *v, domid_t remote_domid, + int *p_port) +{ + int old_port, new_port; + + new_port = alloc_unbound_xen_event_channel(v, remote_domid, NULL); + if ( new_port < 0 ) + return new_port; + + /* xchg() ensures that only we call free_xen_event_channel(). */ + old_port = xchg(p_port, new_port); + free_xen_event_channel(v, old_port); + return 0; +} + +static int hvm_set_ioreq_server_domid(struct hvm_ioreq_server *s, domid_t domid) +{ + struct domain *d = s->domain; + struct vcpu *v; + int rc = 0; + + domain_pause(d); + + if ( d->vcpu[0] ) + { + rc = hvm_replace_event_channel(d->vcpu[0], domid, &s->buf_ioreq_evtchn); + if ( rc < 0 ) + goto done; + } + + for_each_vcpu ( d, v ) + { + rc = hvm_replace_event_channel(v, domid, &s->ioreq_evtchn[v->vcpu_id]); + if ( rc < 0 ) + goto done; + } + + hvm_update_ioreq_server_evtchn(s); + + s->domid = domid; + +done: + domain_unpause(d); + + return rc; +} + +static int hvm_set_ioreq_server_pfn(struct hvm_ioreq_server *s, unsigned long pfn) +{ + struct domain *d = s->domain; + int rc; + + rc = hvm_set_ioreq_page(d, &s->ioreq, pfn); + if ( rc < 0 ) + return rc; + + hvm_update_ioreq_server_evtchn(s); + + return 0; +} + +static int hvm_set_ioreq_server_buf_pfn(struct hvm_ioreq_server *s, unsigned long pfn) +{ + struct domain *d = s->domain; + + return hvm_set_ioreq_page(d, &s->buf_ioreq, pfn); +} + int hvm_domain_initialise(struct domain *d) { int rc; @@ -608,17 +772,20 @@ int hvm_domain_initialise(struct domain *d) rtc_init(d); - hvm_init_ioreq_page(d, &d->arch.hvm_domain.ioreq); - hvm_init_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq); + rc = hvm_init_ioreq_server(d); + if ( rc != 0 ) + goto fail2; register_portio_handler(d, 0xe9, 1, hvm_print_line); rc = hvm_funcs.domain_initialise(d); if ( rc != 0 ) - goto fail2; + goto fail3; return 0; + fail3: + hvm_deinit_ioreq_server(d); fail2: rtc_deinit(d); stdvga_deinit(d); @@ -642,8 +809,7 @@ void hvm_domain_relinquish_resources(struct domain *d) if ( hvm_funcs.nhvm_domain_relinquish_resources ) hvm_funcs.nhvm_domain_relinquish_resources(d); - hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.ioreq); - hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq); + hvm_deinit_ioreq_server(d); msixtbl_pt_cleanup(d); @@ -1155,7 +1321,7 @@ int hvm_vcpu_initialise(struct vcpu *v) { int rc; struct domain *d = v->domain; - domid_t dm_domid; + struct hvm_ioreq_server *s; hvm_asid_flush_vcpu(v); @@ -1198,30 +1364,12 @@ int hvm_vcpu_initialise(struct vcpu *v) && (rc = nestedhvm_vcpu_initialise(v)) < 0 ) /* teardown: nestedhvm_vcpu_destroy */ goto fail5; - dm_domid = d->arch.hvm_domain.params[HVM_PARAM_DM_DOMAIN]; + s = d->arch.hvm_domain.ioreq_server; - /* Create ioreq event channel. */ - rc = alloc_unbound_xen_event_channel(v, dm_domid, NULL); /* teardown: none */ + rc = hvm_ioreq_server_add_vcpu(s, v); if ( rc < 0 ) goto fail6; - /* Register ioreq event channel. */ - v->arch.hvm_vcpu.xen_port = rc; - - if ( v->vcpu_id == 0 ) - { - /* Create bufioreq event channel. */ - rc = alloc_unbound_xen_event_channel(v, dm_domid, NULL); /* teardown: none */ - if ( rc < 0 ) - goto fail6; - d->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_EVTCHN] = rc; - } - - spin_lock(&d->arch.hvm_domain.ioreq.lock); - if ( d->arch.hvm_domain.ioreq.va != NULL ) - get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; - spin_unlock(&d->arch.hvm_domain.ioreq.lock); - if ( v->vcpu_id == 0 ) { /* NB. All these really belong in hvm_domain_initialise(). */ @@ -1255,6 +1403,11 @@ int hvm_vcpu_initialise(struct vcpu *v) void hvm_vcpu_destroy(struct vcpu *v) { + struct domain *d = v->domain; + struct hvm_ioreq_server *s = d->arch.hvm_domain.ioreq_server; + + hvm_ioreq_server_remove_vcpu(s, v); + nestedhvm_vcpu_destroy(v); free_compat_arg_xlat(v); @@ -1266,9 +1419,6 @@ void hvm_vcpu_destroy(struct vcpu *v) vlapic_destroy(v); hvm_funcs.vcpu_destroy(v); - - /* Event channel is already freed by evtchn_destroy(). */ - /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/ } void hvm_vcpu_down(struct vcpu *v) @@ -1298,8 +1448,10 @@ void hvm_vcpu_down(struct vcpu *v) int hvm_buffered_io_send(ioreq_t *p) { struct vcpu *v = current; - struct hvm_ioreq_page *iorp = &v->domain->arch.hvm_domain.buf_ioreq; - buffered_iopage_t *pg = iorp->va; + struct domain *d = v->domain; + struct hvm_ioreq_server *s; + struct hvm_ioreq_page *iorp; + buffered_iopage_t *pg; buf_ioreq_t bp; /* Timeoffset sends 64b data, but no address. Use two consecutive slots. */ int qw = 0; @@ -1307,6 +1459,13 @@ int hvm_buffered_io_send(ioreq_t *p) /* Ensure buffered_iopage fits in a page */ BUILD_BUG_ON(sizeof(buffered_iopage_t) > PAGE_SIZE); + s = d->arch.hvm_domain.ioreq_server; + if ( !s ) + return 0; + + iorp = &s->buf_ioreq; + pg = iorp->va; + /* * Return 0 for the cases we can't deal with: * - 'addr' is only a 20-bit field, so we cannot address beyond 1MB @@ -1367,8 +1526,7 @@ int hvm_buffered_io_send(ioreq_t *p) wmb(); pg->write_pointer += qw ? 2 : 1; - notify_via_xen_event_channel(v->domain, - v->domain->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_EVTCHN]); + notify_via_xen_event_channel(d, s->buf_ioreq_evtchn); spin_unlock(&iorp->lock); return 1; @@ -1376,22 +1534,29 @@ int hvm_buffered_io_send(ioreq_t *p) bool_t hvm_send_assist_req(struct vcpu *v, ioreq_t *proto_p) { + struct domain *d = v->domain; + struct hvm_ioreq_server *s; ioreq_t *p; if ( unlikely(!vcpu_start_shutdown_deferral(v)) ) return 0; /* implicitly bins the i/o operation */ - if ( !(p = get_ioreq(v)) ) + s = d->arch.hvm_domain.ioreq_server; + if ( !s ) return 0; + p = get_ioreq(s, v->vcpu_id); + if ( unlikely(p->state != STATE_IOREQ_NONE) ) { /* This indicates a bug in the device model. Crash the domain. */ gdprintk(XENLOG_ERR, "Device model set bad IO state %d.\n", p->state); - domain_crash(v->domain); + domain_crash(d); return 0; } + v->arch.hvm_vcpu.ioreq_server = s; + p->dir = proto_p->dir; p->data_is_ptr = proto_p->data_is_ptr; p->type = proto_p->type; @@ -1401,14 +1566,14 @@ bool_t hvm_send_assist_req(struct vcpu *v, ioreq_t *proto_p) p->df = proto_p->df; p->data = proto_p->data; - prepare_wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port); + prepare_wait_on_xen_event_channel(p->vp_eport); /* * Following happens /after/ blocking and setting up ioreq contents. * prepare_wait_on_xen_event_channel() is an implicit barrier. */ p->state = STATE_IOREQ_READY; - notify_via_xen_event_channel(v->domain, v->arch.hvm_vcpu.xen_port); + notify_via_xen_event_channel(d, p->vp_eport); return 1; } @@ -3995,21 +4160,6 @@ static int hvmop_flush_tlb_all(void) return 0; } -static int hvm_replace_event_channel(struct vcpu *v, domid_t remote_domid, - int *p_port) -{ - int old_port, new_port; - - new_port = alloc_unbound_xen_event_channel(v, remote_domid, NULL); - if ( new_port < 0 ) - return new_port; - - /* xchg() ensures that only we call free_xen_event_channel(). */ - old_port = xchg(p_port, new_port); - free_xen_event_channel(v, old_port); - return 0; -} - long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) { @@ -4022,7 +4172,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) case HVMOP_get_param: { struct xen_hvm_param a; - struct hvm_ioreq_page *iorp; + struct hvm_ioreq_server *s; struct domain *d; struct vcpu *v; @@ -4048,6 +4198,8 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) if ( rc ) goto param_fail; + s = d->arch.hvm_domain.ioreq_server; + if ( op == HVMOP_set_param ) { rc = 0; @@ -4055,19 +4207,10 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) switch ( a.index ) { case HVM_PARAM_IOREQ_PFN: - iorp = &d->arch.hvm_domain.ioreq; - if ( (rc = hvm_set_ioreq_page(d, iorp, a.value)) != 0 ) - break; - spin_lock(&iorp->lock); - if ( iorp->va != NULL ) - /* Initialise evtchn port info if VCPUs already created. */ - for_each_vcpu ( d, v ) - get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; - spin_unlock(&iorp->lock); + rc = hvm_set_ioreq_server_pfn(s, a.value); break; case HVM_PARAM_BUFIOREQ_PFN: - iorp = &d->arch.hvm_domain.buf_ioreq; - rc = hvm_set_ioreq_page(d, iorp, a.value); + rc = hvm_set_ioreq_server_buf_pfn(s, a.value); break; case HVM_PARAM_CALLBACK_IRQ: hvm_set_callback_via(d, a.value); @@ -4122,31 +4265,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) if ( a.value == DOMID_SELF ) a.value = curr_d->domain_id; - rc = 0; - domain_pause(d); /* safe to change per-vcpu xen_port */ - if ( d->vcpu[0] ) - rc = hvm_replace_event_channel(d->vcpu[0], a.value, - (int *)&d->vcpu[0]->domain->arch.hvm_domain.params - [HVM_PARAM_BUFIOREQ_EVTCHN]); - if ( rc ) - { - domain_unpause(d); - break; - } - iorp = &d->arch.hvm_domain.ioreq; - for_each_vcpu ( d, v ) - { - rc = hvm_replace_event_channel(v, a.value, - &v->arch.hvm_vcpu.xen_port); - if ( rc ) - break; - - spin_lock(&iorp->lock); - if ( iorp->va != NULL ) - get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; - spin_unlock(&iorp->lock); - } - domain_unpause(d); + rc = hvm_set_ioreq_server_domid(s, a.value); break; case HVM_PARAM_ACPI_S_STATE: /* Not reflexive, as we must domain_pause(). */ @@ -4241,6 +4360,9 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) { switch ( a.index ) { + case HVM_PARAM_BUFIOREQ_EVTCHN: + a.value = s->buf_ioreq_evtchn; + break; case HVM_PARAM_ACPI_S_STATE: a.value = d->arch.hvm_domain.is_s3_suspended ? 3 : 0; break; diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index b1e3187..4c039f8 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -41,10 +41,17 @@ struct hvm_ioreq_page { void *va; }; -struct hvm_domain { +struct hvm_ioreq_server { + struct domain *domain; + domid_t domid; struct hvm_ioreq_page ioreq; + int ioreq_evtchn[MAX_HVM_VCPUS]; struct hvm_ioreq_page buf_ioreq; + int buf_ioreq_evtchn; +}; +struct hvm_domain { + struct hvm_ioreq_server *ioreq_server; struct pl_time pl_time; struct hvm_io_handler *io_handler; diff --git a/xen/include/asm-x86/hvm/vcpu.h b/xen/include/asm-x86/hvm/vcpu.h index 122ab0d..4c9d7ee 100644 --- a/xen/include/asm-x86/hvm/vcpu.h +++ b/xen/include/asm-x86/hvm/vcpu.h @@ -138,7 +138,7 @@ struct hvm_vcpu { spinlock_t tm_lock; struct list_head tm_list; - int xen_port; + struct hvm_ioreq_server *ioreq_server; bool_t flag_dr_dirty; bool_t debug_state_latch; -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |