[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
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? > + 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) > -- > 1.9.1 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@xxxxxxxxxxxxxxxxxxxx > https://lists.xenproject.org/mailman/listinfo/xen-devel -- Regards, Oleksandr Tyshchenko _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |