[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH RFC v1 55/74] xen/pvshim: forward evtchn ops between L0 Xen and L2 DomU
>>> On 04.01.18 at 14:06, <wei.liu2@xxxxxxxxxx> wrote: > From: Roger Pau Monne <roger.pau@xxxxxxxxxx> > > Note that the unmask and the virq operations are handled by the shim > itself, and that FIFO event channels are not exposed to the guest. > > Signed-off-by: Anthony Liguori <aliguori@xxxxxxxxxx> > Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> > Signed-off-by: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx> In RFC state this certainly doesn't matter yet, but generally I'd expect From: to match the first S-o-b. > @@ -155,11 +156,31 @@ static void set_vcpu_id(void) > static void xen_evtchn_upcall(struct cpu_user_regs *regs) > { > struct vcpu_info *vcpu_info = this_cpu(vcpu_info); > + unsigned long pending; > > vcpu_info->evtchn_upcall_pending = 0; > - xchg(&vcpu_info->evtchn_pending_sel, 0); > + pending = xchg(&vcpu_info->evtchn_pending_sel, 0); > > - pv_console_rx(regs); > + while ( pending ) > + { > + unsigned int l1 = ffsl(pending) - 1; find_first_set_bit() would look to be the better match here (and below), not the least because it translates (on capable hardware) to TZCNT instead of BSF. > + unsigned long evtchn = xchg(&XEN_shared_info->evtchn_pending[l1], 0); > + > + __clear_bit(l1, &pending); > + evtchn &= ~XEN_shared_info->evtchn_mask[l1]; > + while ( evtchn ) > + { > + unsigned int port = ffsl(evtchn) - 1; > + > + __clear_bit(port, &evtchn); > + port += l1 * BITS_PER_LONG; What about a 32-bit client? If that's not intended to be supported, building of such a guest should be prevented (in dom0_build.c). > @@ -63,6 +65,31 @@ static void __init replace_va(struct domain *d, > l4_pgentry_t *l4start, > : COMPAT_L1_PROT)); > } > > +static void evtchn_reserve(struct domain *d, unsigned int port) const (perhaps also for other helpers below)? > @@ -101,6 +133,233 @@ void pv_shim_shutdown(uint8_t reason) > xen_hypercall_shutdown(reason); > } > > +long pv_shim_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) > +{ > + struct domain *d = current->domain; > + long rc; > + > + switch ( cmd ) > + { > +#define EVTCHN_FORWARD(cmd, port_field) \ > +case EVTCHNOP_##cmd: { \ > + struct evtchn_##cmd op; \ I think this whole macro body would better be indented one more level, matching up with actual indentation at this point. > + \ > + if ( copy_from_guest(&op, arg, 1) != 0 ) \ > + return -EFAULT; \ > + \ > + rc = xen_hypercall_event_channel_op(EVTCHNOP_##cmd, &op); \ > + if ( rc ) \ > + break; \ > + \ > + spin_lock(&d->event_lock); \ Would the lock better be acquired already before the hypercall above? > + rc = evtchn_allocate_port(d, op.port_field); \ > + if ( rc ) \ > + { \ > + struct evtchn_close close = { \ > + .port = op.port_field, \ > + }; \ > + \ > + BUG_ON(xen_hypercall_event_channel_op(EVTCHNOP_close, &close)); \ > + } \ > + else \ > + evtchn_reserve(d, op.port_field); \ > + spin_unlock(&d->event_lock); \ > + \ > + if ( !rc && __copy_to_guest(arg, &op, 1) ) \ > + rc = -EFAULT; \ > + \ > + break; \ > + } > + EVTCHN_FORWARD(alloc_unbound, port) > + EVTCHN_FORWARD(bind_interdomain, local_port) > +#undef EVTCHN_FORWARD > + > + case EVTCHNOP_bind_virq: { > + struct evtchn_bind_virq virq; > + struct evtchn_alloc_unbound alloc = { > + .dom = DOMID_SELF, > + .remote_dom = DOMID_SELF, > + }; > + > + if ( copy_from_guest(&virq, arg, 1) != 0 ) > + return -EFAULT; > + /* > + * The event channel space is actually controlled by L0 Xen, so > + * allocate a port from L0 and then force the VIRQ to be bound to > that > + * specific port. > + * > + * This is only required for VIRQ because the rest of the event > channel > + * operations are handled directly by L0. > + */ > + rc = xen_hypercall_event_channel_op(EVTCHNOP_alloc_unbound, &alloc); > + if ( rc ) > + break; > + > + /* Force L1 to use the event channel port allocated on L0. */ > + rc = evtchn_bind_virq(&virq, alloc.port); > + if ( rc ) > + { > + struct evtchn_close free = { Why is this not named "close", like the other one? Perhaps a single function wide instance of this structure would suffice? > + .port = alloc.port, > + }; > + > + xen_hypercall_event_channel_op(EVTCHNOP_close, &free); > + } > + > + if ( !rc && __copy_to_guest(arg, &virq, 1) ) > + rc = -EFAULT; > + > + break; > + } > + case EVTCHNOP_status: { Blank lines between non-fall-through case blocks please. > + struct evtchn_status status; > + > + if ( copy_from_guest(&status, arg, 1) != 0 ) > + return -EFAULT; > + > + if ( port_is_valid(d, status.port) && evtchn_handled(d, status.port) > ) Please be consistent with the validity checks: Compare this one with ... > + rc = evtchn_status(&status); > + else > + rc = xen_hypercall_event_channel_op(EVTCHNOP_status, &status); > + > + break; > + } > + case EVTCHNOP_bind_vcpu: { > + struct evtchn_bind_vcpu vcpu; > + > + if ( copy_from_guest(&vcpu, arg, 1) != 0 ) > + return -EFAULT; > + > + if ( !port_is_valid(d, vcpu.port) ) > + return -EINVAL; > + > + if ( evtchn_handled(d, vcpu.port) ) ... the one here. Or otherwise add a comment clarifying why they are being done differently. > + case EVTCHNOP_bind_ipi: { > + struct evtchn_bind_ipi ipi; > + > + if ( copy_from_guest(&ipi, arg, 1) != 0 ) > + return -EFAULT; > + > + rc = xen_hypercall_event_channel_op(EVTCHNOP_bind_ipi, &ipi); > + if ( rc ) > + break; > + > + spin_lock(&d->event_lock); > + rc = evtchn_allocate_port(d, ipi.port); > + if ( rc ) > + { > + struct evtchn_close close = { > + .port = ipi.port, > + }; > + > + /* > + * If closing the event channel port also fails there's not > + * much the shim can do, since it has been unable to reserve > + * the port in it's event channel space. > + */ > + BUG_ON(xen_hypercall_event_channel_op(EVTCHNOP_close, &close)); A similar BUG_ON() further up went without comment, which I think would be fine here too. > + case EVTCHNOP_unmask: { > + struct evtchn_unmask unmask; > + > + if ( copy_from_guest(&unmask, arg, 1) != 0 ) > + return -EFAULT; > + > + /* Unmask is handled in L1 */ > + rc = evtchn_unmask(unmask.port); > + > + break; > + } Is this really sufficient, without handing anything through to L0? Perhaps it's fine as long as there's no pass-through support here. > + default: > + /* No FIFO or PIRQ support for now */ > + rc = -ENOSYS; -EOPNOTSUPP please. > --- a/xen/common/domain.c > +++ b/xen/common/domain.c > @@ -63,6 +63,8 @@ struct domain *domain_list; > > struct domain *hardware_domain __read_mostly; > > +struct domain *pv_domain __read_mostly; This shouldn't really live in common code, and even less so outside of any #ifdef (same for its declaration being placed in a common header). > @@ -395,6 +397,11 @@ struct domain *domain_create(domid_t domid, unsigned int > domcr_flags, > rcu_assign_pointer(*pd, d); > rcu_assign_pointer(domain_hash[DOMAIN_HASH(domid)], d); > spin_unlock(&domlist_update_lock); > + > +#ifdef CONFIG_X86 > + if ( pv_shim ) > + pv_domain = d; > +#endif I assume this #ifdef could be more restrictive. > @@ -345,13 +365,13 @@ static long > evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) > } > > > -static long evtchn_bind_virq(evtchn_bind_virq_t *bind) > +int evtchn_bind_virq(evtchn_bind_virq_t *bind, int port) evtchn_port_t please (also in evtchn_allocate_port()), and ... > { > struct evtchn *chn; > struct vcpu *v; > struct domain *d = current->domain; > - int port, virq = bind->virq, vcpu = bind->vcpu; > - long rc = 0; > + int virq = bind->virq, vcpu = bind->vcpu; > + int rc = 0; > > if ( (virq < 0) || (virq >= ARRAY_SIZE(v->virq_to_evtchn)) ) > return -EINVAL; > @@ -368,7 +388,12 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind) > if ( v->virq_to_evtchn[virq] != 0 ) > ERROR_EXIT(-EEXIST); > > - if ( (port = get_free_port(d)) < 0 ) > + if ( port >= 0 ) ... use zero as the "please allocate" indicator here (and in the respective caller). > @@ -511,7 +536,7 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind) > } > > > -static long evtchn_close(struct domain *d1, int port1, bool_t guest) > +long evtchn_close(struct domain *d1, int port1, bool guest) Convert return type to "int" at the same time? > @@ -839,7 +864,7 @@ static void clear_global_virq_handlers(struct domain *d) > } > } > > -static long evtchn_status(evtchn_status_t *status) > +long evtchn_status(evtchn_status_t *status) Same here. > @@ -1030,6 +1055,11 @@ long do_event_channel_op(int cmd, > XEN_GUEST_HANDLE_PARAM(void) arg) > { > long rc; > > +#ifdef CONFIG_X86 > + if ( pv_shim ) > + return pv_shim_event_channel_op(cmd, arg); > +#endif Patch it right into the hypercall table instead? Jan _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |