[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 22/25] xen/arm: Allow vpl011 to be used by DomU
On Wed, 24 Oct 2018, Oleksandr Tyshchenko wrote: > Hi, Stefano > > On Tue, Oct 23, 2018 at 5:04 AM Stefano Stabellini > <sstabellini@xxxxxxxxxx> wrote: > > > > Make vpl011 being able to be used without a userspace component in Dom0. > > In that case, output is printed to the Xen serial and input is received > > from the Xen serial one character at a time. > > > > Call domain_vpl011_init during construct_domU if vpl011 is enabled. > > > > Introduce a new ring struct with only the ring array to avoid a waste of > > memory. Introduce separate read_data and write_data functions for > > initial domains: vpl011_write_data_xen is very simple and just writes > > to the console, while vpl011_read_data_xen is a duplicate of > > vpl011_read_data. Although textually almost identical, we are forced to > > duplicate the functions because the struct layout is different. > > > > Output characters are printed one by one, potentially leading to > > intermixed output of different domains on the console. A follow-up patch > > will solve the issue by introducing buffering. > > > > Signed-off-by: Stefano Stabellini <stefanos@xxxxxxxxxx> > > Acked-by: Julien Grall <julien.grall@xxxxxxx> > > --- > > Changes in v5: > > - renable call to vpl011_rx_char_xen from console.c > > > > Changes in v4: > > - code style > > > > Changes in v3: > > - add in-code comments > > - improve existing comments > > - remove ifdef around domain_vpl011_init in construct_domU > > - add ASSERT > > - use SBSA_UART_FIFO_SIZE for in buffer size > > - rename ring_enable to backend_in_domain > > - rename struct xencons_in to struct vpl011_xen_backend > > - rename inring field to xen > > - rename helper functions accordingly > > - remove unnecessary stub implementation of vpl011_rx_char > > - move vpl011_rx_char_xen within the file to avoid the need of a forward > > declaration of vpl011_data_avail > > - fix small bug in vpl011_rx_char_xen: increment in_prod before using it > > to check xencons_queued. > > > > Changes in v2: > > - only init if vpl011 > > - rename vpl011_read_char to vpl011_rx_char > > - remove spurious change > > - fix coding style > > - use different ring struct > > - move the write_data changes to their own function > > (vpl011_write_data_noring) > > - duplicate vpl011_read_data > > --- > > xen/arch/arm/domain_build.c | 9 +- > > xen/arch/arm/vpl011.c | 200 > > +++++++++++++++++++++++++++++++++++++------ > > xen/drivers/char/console.c | 2 +- > > xen/include/asm-arm/vpl011.h | 8 ++ > > 4 files changed, 193 insertions(+), 26 deletions(-) > > > > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > > index 6026b77..9ffd919 100644 > > --- a/xen/arch/arm/domain_build.c > > +++ b/xen/arch/arm/domain_build.c > > @@ -2629,7 +2629,14 @@ static int __init construct_domU(struct domain *d, > > if ( rc < 0 ) > > return rc; > > > > - return construct_domain(d, &kinfo); > > + rc = construct_domain(d, &kinfo); > > + if ( rc < 0 ) > > + return rc; > > + > > + if ( kinfo.vpl011 ) > > + rc = domain_vpl011_init(d, NULL); > > + > > + return rc; > > } > > > > void __init create_domUs(void) > > diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c > > index 68452a8..131507e 100644 > > --- a/xen/arch/arm/vpl011.c > > +++ b/xen/arch/arm/vpl011.c > > @@ -77,6 +77,91 @@ static void vpl011_update_interrupt_status(struct domain > > *d) > > #endif > > } > > > > +/* > > + * vpl011_write_data_xen writes chars from the vpl011 out buffer to the > > + * console. Only to be used when the backend is Xen. > > + */ > > +static void vpl011_write_data_xen(struct domain *d, uint8_t data) > > +{ > > + unsigned long flags; > > + struct vpl011 *vpl011 = &d->arch.vpl011; > > + > > + VPL011_LOCK(d, flags); > > + > > + printk("%c", data); > > + if (data == '\n') > > + printk("DOM%u: ", d->domain_id); > > + > > + vpl011->uartris |= TXI; > > + vpl011->uartfr &= ~TXFE; > > + vpl011_update_interrupt_status(d); > > + > > + VPL011_UNLOCK(d, flags); > > +} > > + > > +/* > > + * vpl011_read_data_xen reads data when the backend is xen. Characters > > + * are added to the vpl011 receive buffer by vpl011_rx_char_xen. > > + */ > > +static uint8_t vpl011_read_data_xen(struct domain *d) > > +{ > > + unsigned long flags; > > + uint8_t data = 0; > > + struct vpl011 *vpl011 = &d->arch.vpl011; > > + struct vpl011_xen_backend *intf = vpl011->backend.xen; > > + XENCONS_RING_IDX in_cons, in_prod; > > + > > + VPL011_LOCK(d, flags); > > + > > + in_cons = intf->in_cons; > > + in_prod = intf->in_prod; > > + > > + smp_rmb(); > > + > > + /* > > + * It is expected that there will be data in the ring buffer when this > > + * function is called since the guest is expected to read the data > > register > > + * only if the TXFE flag is not set. > > + * If the guest still does read when TXFE bit is set then 0 will be > > returned. > > + */ > > + if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) > 0 ) > > + { > > + unsigned int fifo_level; > > + > > + data = intf->in[xencons_mask(in_cons, sizeof(intf->in))]; > > + in_cons += 1; > > + smp_mb(); > > + intf->in_cons = in_cons; > > + > > + fifo_level = xencons_queued(in_prod, in_cons, sizeof(intf->in)); > > + > > + /* If the FIFO is now empty, we clear the receive timeout > > interrupt. */ > > + if ( fifo_level == 0 ) > > + { > > + vpl011->uartfr |= RXFE; > > + vpl011->uartris &= ~RTI; > > + } > > + > > + /* If the FIFO is more than half empty, we clear the RX interrupt. > > */ > > + if ( fifo_level < sizeof(intf->in) - SBSA_UART_FIFO_LEVEL ) > > + vpl011->uartris &= ~RXI; > > + > > + vpl011_update_interrupt_status(d); > > + } > > + else > > + gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer empty\n"); > > + > > + /* > > + * We have consumed a character or the FIFO was empty, so clear the > > + * "FIFO full" bit. > > + */ > > + vpl011->uartfr &= ~RXFF; > > + > > + VPL011_UNLOCK(d, flags); > > + > > + return data; > > +} > > + > > static uint8_t vpl011_read_data(struct domain *d) > > { > > unsigned long flags; > > @@ -240,7 +325,10 @@ static int vpl011_mmio_read(struct vcpu *v, > > case DR: > > if ( !vpl011_reg32_check_access(dabt) ) goto bad_width; > > > > - *r = vreg_reg32_extract(vpl011_read_data(d), info); > > + if ( vpl011->backend_in_domain ) > > + *r = vreg_reg32_extract(vpl011_read_data(d), info); > > + else > > + *r = vreg_reg32_extract(vpl011_read_data_xen(d), info); > > return 1; > > > > case RSR: > > @@ -325,7 +413,10 @@ static int vpl011_mmio_write(struct vcpu *v, > > > > vreg_reg32_update(&data, r, info); > > data &= 0xFF; > > - vpl011_write_data(v->domain, data); > > + if ( vpl011->backend_in_domain ) > > + vpl011_write_data(v->domain, data); > > + else > > + vpl011_write_data_xen(v->domain, data); > > return 1; > > } > > > > @@ -430,6 +521,39 @@ static void vpl011_data_avail(struct domain *d, > > vpl011->uartfr |= TXFE; > > } > > > > +/* > > + * vpl011_rx_char_xen adds a char to a domain's vpl011 receive buffer. > > + * It is only used when the vpl011 backend is in Xen. > > + */ > > +void vpl011_rx_char_xen(struct domain *d, char c) > > +{ > > + unsigned long flags; > > + struct vpl011 *vpl011 = &d->arch.vpl011; > > + struct vpl011_xen_backend *intf = vpl011->backend.xen; > > + XENCONS_RING_IDX in_cons, in_prod, in_fifo_level; > > + > > + ASSERT(!vpl011->backend_in_domain); > > + VPL011_LOCK(d, flags); > > + > > + in_cons = intf->in_cons; > > + in_prod = intf->in_prod; > Do we need barriers here and after writing the ring? We do not need barriers because both frontend and backend are in Xen for this use-case: both in_cons and in_prod are modified by Xen with the VPL011_LOCK held. There are no simultaneous reads/writes and the lock includes a barrier. > > + if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == > > sizeof(intf->in) ) > > + { > > + VPL011_UNLOCK(d, flags); > > + return; > > + } > > + > > + intf->in[xencons_mask(in_prod, sizeof(intf->in))] = c; > > + intf->in_prod = ++in_prod; > > + > > + in_fifo_level = xencons_queued(in_prod, > > + in_cons, > > + sizeof(intf->in)); > > + > > + vpl011_data_avail(d, in_fifo_level, sizeof(intf->in), 0, > > SBSA_UART_FIFO_SIZE); > > + VPL011_UNLOCK(d, flags); > > +} > > + > > static void vpl011_notification(struct vcpu *v, unsigned int port) > > { > > unsigned long flags; > > @@ -470,27 +594,47 @@ int domain_vpl011_init(struct domain *d, struct > > vpl011_init_info *info) > > if ( vpl011->backend.dom.ring_buf ) > > return -EINVAL; > > > > - /* Map the guest PFN to Xen address space. */ > > - rc = prepare_ring_for_helper(d, > > - gfn_x(info->gfn), > > - &vpl011->backend.dom.ring_page, > > - &vpl011->backend.dom.ring_buf); > > - if ( rc < 0 ) > > - goto out; > > + /* > > + * info is NULL when the backend is in Xen. > > + * info is != NULL when the backend is in a domain. > > + */ > > + if ( info != NULL ) > > + { > > + vpl011->backend_in_domain = true; > > + > > + /* Map the guest PFN to Xen address space. */ > > + rc = prepare_ring_for_helper(d, > > + gfn_x(info->gfn), > > + &vpl011->backend.dom.ring_page, > > + &vpl011->backend.dom.ring_buf); > > + if ( rc < 0 ) > > + goto out; > > + > > + rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid, > > + vpl011_notification); > > + if ( rc < 0 ) > > + goto out1; > > + > > + vpl011->evtchn = info->evtchn = rc; > > + } > > + else > > + { > > + vpl011->backend_in_domain = false; > > + > > + vpl011->backend.xen = xzalloc(struct vpl011_xen_backend); > > + if ( vpl011->backend.xen == NULL ) > > + { > > + rc = -EINVAL; > > + goto out1; > > + } > > + } > > > > rc = vgic_reserve_virq(d, GUEST_VPL011_SPI); > > if ( !rc ) > > { > > rc = -EINVAL; > > - goto out1; > > - } > > - > > - rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid, > > - vpl011_notification); > > - if ( rc < 0 ) > > goto out2; > > - > > - vpl011->evtchn = info->evtchn = rc; > > + } > > > > spin_lock_init(&vpl011->lock); > > > > @@ -503,8 +647,11 @@ out2: > > vgic_free_virq(d, GUEST_VPL011_SPI); > > > > out1: > > - destroy_ring_for_helper(&vpl011->backend.dom.ring_buf, > > - vpl011->backend.dom.ring_page); > > + if ( vpl011->backend_in_domain ) > > + destroy_ring_for_helper(&vpl011->backend.dom.ring_buf, > > + vpl011->backend.dom.ring_page); > > + else > > + xfree(vpl011->backend.xen); > > > > out: > > return rc; > > @@ -514,12 +661,17 @@ void domain_vpl011_deinit(struct domain *d) > > { > > struct vpl011 *vpl011 = &d->arch.vpl011; > > > > - if ( !vpl011->backend.dom.ring_buf ) > > - return; > > + if ( vpl011->backend_in_domain ) > > + { > > + if ( !vpl011->backend.dom.ring_buf ) > > + return; > > > > - free_xen_event_channel(d, vpl011->evtchn); > > - destroy_ring_for_helper(&vpl011->backend.dom.ring_buf, > > - vpl011->backend.dom.ring_page); > > + free_xen_event_channel(d, vpl011->evtchn); > > + destroy_ring_for_helper(&vpl011->backend.dom.ring_buf, > > + vpl011->backend.dom.ring_page); > > + } > > + else > > + xfree(vpl011->backend.xen); > > } > > > > /* > > diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c > > index 75172e7..990c51c 100644 > > --- a/xen/drivers/char/console.c > > +++ b/xen/drivers/char/console.c > > @@ -444,7 +444,7 @@ static void __serial_rx(char c, struct cpu_user_regs > > *regs) > > send_global_virq(VIRQ_CONSOLE); > > break; > > } > > -#if 0 > > +#ifdef CONFIG_SBSA_VUART_CONSOLE > > default: > > { > > struct domain *d = rcu_lock_domain_by_any_id(console_rx - 1); > > diff --git a/xen/include/asm-arm/vpl011.h b/xen/include/asm-arm/vpl011.h > > index 42d7a24..5eb6d25 100644 > > --- a/xen/include/asm-arm/vpl011.h > > +++ b/xen/include/asm-arm/vpl011.h > > @@ -21,6 +21,7 @@ > > > > #include <public/domctl.h> > > #include <public/io/ring.h> > > +#include <public/io/console.h> > > #include <asm/vreg.h> > > #include <xen/mm.h> > > > > @@ -29,13 +30,19 @@ > > #define VPL011_UNLOCK(d,flags) > > spin_unlock_irqrestore(&(d)->arch.vpl011.lock, flags) > > > > #define SBSA_UART_FIFO_SIZE 32 > > +struct vpl011_xen_backend { > > + char in[SBSA_UART_FIFO_SIZE]; > > + XENCONS_RING_IDX in_cons, in_prod; > > +}; > > > > struct vpl011 { > > + bool backend_in_domain; > > union { > > struct { > > void *ring_buf; > > struct page_info *ring_page; > > } dom; > > + struct vpl011_xen_backend *xen; > > } backend; > > uint32_t uartfr; /* Flag register */ > > uint32_t uartcr; /* Control register */ > > @@ -57,6 +64,7 @@ struct vpl011_init_info { > > int domain_vpl011_init(struct domain *d, > > struct vpl011_init_info *info); > > void domain_vpl011_deinit(struct domain *d); > > +void vpl011_rx_char_xen(struct domain *d, char c); > > #else > > static inline int domain_vpl011_init(struct domain *d, > > struct vpl011_init_info *info) _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |