xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/14 v4] PL011 emulation support in Xen
@ 2017-06-06 17:25 Bhupinder Thakur
  2017-06-06 17:25 ` [PATCH 01/14 v4] xen/arm: vpl011: Move vgic register access functions to vreg.h Bhupinder Thakur
                   ` (14 more replies)
  0 siblings, 15 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

PL011 emulation for guests in Xen
===================================
Linaro has published VM System specification for ARM Processors, which
provides a set of guidelines for both guest OS and hypervisor implementations, 
such that building OS images according to these guidelines guarantees
that those images can also run on hypervisors compliant with this specification.

One of the spec requirements is that the hypervisor must provide an
emulated PL011 UART as a serial console which meets the minimum requirements in 
SBSA UART as defined in appendix B of the following 
ARM Server Base Architecture Document:

https://static.docs.arm.com/den0029/a/Server_Base_System_Architecture_v3_1_ARM_DEN_0029A.pdf.

This feature allows the Xen guests to use SBSA compliant pl011 UART as 
as a console. 

Note that SBSA pl011 UART is a subset of full featured ARM pl011 UART and
supports only a subset of registers as mentioned below. It does not support
rx/tx DMA.

Currently, Xen supports paravirtualized (aka PV console) and an emulated serial 
consoles. This feature will expose an emulated SBSA pl011 UART console to the
guest, which a user can access using xenconsole.

The device tree passed to the guest VM will contain the pl011 MMIO address 
range and an irq for receiving rx/tx pl011 interrupts. The device tree format 
is specified in Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt.

The Xen hypervisor will expose two types of interfaces to the backend and domU. 

The interface exposed to domU will be an emulated pl011 UART by emulating the 
access to the following pl011 registers by the guest.

- Data register (DR)            - RW
- Raw interrupt status register (RIS)   - RO
- Masked interrupt status register (MIS)- RO
- Interrupt Mask (IMSC)         - RW
- Interrupt Clear (ICR)         - WO

It will also inject the pl011 interrupts to the guest in the following 
conditions:

- incoming data in the rx buffer for the guest
- there is space in the tx buffer for the guest to write more data

The interface exposed to the backend will be the same PV console interface, 
which minimizes the changes required in xenconsole to support a new pl011 console.

This interface has rx and tx ring buffers and an event channel for 
sending/receiving events from the backend. 

So essentially Xen handles the data on behalf of domU and the backend. Any data 
written by domU is captured by Xen and written to the TX (OUT) ring buffer 
and a pl011 event is raised to the backend to read the TX ring buffer.
 
Similarly on reciving a pl011 event, Xen injects an interrupt to guest to
indicate there is data available in the RX (IN) ring buffer.

The pl011 UART state is completely captured in the set of registers 
mentioned above and this state is updated everytime there is an event from 
the backend or there is register read/write access from domU. 

For example, if domU has masked the rx interrupt in the IMSC register, then Xen 
will not inject an interrupt to guest and will just update the RIS register. 
Once the interrupt is unmasked by guest, the interrupt will be delivered to the 
guest.

Changes summary:

Xen Hypervisor
===============

1. Add emulation code to emulate read/write access to pl011 registers and pl011 
   interrupts:
    - It emulates DR read/write by reading and writing from/to the IN and 
      OUT ring buffers and raising an event to dom0 when there is data in 
      the OUT ring buffer and injecting an interrupt to the guest when there 
      is data in the IN ring buffer.
    - Other registers are related to interrupt management and essentially 
      control when interrupts are delivered to the guest.

2. Add a new domctl API to initialize vpl011 emulation in Xen.

3. Enable vpl011 emulation for a domain based on a libxl option passed during 
   domain creation.

Toolstack
==========

1. Add a new option "vuart" in the domU configuration file to enable/disable vuart.

2. Create a SBSA UART DT node in the guest device tree. It uses a fixed
   vpl011 SPI IRQ number and MMIO address.

3. Call vpl011 init DOMCTL API to enable vpl011 emulation.

5. Add a new vuart xenstore node, which contains:
    - ring-ref
    - event channel
    - buffer limit
    - type

Xenconsoled
============

1. Split the domain structure to support multiple consoles.

2. Modify different APIs such as buffer_append() etc. to operate on the 
   console structure.
   
3. Add support for handling multiple consoles.

4. Add support for vuart console:

The vpl011 changes available at the following repo:

url: ssh://git@git.linaro.org:/people/bhupinder.thakur/xen.git
branch: vpl011_v4

There are some TBD items which need to be looked at in the future:

1. Currently UEFI firmware logs the output to hvc console only. How can 
   UEFI firmware be made aware of pl011 console and how it can use it
   as a console instead of hvc.
2. Linux seems to have hvc console as the default console i.e. if no
   console is specified then it uses hvc as the console. How can an 
   option be provided in Linux to select either hvc or pl011 as the 
   default console.

3. ACPI support for pl011 device.

CC: ij
CC: wl
CC: ss
CC: jg
CC: kw

Bhupinder Thakur (14):
  xen/arm: vpl011: Move vgic register access functions to vreg.h
  xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h
  xen/arm: vpl011: Add pl011 uart emulation in Xen
  xen/arm: vpl011: Add support for vuart in libxl
  xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart
  xen/arm: vpl011: Add a new domctl API to initialize vpl011
  xen/arm: vpl011: Add a new vuart node in the xenstore
  xen/arm: vpl011: Modify xenconsole to define and use a new console    
    structure
  xen/arm: vpl011: Modify xenconsole functions to take console structure
    as input
  xen/arm: vpl011: Modify xenconsole to support multiple consoles
  xen/arm: vpl011: Add support for vuart console in xenconsole
  xen/arm: vpl011: Add a new vuart console type to xenconsole client
  xen/arm: vpl011: Add a pl011 uart DT node in the guest device tree
  xen/arm: vpl011: Update documentation for vuart console support

 config/arm32.mk                      |   1 +
 config/arm64.mk                      |   1 +
 docs/man/xl.cfg.pod.5.in             |   9 +
 docs/misc/console.txt                |  44 ++-
 tools/console/Makefile               |   4 +-
 tools/console/client/main.c          |  25 +-
 tools/console/daemon/io.c            | 544 ++++++++++++++++++++++++-----------
 tools/libxc/include/xc_dom.h         |   3 +
 tools/libxc/include/xenctrl.h        |  17 ++
 tools/libxc/xc_dom_arm.c             |  12 +-
 tools/libxc/xc_dom_boot.c            |   2 +
 tools/libxc/xc_domain.c              |  23 ++
 tools/libxl/libxl.h                  |   6 +
 tools/libxl/libxl_arch.h             |   7 +
 tools/libxl/libxl_arm.c              |  71 ++++-
 tools/libxl/libxl_console.c          |  47 +++
 tools/libxl/libxl_create.c           |  12 +-
 tools/libxl/libxl_device.c           |   9 +-
 tools/libxl/libxl_dom.c              |   8 +-
 tools/libxl/libxl_internal.h         |   7 +
 tools/libxl/libxl_types.idl          |   7 +
 tools/libxl/libxl_types_internal.idl |   1 +
 tools/libxl/libxl_x86.c              |   8 +
 tools/xl/Makefile                    |   4 +
 tools/xl/xl_cmdtable.c               |   4 +
 tools/xl/xl_console.c                |  11 +-
 tools/xl/xl_parse.c                  |   8 +
 xen/arch/arm/Kconfig                 |   5 +
 xen/arch/arm/Makefile                |   1 +
 xen/arch/arm/domain.c                |   2 +
 xen/arch/arm/domctl.c                |  44 ++-
 xen/arch/arm/vgic-v2.c               |  28 +-
 xen/arch/arm/vgic-v3.c               |  40 +--
 xen/arch/arm/vpl011.c                | 418 +++++++++++++++++++++++++++
 xen/include/asm-arm/domain.h         |   6 +
 xen/include/asm-arm/pl011-uart.h     |   2 +
 xen/include/asm-arm/vgic.h           | 111 +------
 xen/include/asm-arm/vpl011.h         |  74 +++++
 xen/include/asm-arm/vreg.h           | 109 +++++++
 xen/include/public/arch-arm.h        |   6 +
 xen/include/public/domctl.h          |  12 +
 xen/include/public/io/console.h      |   4 +
 42 files changed, 1421 insertions(+), 336 deletions(-)
 create mode 100644 xen/arch/arm/vpl011.c
 create mode 100644 xen/include/asm-arm/vpl011.h

-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH 01/14 v4] xen/arm: vpl011: Move vgic register access functions to vreg.h
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-09 12:49   ` Julien Grall
  2017-06-06 17:25 ` [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h Bhupinder Thakur
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Julien Grall, Stefano Stabellini

These functions are generic in nature and can be reused by other emulation
code in Xen. One recent example is pl011 emulation, which needs similar
functions to read/write the registers.

This patch moves the register access function definitions from vgic.h to
vreg.h.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ss
CC: jg

Changes since v3:
- Moved the macro call VGIC_REG_HELPERS to vreg.h from vgic.h.

 xen/include/asm-arm/vgic.h | 111 +--------------------------------------------
 xen/include/asm-arm/vreg.h | 110 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+), 110 deletions(-)

diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 544867a..75c716e 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -20,6 +20,7 @@
 
 #include <xen/bitops.h>
 #include <asm/mmio.h>
+#include <asm-arm/vreg.h>
 
 struct pending_irq
 {
@@ -171,116 +172,6 @@ static inline int REG_RANK_NR(int b, uint32_t n)
     }
 }
 
-#define VGIC_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
-
-/*
- * The check on the size supported by the register has to be done by
- * the caller of vgic_regN_*.
- *
- * vgic_reg_* should never be called directly. Instead use the vgic_regN_*
- * according to size of the emulated register
- *
- * Note that the alignment fault will always be taken in the guest
- * (see B3.12.7 DDI0406.b).
- */
-static inline register_t vgic_reg_extract(unsigned long reg,
-                                          unsigned int offset,
-                                          enum dabt_size size)
-{
-    reg >>= 8 * offset;
-    reg &= VGIC_REG_MASK(size);
-
-    return reg;
-}
-
-static inline void vgic_reg_update(unsigned long *reg, register_t val,
-                                   unsigned int offset,
-                                   enum dabt_size size)
-{
-    unsigned long mask = VGIC_REG_MASK(size);
-    int shift = offset * 8;
-
-    *reg &= ~(mask << shift);
-    *reg |= ((unsigned long)val & mask) << shift;
-}
-
-static inline void vgic_reg_setbits(unsigned long *reg, register_t bits,
-                                    unsigned int offset,
-                                    enum dabt_size size)
-{
-    unsigned long mask = VGIC_REG_MASK(size);
-    int shift = offset * 8;
-
-    *reg |= ((unsigned long)bits & mask) << shift;
-}
-
-static inline void vgic_reg_clearbits(unsigned long *reg, register_t bits,
-                                      unsigned int offset,
-                                      enum dabt_size size)
-{
-    unsigned long mask = VGIC_REG_MASK(size);
-    int shift = offset * 8;
-
-    *reg &= ~(((unsigned long)bits & mask) << shift);
-}
-
-/* N-bit register helpers */
-#define VGIC_REG_HELPERS(sz, offmask)                                   \
-static inline register_t vgic_reg##sz##_extract(uint##sz##_t reg,       \
-                                                const mmio_info_t *info)\
-{                                                                       \
-    return vgic_reg_extract(reg, info->gpa & offmask,                   \
-                            info->dabt.size);                           \
-}                                                                       \
-                                                                        \
-static inline void vgic_reg##sz##_update(uint##sz##_t *reg,             \
-                                         register_t val,                \
-                                         const mmio_info_t *info)       \
-{                                                                       \
-    unsigned long tmp = *reg;                                           \
-                                                                        \
-    vgic_reg_update(&tmp, val, info->gpa & offmask,                     \
-                    info->dabt.size);                                   \
-                                                                        \
-    *reg = tmp;                                                         \
-}                                                                       \
-                                                                        \
-static inline void vgic_reg##sz##_setbits(uint##sz##_t *reg,            \
-                                          register_t bits,              \
-                                          const mmio_info_t *info)      \
-{                                                                       \
-    unsigned long tmp = *reg;                                           \
-                                                                        \
-    vgic_reg_setbits(&tmp, bits, info->gpa & offmask,                   \
-                     info->dabt.size);                                  \
-                                                                        \
-    *reg = tmp;                                                         \
-}                                                                       \
-                                                                        \
-static inline void vgic_reg##sz##_clearbits(uint##sz##_t *reg,          \
-                                            register_t bits,            \
-                                            const mmio_info_t *info)    \
-{                                                                       \
-    unsigned long tmp = *reg;                                           \
-                                                                        \
-    vgic_reg_clearbits(&tmp, bits, info->gpa & offmask,                 \
-                       info->dabt.size);                                \
-                                                                        \
-    *reg = tmp;                                                         \
-}
-
-/*
- * 64 bits registers are only supported on platform with 64-bit long.
- * This is also allow us to optimize the 32 bit case by using
- * unsigned long rather than uint64_t
- */
-#if BITS_PER_LONG == 64
-VGIC_REG_HELPERS(64, 0x7);
-#endif
-VGIC_REG_HELPERS(32, 0x3);
-
-#undef VGIC_REG_HELPERS
-
 enum gic_sgi_mode;
 
 /*
diff --git a/xen/include/asm-arm/vreg.h b/xen/include/asm-arm/vreg.h
index ed2bd6f..348584f 100644
--- a/xen/include/asm-arm/vreg.h
+++ b/xen/include/asm-arm/vreg.h
@@ -107,4 +107,114 @@ static inline bool vreg_emulate_sysreg64(struct cpu_user_regs *regs, union hsr h
 
 #endif
 
+#define VGIC_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
+
+/*
+ * The check on the size supported by the register has to be done by
+ * the caller of vgic_regN_*.
+ *
+ * vgic_reg_* should never be called directly. Instead use the vgic_regN_*
+ * according to size of the emulated register
+ *
+ * Note that the alignment fault will always be taken in the guest
+ * (see B3.12.7 DDI0406.b).
+ */
+static inline register_t vgic_reg_extract(unsigned long reg,
+                                          unsigned int offset,
+                                          enum dabt_size size)
+{
+    reg >>= 8 * offset;
+    reg &= VGIC_REG_MASK(size);
+
+    return reg;
+}
+
+static inline void vgic_reg_update(unsigned long *reg, register_t val,
+                                   unsigned int offset,
+                                   enum dabt_size size)
+{
+    unsigned long mask = VGIC_REG_MASK(size);
+    int shift = offset * 8;
+
+    *reg &= ~(mask << shift);
+    *reg |= ((unsigned long)val & mask) << shift;
+}
+
+static inline void vgic_reg_setbits(unsigned long *reg, register_t bits,
+                                    unsigned int offset,
+                                    enum dabt_size size)
+{
+    unsigned long mask = VGIC_REG_MASK(size);
+    int shift = offset * 8;
+
+    *reg |= ((unsigned long)bits & mask) << shift;
+}
+
+static inline void vgic_reg_clearbits(unsigned long *reg, register_t bits,
+                                      unsigned int offset,
+                                      enum dabt_size size)
+{
+    unsigned long mask = VGIC_REG_MASK(size);
+    int shift = offset * 8;
+
+    *reg &= ~(((unsigned long)bits & mask) << shift);
+}
+
+/* N-bit register helpers */
+#define VGIC_REG_HELPERS(sz, offmask)                                   \
+static inline register_t vgic_reg##sz##_extract(uint##sz##_t reg,       \
+                                                const mmio_info_t *info)\
+{                                                                       \
+    return vgic_reg_extract(reg, info->gpa & offmask,                   \
+                            info->dabt.size);                           \
+}                                                                       \
+                                                                        \
+static inline void vgic_reg##sz##_update(uint##sz##_t *reg,             \
+                                         register_t val,                \
+                                         const mmio_info_t *info)       \
+{                                                                       \
+    unsigned long tmp = *reg;                                           \
+                                                                        \
+    vgic_reg_update(&tmp, val, info->gpa & offmask,                     \
+                    info->dabt.size);                                   \
+                                                                        \
+    *reg = tmp;                                                         \
+}                                                                       \
+                                                                        \
+static inline void vgic_reg##sz##_setbits(uint##sz##_t *reg,            \
+                                          register_t bits,              \
+                                          const mmio_info_t *info)      \
+{                                                                       \
+    unsigned long tmp = *reg;                                           \
+                                                                        \
+    vgic_reg_setbits(&tmp, bits, info->gpa & offmask,                   \
+                     info->dabt.size);                                  \
+                                                                        \
+    *reg = tmp;                                                         \
+}                                                                       \
+                                                                        \
+static inline void vgic_reg##sz##_clearbits(uint##sz##_t *reg,          \
+                                            register_t bits,            \
+                                            const mmio_info_t *info)    \
+{                                                                       \
+    unsigned long tmp = *reg;                                           \
+                                                                        \
+    vgic_reg_clearbits(&tmp, bits, info->gpa & offmask,                 \
+                       info->dabt.size);                                \
+                                                                        \
+    *reg = tmp;                                                         \
+}
+
+/*
+ * 64 bits registers are only supported on platform with 64-bit long.
+ * This is also allow us to optimize the 32 bit case by using
+ * unsigned long rather than uint64_t
+ */
+#if BITS_PER_LONG == 64
+VGIC_REG_HELPERS(64, 0x7);
+#endif
+VGIC_REG_HELPERS(32, 0x3);
+
+#undef VGIC_REG_HELPERS
+
 #endif /* __ASM_ARM_VREG__ */
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
  2017-06-06 17:25 ` [PATCH 01/14 v4] xen/arm: vpl011: Move vgic register access functions to vreg.h Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-09 12:54   ` Julien Grall
  2017-06-19  9:33   ` Andre Przywara
  2017-06-06 17:25 ` [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen Bhupinder Thakur
                   ` (12 subsequent siblings)
  14 siblings, 2 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Julien Grall, Stefano Stabellini

This patch redefines the vgic_reg* access functions to vreg_reg* functions.
These are generic functions, which will be used by the vgic emulation code
to access the vgic registers.

PL011 emulation code will also use vreg_reg* access functions.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ss
CC: jg

Changes since v3:
- Renamed DEFINE_VREG_REG_HELPERS to VREG_REG_HELPERS.

 xen/arch/arm/vgic-v2.c     |  28 +++++------
 xen/arch/arm/vgic-v3.c     |  40 ++++++++--------
 xen/include/asm-arm/vreg.h | 115 ++++++++++++++++++++++-----------------------
 3 files changed, 91 insertions(+), 92 deletions(-)

diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index dc9f95b..3e35a90 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -179,7 +179,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
     case VREG32(GICD_CTLR):
         if ( dabt.size != DABT_WORD ) goto bad_width;
         vgic_lock(v);
-        *r = vgic_reg32_extract(v->domain->arch.vgic.ctlr, info);
+        *r = vreg_reg32_extract(v->domain->arch.vgic.ctlr, info);
         vgic_unlock(v);
         return 1;
 
@@ -194,7 +194,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
             | DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32);
         vgic_unlock(v);
 
-        *r = vgic_reg32_extract(typer, info);
+        *r = vreg_reg32_extract(typer, info);
 
         return 1;
     }
@@ -205,7 +205,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
          * XXX Do we need a JEP106 manufacturer ID?
          * Just use the physical h/w value for now
          */
-        *r = vgic_reg32_extract(0x0000043b, info);
+        *r = vreg_reg32_extract(0x0000043b, info);
         return 1;
 
     case VRANGE32(0x00C, 0x01C):
@@ -226,7 +226,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ISENABLER, DABT_WORD);
         if ( rank == NULL) goto read_as_zero;
         vgic_lock_rank(v, rank, flags);
-        *r = vgic_reg32_extract(rank->ienable, info);
+        *r = vreg_reg32_extract(rank->ienable, info);
         vgic_unlock_rank(v, rank, flags);
         return 1;
 
@@ -235,7 +235,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICENABLER, DABT_WORD);
         if ( rank == NULL) goto read_as_zero;
         vgic_lock_rank(v, rank, flags);
-        *r = vgic_reg32_extract(rank->ienable, info);
+        *r = vreg_reg32_extract(rank->ienable, info);
         vgic_unlock_rank(v, rank, flags);
         return 1;
 
@@ -262,7 +262,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
                                                      gicd_reg - GICD_IPRIORITYR,
                                                      DABT_WORD)];
         vgic_unlock_rank(v, rank, flags);
-        *r = vgic_reg32_extract(ipriorityr, info);
+        *r = vreg_reg32_extract(ipriorityr, info);
 
         return 1;
     }
@@ -280,7 +280,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         vgic_lock_rank(v, rank, flags);
         itargetsr = vgic_fetch_itargetsr(rank, gicd_reg - GICD_ITARGETSR);
         vgic_unlock_rank(v, rank, flags);
-        *r = vgic_reg32_extract(itargetsr, info);
+        *r = vreg_reg32_extract(itargetsr, info);
 
         return 1;
     }
@@ -299,7 +299,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         icfgr = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR, DABT_WORD)];
         vgic_unlock_rank(v, rank, flags);
 
-        *r = vgic_reg32_extract(icfgr, info);
+        *r = vreg_reg32_extract(icfgr, info);
 
         return 1;
     }
@@ -424,7 +424,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
         if ( dabt.size != DABT_WORD ) goto bad_width;
         /* Ignore all but the enable bit */
         vgic_lock(v);
-        vgic_reg32_update(&v->domain->arch.vgic.ctlr, r, info);
+        vreg_reg32_update(&v->domain->arch.vgic.ctlr, r, info);
         v->domain->arch.vgic.ctlr &= GICD_CTL_ENABLE;
         vgic_unlock(v);
 
@@ -454,7 +454,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
         if ( rank == NULL) goto write_ignore;
         vgic_lock_rank(v, rank, flags);
         tr = rank->ienable;
-        vgic_reg32_setbits(&rank->ienable, r, info);
+        vreg_reg32_setbits(&rank->ienable, r, info);
         vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
         vgic_unlock_rank(v, rank, flags);
         return 1;
@@ -465,7 +465,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
         if ( rank == NULL) goto write_ignore;
         vgic_lock_rank(v, rank, flags);
         tr = rank->ienable;
-        vgic_reg32_clearbits(&rank->ienable, r, info);
+        vreg_reg32_clearbits(&rank->ienable, r, info);
         vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
         vgic_unlock_rank(v, rank, flags);
         return 1;
@@ -508,7 +508,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
         ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
                                                       gicd_reg - GICD_IPRIORITYR,
                                                       DABT_WORD)];
-        vgic_reg32_update(ipriorityr, r, info);
+        vreg_reg32_update(ipriorityr, r, info);
         vgic_unlock_rank(v, rank, flags);
         return 1;
     }
@@ -529,7 +529,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
         if ( rank == NULL) goto write_ignore;
         vgic_lock_rank(v, rank, flags);
         itargetsr = vgic_fetch_itargetsr(rank, gicd_reg - GICD_ITARGETSR);
-        vgic_reg32_update(&itargetsr, r, info);
+        vreg_reg32_update(&itargetsr, r, info);
         vgic_store_itargetsr(v->domain, rank, gicd_reg - GICD_ITARGETSR,
                              itargetsr);
         vgic_unlock_rank(v, rank, flags);
@@ -551,7 +551,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
         rank = vgic_rank_offset(v, 2, gicd_reg - GICD_ICFGR, DABT_WORD);
         if ( rank == NULL) goto write_ignore;
         vgic_lock_rank(v, rank, flags);
-        vgic_reg32_update(&rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR,
+        vreg_reg32_update(&rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR,
                                                      DABT_WORD)],
                           r, info);
         vgic_unlock_rank(v, rank, flags);
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index d10757a..e1213d9 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -181,7 +181,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
 
     case VREG32(GICR_IIDR):
         if ( dabt.size != DABT_WORD ) goto bad_width;
-        *r = vgic_reg32_extract(GICV3_GICR_IIDR_VAL, info);
+        *r = vreg_reg32_extract(GICV3_GICR_IIDR_VAL, info);
         return 1;
 
     case VREG64(GICR_TYPER):
@@ -199,7 +199,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
         if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST )
             typer |= GICR_TYPER_LAST;
 
-        *r = vgic_reg64_extract(typer, info);
+        *r = vreg_reg64_extract(typer, info);
 
         return 1;
     }
@@ -257,7 +257,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
     case VREG32(GICR_SYNCR):
         if ( dabt.size != DABT_WORD ) goto bad_width;
         /* RO . But when read it always returns busy bito bit[0] */
-        *r = vgic_reg32_extract(GICR_SYNCR_NOT_BUSY, info);
+        *r = vreg_reg32_extract(GICR_SYNCR_NOT_BUSY, info);
         return 1;
 
     case 0x00C8:
@@ -284,7 +284,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
 
     case VREG32(GICR_PIDR2):
         if ( dabt.size != DABT_WORD ) goto bad_width;
-        *r = vgic_reg32_extract(GICV3_GICR_PIDR2, info);
+        *r = vreg_reg32_extract(GICV3_GICR_PIDR2, info);
          return 1;
 
     case 0xFFEC ... 0xFFFC:
@@ -328,7 +328,7 @@ read_reserved:
     return 1;
 
 read_unknown:
-    *r = vgic_reg64_extract(0xdeadbeafdeadbeaf, info);
+    *r = vreg_reg64_extract(0xdeadbeafdeadbeaf, info);
     return 1;
 }
 
@@ -489,7 +489,7 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
         rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
         if ( rank == NULL ) goto read_as_zero;
         vgic_lock_rank(v, rank, flags);
-        *r = vgic_reg32_extract(rank->ienable, info);
+        *r = vreg_reg32_extract(rank->ienable, info);
         vgic_unlock_rank(v, rank, flags);
         return 1;
 
@@ -498,7 +498,7 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
         rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
         if ( rank == NULL ) goto read_as_zero;
         vgic_lock_rank(v, rank, flags);
-        *r = vgic_reg32_extract(rank->ienable, info);
+        *r = vreg_reg32_extract(rank->ienable, info);
         vgic_unlock_rank(v, rank, flags);
         return 1;
 
@@ -525,7 +525,7 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
                                                      DABT_WORD)];
         vgic_unlock_rank(v, rank, flags);
 
-        *r = vgic_reg32_extract(ipriorityr, info);
+        *r = vreg_reg32_extract(ipriorityr, info);
 
         return 1;
     }
@@ -541,7 +541,7 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
         icfgr = rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, DABT_WORD)];
         vgic_unlock_rank(v, rank, flags);
 
-        *r = vgic_reg32_extract(icfgr, info);
+        *r = vreg_reg32_extract(icfgr, info);
 
         return 1;
     }
@@ -585,7 +585,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
         if ( rank == NULL ) goto write_ignore;
         vgic_lock_rank(v, rank, flags);
         tr = rank->ienable;
-        vgic_reg32_setbits(&rank->ienable, r, info);
+        vreg_reg32_setbits(&rank->ienable, r, info);
         vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
         vgic_unlock_rank(v, rank, flags);
         return 1;
@@ -596,7 +596,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
         if ( rank == NULL ) goto write_ignore;
         vgic_lock_rank(v, rank, flags);
         tr = rank->ienable;
-        vgic_reg32_clearbits(&rank->ienable, r, info);
+        vreg_reg32_clearbits(&rank->ienable, r, info);
         vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
         vgic_unlock_rank(v, rank, flags);
         return 1;
@@ -638,7 +638,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
         vgic_lock_rank(v, rank, flags);
         ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8, reg - GICD_IPRIORITYR,
                                                       DABT_WORD)];
-        vgic_reg32_update(ipriorityr, r, info);
+        vreg_reg32_update(ipriorityr, r, info);
         vgic_unlock_rank(v, rank, flags);
         return 1;
     }
@@ -653,7 +653,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
         rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD);
         if ( rank == NULL ) goto write_ignore;
         vgic_lock_rank(v, rank, flags);
-        vgic_reg32_update(&rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR,
+        vreg_reg32_update(&rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR,
                                                      DABT_WORD)],
                           r, info);
         vgic_unlock_rank(v, rank, flags);
@@ -901,7 +901,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
     case VREG32(GICD_CTLR):
         if ( dabt.size != DABT_WORD ) goto bad_width;
         vgic_lock(v);
-        *r = vgic_reg32_extract(v->domain->arch.vgic.ctlr, info);
+        *r = vreg_reg32_extract(v->domain->arch.vgic.ctlr, info);
         vgic_unlock(v);
         return 1;
 
@@ -926,14 +926,14 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
 
         typer |= (irq_bits - 1) << GICD_TYPE_ID_BITS_SHIFT;
 
-        *r = vgic_reg32_extract(typer, info);
+        *r = vreg_reg32_extract(typer, info);
 
         return 1;
     }
 
     case VREG32(GICD_IIDR):
         if ( dabt.size != DABT_WORD ) goto bad_width;
-        *r = vgic_reg32_extract(GICV3_GICD_IIDR_VAL, info);
+        *r = vreg_reg32_extract(GICV3_GICD_IIDR_VAL, info);
         return 1;
 
     case VREG32(0x000C):
@@ -1026,7 +1026,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         irouter = vgic_fetch_irouter(rank, gicd_reg - GICD_IROUTER);
         vgic_unlock_rank(v, rank, flags);
 
-        *r = vgic_reg64_extract(irouter, info);
+        *r = vreg_reg64_extract(irouter, info);
 
         return 1;
     }
@@ -1044,7 +1044,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
     case VREG32(GICD_PIDR2):
         /* GICv3 identification value */
         if ( dabt.size != DABT_WORD ) goto bad_width;
-        *r = vgic_reg32_extract(GICV3_GICD_PIDR2, info);
+        *r = vreg_reg32_extract(GICV3_GICD_PIDR2, info);
         return 1;
 
     case VRANGE32(0xFFEC, 0xFFFC):
@@ -1107,7 +1107,7 @@ static int vgic_v3_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
 
         vgic_lock(v);
 
-        vgic_reg32_update(&ctlr, r, info);
+        vreg_reg32_update(&ctlr, r, info);
 
         /* Only EnableGrp1A can be changed */
         if ( ctlr & GICD_CTLR_ENABLE_G1A )
@@ -1213,7 +1213,7 @@ static int vgic_v3_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
         if ( rank == NULL ) goto write_ignore;
         vgic_lock_rank(v, rank, flags);
         irouter = vgic_fetch_irouter(rank, gicd_reg - GICD_IROUTER);
-        vgic_reg64_update(&irouter, r, info);
+        vreg_reg64_update(&irouter, r, info);
         vgic_store_irouter(v->domain, rank, gicd_reg - GICD_IROUTER, irouter);
         vgic_unlock_rank(v, rank, flags);
         return 1;
diff --git a/xen/include/asm-arm/vreg.h b/xen/include/asm-arm/vreg.h
index 348584f..16207ce 100644
--- a/xen/include/asm-arm/vreg.h
+++ b/xen/include/asm-arm/vreg.h
@@ -107,102 +107,102 @@ static inline bool vreg_emulate_sysreg64(struct cpu_user_regs *regs, union hsr h
 
 #endif
 
-#define VGIC_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
+#define VREG_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
 
 /*
  * The check on the size supported by the register has to be done by
- * the caller of vgic_regN_*.
+ * the caller of vreg_regN_*.
  *
- * vgic_reg_* should never be called directly. Instead use the vgic_regN_*
+ * vreg_reg_* should never be called directly. Instead use the vreg_regN_*
  * according to size of the emulated register
  *
  * Note that the alignment fault will always be taken in the guest
  * (see B3.12.7 DDI0406.b).
  */
-static inline register_t vgic_reg_extract(unsigned long reg,
+static inline register_t vreg_reg_extract(unsigned long reg,
                                           unsigned int offset,
                                           enum dabt_size size)
 {
     reg >>= 8 * offset;
-    reg &= VGIC_REG_MASK(size);
+    reg &= VREG_REG_MASK(size);
 
     return reg;
 }
 
-static inline void vgic_reg_update(unsigned long *reg, register_t val,
+static inline void vreg_reg_update(unsigned long *reg, register_t val,
                                    unsigned int offset,
                                    enum dabt_size size)
 {
-    unsigned long mask = VGIC_REG_MASK(size);
+    unsigned long mask = VREG_REG_MASK(size);
     int shift = offset * 8;
 
     *reg &= ~(mask << shift);
     *reg |= ((unsigned long)val & mask) << shift;
 }
 
-static inline void vgic_reg_setbits(unsigned long *reg, register_t bits,
+static inline void vreg_reg_setbits(unsigned long *reg, register_t bits,
                                     unsigned int offset,
                                     enum dabt_size size)
 {
-    unsigned long mask = VGIC_REG_MASK(size);
+    unsigned long mask = VREG_REG_MASK(size);
     int shift = offset * 8;
 
     *reg |= ((unsigned long)bits & mask) << shift;
 }
 
-static inline void vgic_reg_clearbits(unsigned long *reg, register_t bits,
+static inline void vreg_reg_clearbits(unsigned long *reg, register_t bits,
                                       unsigned int offset,
                                       enum dabt_size size)
 {
-    unsigned long mask = VGIC_REG_MASK(size);
+    unsigned long mask = VREG_REG_MASK(size);
     int shift = offset * 8;
 
     *reg &= ~(((unsigned long)bits & mask) << shift);
 }
 
-/* N-bit register helpers */
-#define VGIC_REG_HELPERS(sz, offmask)                                   \
-static inline register_t vgic_reg##sz##_extract(uint##sz##_t reg,       \
-                                                const mmio_info_t *info)\
-{                                                                       \
-    return vgic_reg_extract(reg, info->gpa & offmask,                   \
-                            info->dabt.size);                           \
-}                                                                       \
-                                                                        \
-static inline void vgic_reg##sz##_update(uint##sz##_t *reg,             \
-                                         register_t val,                \
-                                         const mmio_info_t *info)       \
-{                                                                       \
-    unsigned long tmp = *reg;                                           \
-                                                                        \
-    vgic_reg_update(&tmp, val, info->gpa & offmask,                     \
-                    info->dabt.size);                                   \
-                                                                        \
-    *reg = tmp;                                                         \
-}                                                                       \
-                                                                        \
-static inline void vgic_reg##sz##_setbits(uint##sz##_t *reg,            \
-                                          register_t bits,              \
-                                          const mmio_info_t *info)      \
-{                                                                       \
-    unsigned long tmp = *reg;                                           \
-                                                                        \
-    vgic_reg_setbits(&tmp, bits, info->gpa & offmask,                   \
-                     info->dabt.size);                                  \
-                                                                        \
-    *reg = tmp;                                                         \
-}                                                                       \
-                                                                        \
-static inline void vgic_reg##sz##_clearbits(uint##sz##_t *reg,          \
-                                            register_t bits,            \
-                                            const mmio_info_t *info)    \
-{                                                                       \
-    unsigned long tmp = *reg;                                           \
-                                                                        \
-    vgic_reg_clearbits(&tmp, bits, info->gpa & offmask,                 \
-                       info->dabt.size);                                \
-                                                                        \
-    *reg = tmp;                                                         \
+#define VREG_REG_HELPERS(sz, offmask)                                           \
+/* N-bit register helpers */                                                    \
+static inline register_t vreg_reg##sz##_extract(uint##sz##_t reg,               \
+                                                  const mmio_info_t *info)      \
+{                                                                               \
+    return vreg_reg_extract(reg, info->gpa & offmask,                           \
+                            info->dabt.size);                                   \
+}                                                                               \
+                                                                                \
+static inline void vreg_reg##sz##_update(uint##sz##_t *reg,                     \
+                                           register_t val,                      \
+                                           const mmio_info_t *info)             \
+{                                                                               \
+    unsigned long tmp = *reg;                                                   \
+                                                                                \
+    vreg_reg_update(&tmp, val, info->gpa & offmask,                             \
+                    info->dabt.size);                                           \
+                                                                                \
+    *reg = tmp;                                                                 \
+}                                                                               \
+                                                                                \
+static inline void vreg_reg##sz##_setbits(uint##sz##_t *reg,                    \
+                                            register_t bits,                    \
+                                            const mmio_info_t *info)            \
+{                                                                               \
+    unsigned long tmp = *reg;                                                   \
+                                                                                \
+    vreg_reg_setbits(&tmp, bits, info->gpa & offmask,                           \
+                     info->dabt.size);                                          \
+                                                                                \
+    *reg = tmp;                                                                 \
+}                                                                               \
+                                                                                \
+static inline void vreg_reg##sz##_clearbits(uint##sz##_t *reg,                  \
+                                              register_t bits,                  \
+                                              const mmio_info_t *info)          \
+{                                                                               \
+    unsigned long tmp = *reg;                                                   \
+                                                                                \
+    vreg_reg_clearbits(&tmp, bits, info->gpa & offmask,                         \
+                       info->dabt.size);                                        \
+                                                                                \
+    *reg = tmp;                                                                 \
 }
 
 /*
@@ -211,10 +211,9 @@ static inline void vgic_reg##sz##_clearbits(uint##sz##_t *reg,          \
  * unsigned long rather than uint64_t
  */
 #if BITS_PER_LONG == 64
-VGIC_REG_HELPERS(64, 0x7);
+VREG_REG_HELPERS(64, 0x7);
 #endif
-VGIC_REG_HELPERS(32, 0x3);
-
-#undef VGIC_REG_HELPERS
+VREG_REG_HELPERS(32, 0x3);
+#undef VREG_REG_HELPERS
 
 #endif /* __ASM_ARM_VREG__ */
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
  2017-06-06 17:25 ` [PATCH 01/14 v4] xen/arm: vpl011: Move vgic register access functions to vreg.h Bhupinder Thakur
  2017-06-06 17:25 ` [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-06 23:02   ` Stefano Stabellini
                     ` (2 more replies)
  2017-06-06 17:25 ` [PATCH 04/14 v4] xen/arm: vpl011: Add support for vuart in libxl Bhupinder Thakur
                   ` (11 subsequent siblings)
  14 siblings, 3 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

Add emulation code to emulate read/write access to pl011 registers
and pl011 interrupts:

    - Emulate DR read/write by reading and writing from/to the IN
      and OUT ring buffers and raising an event to the backend when
      there is data in the OUT ring buffer and injecting an interrupt
      to the guest when there is data in the IN ring buffer

    - Other registers are related to interrupt management and
      essentially control when interrupts are delivered to the guest

The SBSA compliant pl011 uart is covered in Appendix B of
https://static.docs.arm.com/den0029/a/Server_Base_System_Architecture_v3_1_ARM_DEN_0029A.pdf

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg
CC: kw

Changes since v3:
- Moved the call to DEFINE_XEN_FLEX_RING from vpl011.h to public/console.h. This macro defines
  standard functions to operate on the ring buffer.
- Lock taken while updating the interrupt mask and clear registers in mmio_write.
- Use gfn_t instead of xen_pfn_t.
- vgic_free_virq called if there is any error in vpl011 initialization.
- mmio handlers freed if there is any error in vpl011 initialization.
- Removed vpl011->initialized flag usage as the same check could be done 
  using vpl011->ring-ref.
- Used return instead of break in the switch handling of emulation of different pl011 registers.
- Renamed vpl011_update_spi() to vpl011_update().

Changes since v2:
- Use generic vreg_reg* for read/write of registers emulating pl011.
- Use generic ring buffer functions defined using DEFINE_XEN_FLEX_RING.
- Renamed the SPI injection function to vpl011_update_spi() to reflect level 
  triggered nature of pl011 interrupts.
- The pl011 register access address should always be the base address of the
  corresponding register as per section B of the SBSA document. For this reason,
  the register range address access is not allowed.

Changes since v1:
- Removed the optimiztion related to sendiing events to xenconsole 
- Use local variables as ring buffer indices while using the ring buffer

 tools/console/daemon/io.c        |   2 +-
 xen/arch/arm/Kconfig             |   5 +
 xen/arch/arm/Makefile            |   1 +
 xen/arch/arm/vpl011.c            | 418 +++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/domain.h     |   6 +
 xen/include/asm-arm/pl011-uart.h |   2 +
 xen/include/asm-arm/vpl011.h     |  74 +++++++
 xen/include/public/arch-arm.h    |   6 +
 xen/include/public/io/console.h  |   4 +
 9 files changed, 517 insertions(+), 1 deletion(-)
 create mode 100644 xen/arch/arm/vpl011.c
 create mode 100644 xen/include/asm-arm/vpl011.h

diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index 7e6a886..947f13a 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -21,6 +21,7 @@
 
 #include "utils.h"
 #include "io.h"
+#include <string.h>
 #include <xenevtchn.h>
 #include <xengnttab.h>
 #include <xenstore.h>
@@ -29,7 +30,6 @@
 
 #include <stdlib.h>
 #include <errno.h>
-#include <string.h>
 #include <poll.h>
 #include <fcntl.h>
 #include <unistd.h>
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index d46b98c..c1a0e7f 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -50,6 +50,11 @@ config HAS_ITS
         prompt "GICv3 ITS MSI controller support" if EXPERT = "y"
         depends on HAS_GICV3
 
+config VPL011_CONSOLE
+	bool "Emulated pl011 console support"
+	default y
+	---help---
+	  Allows a guest to use pl011 UART as a console
 endmenu
 
 menu "ARM errata workaround via the alternative framework"
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 49e1fb2..15efc13 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -52,6 +52,7 @@ obj-y += vm_event.o
 obj-y += vtimer.o
 obj-y += vpsci.o
 obj-y += vuart.o
+obj-$(CONFIG_VPL011_CONSOLE) += vpl011.o
 
 #obj-bin-y += ....o
 
diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
new file mode 100644
index 0000000..9b1f27e
--- /dev/null
+++ b/xen/arch/arm/vpl011.c
@@ -0,0 +1,418 @@
+/*
+ * arch/arm/vpl011.c
+ *
+ * Virtual PL011 UART
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/errno.h>
+#include <xen/event.h>
+#include <xen/guest_access.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/sched.h>
+#include <public/domctl.h>
+#include <public/io/console.h>
+#include <asm-arm/pl011-uart.h>
+#include <asm-arm/vgic-emul.h>
+#include <asm-arm/vpl011.h>
+
+static bool vpl011_reg32_check_access(struct hsr_dabt dabt)
+{
+    return (dabt.size != DABT_DOUBLE_WORD);
+}
+
+static void vpl011_update(struct domain *d)
+{
+    struct vpl011 *vpl011 = &d->arch.vpl011;
+
+    /*
+     * TODO: PL011 interrupts are level triggered which means
+     * that interrupt needs to be set/clear instead of being
+     * injected. However, currently vGIC does not handle level 
+     * triggered interrupts properly. This function needs to be 
+     * revisited once vGIC starts handling level triggered 
+     * interrupts.
+     */
+    if ( vpl011->uartris & vpl011->uartimsc )
+        vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI);
+}
+
+static uint8_t vpl011_read_data(struct domain *d)
+{
+    unsigned long flags;
+    uint8_t data = 0;
+    struct vpl011 *vpl011 = &d->arch.vpl011;
+    struct xencons_interface *intf = vpl011->ring_buf;
+    XENCONS_RING_IDX in_cons = intf->in_cons;
+    XENCONS_RING_IDX in_prod = intf->in_prod;
+
+    VPL011_LOCK(d, flags);
+
+    /*
+     * 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 )
+    {
+        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
+        in_cons += 1;
+        intf->in_cons = in_cons;
+        smp_mb();
+    }
+    else
+    {
+        gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer empty\n");
+    }
+
+    if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == 0 )
+    {
+        vpl011->uartfr |= RXFE;
+        vpl011->uartris &= ~RXI;
+    }
+    vpl011->uartfr &= ~RXFF;
+    VPL011_UNLOCK(d, flags);
+
+    return data;
+}
+
+static void vpl011_write_data(struct domain *d, uint8_t data)
+{
+    unsigned long flags;
+    struct vpl011 *vpl011 = &d->arch.vpl011;
+    struct xencons_interface *intf = vpl011->ring_buf;
+    XENCONS_RING_IDX out_cons = intf->out_cons;
+    XENCONS_RING_IDX out_prod = intf->out_prod;
+
+    VPL011_LOCK(d, flags);
+
+    /*
+     * It is expected that the ring is not full when this function is called
+     * as the guest is expected to write to the data register only when the
+     * TXFF flag is not set.
+     * In case the guest does write even when the TXFF flag is set then the
+     * data will be silently dropped.
+     */
+    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) !=
+         sizeof (intf->out) )
+    {
+        intf->out[xencons_mask(out_prod, sizeof(intf->out))] = data;
+        smp_wmb();
+        out_prod += 1;
+        intf->out_prod = out_prod;
+    }
+    else
+    {
+        gprintk(XENLOG_ERR, "vpl011: Unexpected OUT ring buffer full\n");
+    }
+
+    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) ==
+         sizeof (intf->out) )
+    {
+        vpl011->uartfr |= TXFF;
+        vpl011->uartris &= ~TXI;
+    }
+
+    vpl011->uartfr |= BUSY;
+
+    vpl011->uartfr &= ~TXFE;
+
+    VPL011_UNLOCK(d, flags);
+
+    /*
+     * Send an event to console backend to indicate that there is 
+     * data in the OUT ring buffer.
+     */
+    notify_via_xen_event_channel(d, vpl011->evtchn);
+}
+
+static int vpl011_mmio_read(struct vcpu *v,
+                            mmio_info_t *info,
+                            register_t *r,
+                            void *priv)
+{
+    struct hsr_dabt dabt = info->dabt;
+    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
+    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
+
+    switch ( vpl011_reg )
+    {
+    case DR:
+        /*
+         * Since pl011 registers are 32-bit registers, all registers
+         * are handled similarly allowing 8-bit, 16-bit and 32-bit
+         * accesses.
+         */
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        *r = vreg_reg32_extract(vpl011_read_data(v->domain), info);
+        return 1;
+
+    case RSR:
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        /* It always returns 0 as there are no physical errors. */
+        *r = 0;
+        return 1;
+
+    case FR:
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        *r = vreg_reg32_extract(vpl011->uartfr, info);
+        return 1;
+
+    case RIS:
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        *r = vreg_reg32_extract(vpl011->uartris, info);
+        return 1;
+
+    case MIS:
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        *r = vreg_reg32_extract(vpl011->uartris & 
+                                vpl011->uartimsc, info);
+        return 1;
+
+    case IMSC:
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        *r = vreg_reg32_extract(vpl011->uartimsc, info);
+        return 1;
+
+    case ICR:
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        /* Only write is valid. */
+        return 0;
+
+    default:
+        gprintk(XENLOG_ERR, "vpl011: unhandled read r%d offset %#08x\n",
+                dabt.reg, vpl011_reg);
+        return 0;
+    }
+
+    return 1;
+
+bad_width:
+    gprintk(XENLOG_ERR, "vpl011: bad read width %d r%d offset %#08x\n",
+            dabt.size, dabt.reg, vpl011_reg);
+    domain_crash_synchronous();
+    return 0;
+
+}
+
+static int vpl011_mmio_write(struct vcpu *v,
+                             mmio_info_t *info,
+                             register_t r,
+                             void *priv)
+{
+    struct hsr_dabt dabt = info->dabt;
+    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
+    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
+    struct domain *d = v->domain;
+    unsigned long flags;
+
+    switch ( vpl011_reg )
+    {
+    case DR:
+    {
+        uint32_t data = 0;
+
+        /*
+         * Since pl011 registers are 32-bit registers, all registers
+         * are handled similarly allowing 8-bit, 16-bit and 32-bit
+         * accesses.
+         */
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        vreg_reg32_update(&data, r, info);
+        data &= 0xFF;
+        vpl011_write_data(v->domain, data);
+        return 1;
+    }
+    case RSR: /* Nothing to clear. */
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        return 1; 
+
+    case FR:
+    case RIS:
+    case MIS:
+        goto write_ignore;
+
+    case IMSC:
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        VPL011_LOCK(d, flags);
+        vreg_reg32_update(&vpl011->uartimsc, r, info);
+        VPL011_UNLOCK(d, flags);
+        vpl011_update(v->domain);
+        return 1;
+
+    case ICR:
+        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
+
+        VPL011_LOCK(d, flags);
+        vreg_reg32_clearbits(&vpl011->uartris, r, info);
+        VPL011_UNLOCK(d, flags);
+        vpl011_update(d);
+        return 1;
+
+    default:
+        gprintk(XENLOG_ERR, "vpl011: unhandled write r%d offset %#08x\n",
+                dabt.reg, vpl011_reg);
+        return 0;
+    }
+
+write_ignore:
+    return 1;
+
+bad_width:
+    gprintk(XENLOG_ERR, "vpl011: bad write width %d r%d offset %#08x\n",
+            dabt.size, dabt.reg, vpl011_reg);
+    domain_crash_synchronous();
+    return 0;
+
+}
+
+static const struct mmio_handler_ops vpl011_mmio_handler = {
+    .read = vpl011_mmio_read,
+    .write = vpl011_mmio_write,
+};
+
+static void vpl011_data_avail(struct domain *d)
+{
+    unsigned long flags;
+    struct vpl011 *vpl011 = &d->arch.vpl011;
+    struct xencons_interface *intf = vpl011->ring_buf;
+    XENCONS_RING_IDX in_cons = intf->in_cons;
+    XENCONS_RING_IDX in_prod = intf->in_prod;
+    XENCONS_RING_IDX out_cons = intf->out_cons;
+    XENCONS_RING_IDX out_prod = intf->out_prod;
+    XENCONS_RING_IDX in_ring_qsize, out_ring_qsize;
+
+    VPL011_LOCK(d, flags);
+
+    in_ring_qsize = xencons_queued(in_prod,
+                                   in_cons,
+                                   sizeof(intf->in));
+
+    out_ring_qsize = xencons_queued(out_prod,
+                                    out_cons,
+                                    sizeof(intf->out));
+
+    /* Update the uart rx state if the buffer is not empty. */
+    if ( in_ring_qsize != 0 )
+    {
+        vpl011->uartfr &= ~RXFE;
+        if ( in_ring_qsize == sizeof(intf->in) )
+            vpl011->uartfr |= RXFF;
+        vpl011->uartris |= RXI;
+    }
+
+    /* Update the uart tx state if the buffer is not full. */
+    if ( out_ring_qsize != sizeof(intf->out) )
+    {
+        vpl011->uartfr &= ~TXFF;
+        vpl011->uartris |= TXI;
+        if ( out_ring_qsize == 0 )
+        {
+            vpl011->uartfr &= ~BUSY;
+            vpl011->uartfr |= TXFE;
+        }
+    }
+
+    VPL011_UNLOCK(d, flags);
+
+    vpl011_update(d);
+}
+
+
+static void vpl011_notification(struct vcpu *v, unsigned int port)
+{
+    vpl011_data_avail(v->domain);
+}
+
+int domain_vpl011_init(struct domain *d, struct vpl011_init_info *info)
+{
+    int rc;
+    struct vpl011 *vpl011 = &d->arch.vpl011;
+
+    if ( vpl011->ring_buf )
+        return 0;
+
+    /* Map the guest PFN to Xen address space. */
+    rc =  prepare_ring_for_helper(d,
+                                  gfn_x(info->gfn),
+                                  &vpl011->ring_page,
+                                  &vpl011->ring_buf);
+    if ( rc < 0 )
+        goto out;
+
+    rc = vgic_reserve_virq(d, GUEST_VPL011_SPI);
+    if ( !rc )
+    {
+        rc = -EINVAL;
+        goto out1;
+    }
+
+    register_mmio_handler(d, &vpl011_mmio_handler,
+                          GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);
+
+    spin_lock_init(&vpl011->lock);
+
+    rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid,
+                                         vpl011_notification);
+    if ( rc < 0 )
+        goto out2;
+
+    vpl011->evtchn = info->evtchn = rc;
+
+    return 0;
+
+out2:
+    xfree(d->arch.vmmio.handlers);
+    vgic_free_virq(d, GUEST_VPL011_SPI);
+
+out1:
+    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
+
+out:
+    return rc;
+}
+
+void domain_vpl011_deinit(struct domain *d)
+{
+    struct vpl011 *vpl011 = &d->arch.vpl011;
+
+    if ( !vpl011->ring_buf )
+        return;
+
+    free_xen_event_channel(d, vpl011->evtchn);
+    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
+    xfree(d->arch.vmmio.handlers);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 6de8082..91d1061 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -11,6 +11,7 @@
 #include <public/hvm/params.h>
 #include <xen/serial.h>
 #include <xen/rbtree.h>
+#include <asm-arm/vpl011.h>
 
 struct hvm_domain
 {
@@ -133,6 +134,11 @@ struct arch_domain
     struct {
         uint8_t privileged_call_enabled : 1;
     } monitor;
+
+#ifdef CONFIG_VPL011_CONSOLE
+    struct vpl011 vpl011;
+#endif
+
 }  __cacheline_aligned;
 
 struct arch_vcpu
diff --git a/xen/include/asm-arm/pl011-uart.h b/xen/include/asm-arm/pl011-uart.h
index 123f477..57e9ec7 100644
--- a/xen/include/asm-arm/pl011-uart.h
+++ b/xen/include/asm-arm/pl011-uart.h
@@ -49,6 +49,8 @@
 /* FR bits */
 #define TXFE   (1<<7) /* TX FIFO empty */
 #define RXFE   (1<<4) /* RX FIFO empty */
+#define TXFF   (1<<5) /* TX FIFO full */
+#define RXFF   (1<<6) /* RX FIFO full */
 #define BUSY   (1<<3) /* Transmit is not complete */
 
 /* LCR_H bits */
diff --git a/xen/include/asm-arm/vpl011.h b/xen/include/asm-arm/vpl011.h
new file mode 100644
index 0000000..b3e332d
--- /dev/null
+++ b/xen/include/asm-arm/vpl011.h
@@ -0,0 +1,74 @@
+/*
+ * include/xen/vpl011.h
+ *
+ * Virtual PL011 UART
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _VPL011_H_
+
+#define _VPL011_H_
+
+#include <public/domctl.h>
+#include <public/io/ring.h>
+#include <asm-arm/vreg.h>
+#include <xen/mm.h>
+
+/* helper macros */
+#define VPL011_LOCK(d,flags) spin_lock_irqsave(&(d)->arch.vpl011.lock, flags)
+#define VPL011_UNLOCK(d,flags) spin_unlock_irqrestore(&(d)->arch.vpl011.lock, flags)
+
+struct vpl011 {
+    void *ring_buf;
+    struct page_info *ring_page;
+    uint32_t    uartfr;     /* Flag register */
+    uint32_t    uartcr;     /* Control register */
+    uint32_t    uartimsc;   /* Interrupt mask register*/
+    uint32_t    uarticr;    /* Interrupt clear register */
+    uint32_t    uartris;    /* Raw interrupt status register */
+    uint32_t    uartmis;    /* Masked interrupt register */
+    spinlock_t  lock;
+    evtchn_port_t evtchn;
+};
+
+struct vpl011_init_info {
+    uint32_t console_domid;
+    gfn_t gfn;
+    evtchn_port_t evtchn;
+};
+
+#ifdef CONFIG_VPL011_CONSOLE
+int domain_vpl011_init(struct domain *d,
+                       struct vpl011_init_info *info);
+void domain_vpl011_deinit(struct domain *d);
+#else
+static inline int domain_vpl011_init(struct domain *d,
+                                     struct vpl011_init_info *info)
+{
+    return -ENOSYS;
+}
+
+static inline void domain_vpl011_deinit(struct domain *d) { }
+#endif
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index bd974fb..85ab665 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -410,6 +410,10 @@ typedef uint64_t xen_callback_t;
 #define GUEST_ACPI_BASE 0x20000000ULL
 #define GUEST_ACPI_SIZE 0x02000000ULL
 
+/* PL011 mappings */
+#define GUEST_PL011_BASE    0x22000000ULL
+#define GUEST_PL011_SIZE    0x00001000ULL
+
 /*
  * 16MB == 4096 pages reserved for guest to use as a region to map its
  * grant table in.
@@ -444,6 +448,8 @@ typedef uint64_t xen_callback_t;
 #define GUEST_TIMER_PHYS_NS_PPI 30
 #define GUEST_EVTCHN_PPI        31
 
+#define GUEST_VPL011_SPI        32
+
 /* PSCI functions */
 #define PSCI_cpu_suspend 0
 #define PSCI_cpu_off     1
diff --git a/xen/include/public/io/console.h b/xen/include/public/io/console.h
index e2cd97f..5e45e1c 100644
--- a/xen/include/public/io/console.h
+++ b/xen/include/public/io/console.h
@@ -27,6 +27,8 @@
 #ifndef __XEN_PUBLIC_IO_CONSOLE_H__
 #define __XEN_PUBLIC_IO_CONSOLE_H__
 
+#include "ring.h"
+
 typedef uint32_t XENCONS_RING_IDX;
 
 #define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
@@ -38,6 +40,8 @@ struct xencons_interface {
     XENCONS_RING_IDX out_cons, out_prod;
 };
 
+DEFINE_XEN_FLEX_RING(xencons);
+
 #endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
 
 /*
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 04/14 v4] xen/arm: vpl011: Add support for vuart in libxl
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (2 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-06 23:07   ` Stefano Stabellini
  2017-06-06 17:25 ` [PATCH 05/14 v4] xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart Bhupinder Thakur
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

An option is provided in libxl to enable/disable pl011 vuart while
creating a guest domain.

Libxl now suppots a generic vuart console and pl011 is a specific type.
In future support can be added for multiple vuart of different types.

User can enable pl011 vuart by adding the following line in the guest
configuration file:

vuart = "pl011"

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- Added a new config option CONFIG_VUART_CONSOLE to enable/disable vuart console
  support.
- Moved libxl_vuart_type to arch-arm part of libxl_domain_build_info
- Updated xl command help to mention new console type - vuart.

Changes since v2:
- Defined vuart option as an enum instead of a string.
- Removed the domain creation flag defined for vuart and the related code
  to pass on the information while domain creation. Now vpl011 is initialized
  independent of domain creation through new DOMCTL APIs.

 config/arm32.mk              |  1 +
 config/arm64.mk              |  1 +
 tools/libxl/libxl.h          |  6 ++++++
 tools/libxl/libxl_console.c  |  3 +++
 tools/libxl/libxl_internal.h |  3 +++
 tools/libxl/libxl_types.idl  |  7 +++++++
 tools/xl/Makefile            |  4 ++++
 tools/xl/xl_cmdtable.c       |  4 ++++
 tools/xl/xl_console.c        | 11 ++++++++++-
 tools/xl/xl_parse.c          |  8 ++++++++
 10 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/config/arm32.mk b/config/arm32.mk
index f95228e..b9f23fe 100644
--- a/config/arm32.mk
+++ b/config/arm32.mk
@@ -1,5 +1,6 @@
 CONFIG_ARM := y
 CONFIG_ARM_32 := y
+CONFIG_VUART_CONSOLE := y
 CONFIG_ARM_$(XEN_OS) := y
 
 CONFIG_XEN_INSTALL_SUFFIX :=
diff --git a/config/arm64.mk b/config/arm64.mk
index aa45772..861d0a4 100644
--- a/config/arm64.mk
+++ b/config/arm64.mk
@@ -1,5 +1,6 @@
 CONFIG_ARM := y
 CONFIG_ARM_64 := y
+CONFIG_VUART_CONSOLE := y
 CONFIG_ARM_$(XEN_OS) := y
 
 CONFIG_XEN_INSTALL_SUFFIX :=
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index cf8687a..bcfbb6c 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -306,6 +306,12 @@
 #define LIBXL_HAVE_BUILDINFO_HVM_ACPI_LAPTOP_SLATE 1
 
 /*
+ * LIBXL_HAVE_VUART indicates that xenconsole/client supports
+ * virtual uart.
+ */
+#define LIBXL_HAVE_VUART 1
+
+/*
  * libxl ABI compatibility
  *
  * The only guarantee which libxl makes regarding ABI compatibility
diff --git a/tools/libxl/libxl_console.c b/tools/libxl/libxl_console.c
index 446e766..853be15 100644
--- a/tools/libxl/libxl_console.c
+++ b/tools/libxl/libxl_console.c
@@ -67,6 +67,9 @@ int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num,
     case LIBXL_CONSOLE_TYPE_SERIAL:
         cons_type_s = "serial";
         break;
+    case LIBXL_CONSOLE_TYPE_VUART:
+        cons_type_s = "vuart";
+        break;
     default:
         goto out;
     }
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 5d082c5..4e2c247 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1135,6 +1135,9 @@ typedef struct {
     uint32_t num_vmemranges;
 
     xc_domain_configuration_t config;
+
+    xen_pfn_t vuart_gfn;
+    evtchn_port_t vuart_port;
 } libxl__domain_build_state;
 
 _hidden int libxl__build_pre(libxl__gc *gc, uint32_t domid,
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 2204425..066aace 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -105,6 +105,7 @@ libxl_console_type = Enumeration("console_type", [
     (0, "UNKNOWN"),
     (1, "SERIAL"),
     (2, "PV"),
+    (3, "VUART"),
     ])
 
 libxl_disk_format = Enumeration("disk_format", [
@@ -240,6 +241,11 @@ libxl_checkpointed_stream = Enumeration("checkpointed_stream", [
     (2, "COLO"),
     ])
 
+libxl_vuart_type = Enumeration("vuart_type", [
+    (0, "unknown"),
+    (1, "pl011"),
+    ])
+
 #
 # Complex libxl types
 #
@@ -580,6 +586,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
 
 
     ("arch_arm", Struct(None, [("gic_version", libxl_gic_version),
+                               ("vuart", libxl_vuart_type),
                               ])),
     # Alternate p2m is not bound to any architecture or guest type, as it is
     # supported by x86 HVM and ARM support is planned.
diff --git a/tools/xl/Makefile b/tools/xl/Makefile
index e16f877..d7c4927 100644
--- a/tools/xl/Makefile
+++ b/tools/xl/Makefile
@@ -15,6 +15,10 @@ LDFLAGS += $(PTHREAD_LDFLAGS)
 CFLAGS_XL += $(CFLAGS_libxenlight)
 CFLAGS_XL += -Wshadow
 
+ifeq ($(CONFIG_VUART_CONSOLE),y)
+CFLAGS_XL += -DCONFIG_VUART_CONSOLE
+endif
+
 XL_OBJS = xl.o xl_cmdtable.o xl_sxp.o xl_utils.o
 XL_OBJS += xl_tmem.o xl_parse.o xl_cpupool.o xl_flask.o
 XL_OBJS += xl_vtpm.o xl_block.o xl_nic.o xl_usb.o
diff --git a/tools/xl/xl_cmdtable.c b/tools/xl/xl_cmdtable.c
index 30eb93c..14f7a50 100644
--- a/tools/xl/xl_cmdtable.c
+++ b/tools/xl/xl_cmdtable.c
@@ -133,7 +133,11 @@ struct cmd_spec cmd_table[] = {
       &main_console, 0, 0,
       "Attach to domain's console",
       "[options] <Domain>\n"
+#ifdef CONFIG_VUART_CONSOLE
+      "-t <type>       console type, pv , serial or vuart\n"
+#else
       "-t <type>       console type, pv or serial\n"
+#endif
       "-n <number>     console number"
     },
     { "vncviewer",
diff --git a/tools/xl/xl_console.c b/tools/xl/xl_console.c
index 0508dda..d6ca93f 100644
--- a/tools/xl/xl_console.c
+++ b/tools/xl/xl_console.c
@@ -27,6 +27,11 @@ int main_console(int argc, char **argv)
     uint32_t domid;
     int opt = 0, num = 0;
     libxl_console_type type = 0;
+#ifdef CONFIG_VUART_CONSOLE
+    char *console_names = "pv, serial, vuart";
+#else
+    char *console_names = "pv, serial";
+#endif
 
     SWITCH_FOREACH_OPT(opt, "n:t:", NULL, "console", 1) {
     case 't':
@@ -34,8 +39,12 @@ int main_console(int argc, char **argv)
             type = LIBXL_CONSOLE_TYPE_PV;
         else if (!strcmp(optarg, "serial"))
             type = LIBXL_CONSOLE_TYPE_SERIAL;
+#ifdef CONFIG_VUART_CONSOLE
+        else if (!strcmp(optarg, "vuart"))
+            type = LIBXL_CONSOLE_TYPE_VUART;
+#endif
         else {
-            fprintf(stderr, "console type supported are: pv, serial\n");
+            fprintf(stderr, "console type supported are: %s\n", console_names);
             return EXIT_FAILURE;
         }
         break;
diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
index 856a304..37581ef 100644
--- a/tools/xl/xl_parse.c
+++ b/tools/xl/xl_parse.c
@@ -916,6 +916,14 @@ void parse_config_data(const char *config_source,
     if (!xlu_cfg_get_long (config, "maxvcpus", &l, 0))
         b_info->max_vcpus = l;
 
+    if (!xlu_cfg_get_string(config, "vuart", &buf, 0)) {
+        if (libxl_vuart_type_from_string(buf, &b_info->arch_arm.vuart)) {
+            fprintf(stderr, "ERROR: invalid value \"%s\" for \"vuart\"\n",
+                    buf);
+            exit(1);
+        }
+    }
+
     parse_vnuma_config(config, b_info);
 
     /* Set max_memkb to target_memkb and max_vcpus to avail_vcpus if
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 05/14 v4] xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (3 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 04/14 v4] xen/arm: vpl011: Add support for vuart in libxl Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-06 23:17   ` Stefano Stabellini
  2017-06-07 16:43   ` Wei Liu
  2017-06-06 17:25 ` [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011 Bhupinder Thakur
                   ` (9 subsequent siblings)
  14 siblings, 2 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

Allocate a new gfn to be used as a ring buffer between xenconsole
and Xen for sending/receiving pl011 console data.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- Added a new helper function xc_get_vuart_gfn() to return the GFN allocated for
  vpl011.
- Since a new function has been added in this patch, I have not included Stefano's
  reviewed-by and Wei's acked-by tags.

Changes since v2:
- Removed the DOMCTL call to set the GFN as now this information is passed
  in the DOMCTL call to initialize vpl011 emulation.

 tools/libxc/include/xc_dom.h |  3 +++
 tools/libxc/xc_dom_arm.c     | 12 +++++++++++-
 tools/libxc/xc_dom_boot.c    |  2 ++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/tools/libxc/include/xc_dom.h b/tools/libxc/include/xc_dom.h
index ce47058..1cde2b7 100644
--- a/tools/libxc/include/xc_dom.h
+++ b/tools/libxc/include/xc_dom.h
@@ -216,6 +216,8 @@ struct xc_dom_image {
 
     /* Extra SMBIOS structures passed to HVMLOADER */
     struct xc_hvm_firmware_module smbios_module;
+
+    xen_pfn_t vuart_gfn;
 };
 
 /* --- pluggable kernel loader ------------------------------------- */
@@ -334,6 +336,7 @@ int xc_dom_gnttab_seed(xc_interface *xch, domid_t domid,
                        domid_t console_domid,
                        domid_t xenstore_domid);
 bool xc_dom_translated(const struct xc_dom_image *dom);
+xen_pfn_t xc_get_vuart_gfn(void);
 
 /* --- debugging bits ---------------------------------------------- */
 
diff --git a/tools/libxc/xc_dom_arm.c b/tools/libxc/xc_dom_arm.c
index e7d4bd0..89d0d37 100644
--- a/tools/libxc/xc_dom_arm.c
+++ b/tools/libxc/xc_dom_arm.c
@@ -26,10 +26,11 @@
 #include "xg_private.h"
 #include "xc_dom.h"
 
-#define NR_MAGIC_PAGES 3
+#define NR_MAGIC_PAGES 4
 #define CONSOLE_PFN_OFFSET 0
 #define XENSTORE_PFN_OFFSET 1
 #define MEMACCESS_PFN_OFFSET 2
+#define VUART_PFN_OFFSET 3
 
 #define LPAE_SHIFT 9
 
@@ -64,6 +65,13 @@ static int setup_pgtables_arm(struct xc_dom_image *dom)
 
 /* ------------------------------------------------------------------------ */
 
+xen_pfn_t xc_get_vuart_gfn()
+{
+    const xen_pfn_t base = GUEST_MAGIC_BASE >> XC_PAGE_SHIFT;
+
+    return base + VUART_PFN_OFFSET;
+}
+
 static int alloc_magic_pages(struct xc_dom_image *dom)
 {
     int rc, i;
@@ -85,10 +93,12 @@ static int alloc_magic_pages(struct xc_dom_image *dom)
 
     dom->console_pfn = base + CONSOLE_PFN_OFFSET;
     dom->xenstore_pfn = base + XENSTORE_PFN_OFFSET;
+    dom->vuart_gfn = base + VUART_PFN_OFFSET;
 
     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->console_pfn);
     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->xenstore_pfn);
     xc_clear_domain_page(dom->xch, dom->guest_domid, base + MEMACCESS_PFN_OFFSET);
+    xc_clear_domain_page(dom->xch, dom->guest_domid, base + VUART_PFN_OFFSET);
     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CONSOLE_PFN,
             dom->console_pfn);
     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_STORE_PFN,
diff --git a/tools/libxc/xc_dom_boot.c b/tools/libxc/xc_dom_boot.c
index c3b44dd..8a376d0 100644
--- a/tools/libxc/xc_dom_boot.c
+++ b/tools/libxc/xc_dom_boot.c
@@ -226,6 +226,8 @@ int xc_dom_boot_image(struct xc_dom_image *dom)
         return rc;
     if ( (rc = clear_page(dom, dom->xenstore_pfn)) != 0 )
         return rc;
+    if ( (rc = clear_page(dom, dom->vuart_gfn)) != 0 )
+        return rc;
 
     /* start info page */
     if ( dom->arch_hooks->start_info )
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (4 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 05/14 v4] xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-06 23:26   ` Stefano Stabellini
  2017-06-09 14:13   ` Julien Grall
  2017-06-06 17:25 ` [PATCH 07/14 v4] xen/arm: vpl011: Add a new vuart node in the xenstore Bhupinder Thakur
                   ` (8 subsequent siblings)
  14 siblings, 2 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

Add a new domctl API to initialize vpl011. It takes the GFN and console
backend domid as input and returns an event channel to be used for
sending and receiving events from Xen.

Xen will communicate with xenconsole using GFN as the ring buffer and
the event channel to transmit and receive pl011 data on the guest domain's
behalf.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- Added a new arch specific function libxl__arch_domain_create_finish(), which
  calls the vpl011 initialization function. For x86 this function does not do
  anything.
- domain_vpl011_init() takes a pointer to a structure which contains all the 
  required information such as console_domid, gfn instead of passing parameters
  separately.
- Dropped a DOMCTL API defined for de-initializing vpl011 as that should be
  taken care when the domain is destroyed (and not dependent on userspace 
  libraries/applications).

Changes since v2:
- Replaced the DOMCTL APIs defined for get/set of event channel and GFN with 
  a set of DOMCTL APIs for initializing and de-initializing vpl011 emulation.

 tools/libxc/include/xenctrl.h | 17 +++++++++++++++++
 tools/libxc/xc_domain.c       | 23 ++++++++++++++++++++++
 tools/libxl/libxl_arch.h      |  7 +++++++
 tools/libxl/libxl_arm.c       | 19 +++++++++++++++++++
 tools/libxl/libxl_dom.c       |  6 +++++-
 tools/libxl/libxl_x86.c       |  8 ++++++++
 xen/arch/arm/domain.c         |  2 ++
 xen/arch/arm/domctl.c         | 44 ++++++++++++++++++++++++++++++++++++++++---
 xen/include/public/domctl.h   | 12 ++++++++++++
 9 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 1629f41..77425dd 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -884,6 +884,23 @@ int xc_vcpu_getcontext(xc_interface *xch,
                        uint32_t domid,
                        uint32_t vcpu,
                        vcpu_guest_context_any_t *ctxt);
+/**
+ * This function initializes the vpl011 emulation and returns
+ * the event to be used by the backend for communicating with
+ * the emulation code.
+ *
+ * @parm xch a handle to an open hypervisor interface
+ * @parm domid the domain to get information from
+ * @parm console_domid the domid of the backend console
+ * @parm gfn the guest pfn to be used as the ring buffer
+ * @parm evtchn the event channel to be used for events
+ * @return 0 on success, negative error on failure
+ */
+int xc_dom_vpl011_init(xc_interface *xch,
+                       uint32_t domid,
+                       uint32_t console_domid,
+                       xen_pfn_t gfn,
+                       evtchn_port_t *evtchn);
 
 /**
  * This function returns information about the XSAVE state of a particular
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 00909ad4..a8efd5e 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -343,6 +343,29 @@ int xc_domain_get_guest_width(xc_interface *xch, uint32_t domid,
     return 0;
 }
 
+int xc_dom_vpl011_init(xc_interface *xch,
+                       uint32_t domid,
+                       uint32_t console_domid,
+                       xen_pfn_t gfn,
+                       evtchn_port_t *evtchn)
+{
+    DECLARE_DOMCTL;
+    int rc = 0;
+
+    domctl.cmd = XEN_DOMCTL_vuart_op;
+    domctl.domain = (domid_t)domid;
+    domctl.u.vuart_op.cmd = XEN_DOMCTL_VUART_OP_INIT_VPL011;
+    domctl.u.vuart_op.console_domid = console_domid;
+    domctl.u.vuart_op.gfn = gfn;
+
+    if ( (rc = do_domctl(xch, &domctl)) < 0 )
+        return rc;
+
+    *evtchn = domctl.u.vuart_op.evtchn;
+
+    return rc;
+}
+
 int xc_domain_getinfo(xc_interface *xch,
                       uint32_t first_domid,
                       unsigned int max_doms,
diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
index 5e1fc60..d1ca9c6 100644
--- a/tools/libxl/libxl_arch.h
+++ b/tools/libxl/libxl_arch.h
@@ -32,6 +32,13 @@ _hidden
 int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
                uint32_t domid);
 
+/* arch specific internal domain creation finish function */
+_hidden
+int libxl__arch_domain_create_finish(libxl__gc *gc,
+                                     libxl_domain_build_info *info,
+                                     uint32_t domid,
+                                     libxl__domain_build_state *state);
+
 /* setup arch specific hardware description, i.e. DTB on ARM */
 _hidden
 int libxl__arch_domain_init_hw_description(libxl__gc *gc,
diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
index d842d88..b60dfa9 100644
--- a/tools/libxl/libxl_arm.c
+++ b/tools/libxl/libxl_arm.c
@@ -106,6 +106,25 @@ int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
     return 0;
 }
 
+int libxl__arch_domain_create_finish(libxl__gc *gc,
+                                     libxl_domain_build_info *info,
+                                     uint32_t domid,
+                                     libxl__domain_build_state *state)
+{
+    int ret = 0;
+
+    if ( info->arch_arm.vuart &&
+         (ret = xc_dom_vpl011_init(CTX->xch,
+                                   domid,
+                                   state->console_domid,
+                                   xc_get_vuart_gfn(),
+                                   &state->vuart_port)) != 0 ) {
+        LOG(ERROR, "xc_dom_vpl011_init failed\n");
+    }
+
+    return ret;
+}
+
 int libxl__arch_extra_memory(libxl__gc *gc,
                              const libxl_domain_build_info *info,
                              uint64_t *out)
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index 5d914a5..187c5bd 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -587,7 +587,10 @@ retry_transaction:
             goto retry_transaction;
     xs_introduce_domain(ctx->xsh, domid, state->store_mfn, state->store_port);
     free(vm_path);
-    return 0;
+
+    rc = libxl__arch_domain_create_finish(gc, info, domid, state);
+
+    return rc;
 }
 
 static int set_vnuma_info(libxl__gc *gc, uint32_t domid,
@@ -788,6 +791,7 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
     if (xc_dom_translated(dom)) {
         state->console_mfn = dom->console_pfn;
         state->store_mfn = dom->xenstore_pfn;
+        state->vuart_gfn = dom->vuart_gfn;
     } else {
         state->console_mfn = xc_dom_p2m(dom, dom->console_pfn);
         state->store_mfn = xc_dom_p2m(dom, dom->xenstore_pfn);
diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
index 455f6f0..3544028 100644
--- a/tools/libxl/libxl_x86.c
+++ b/tools/libxl/libxl_x86.c
@@ -358,6 +358,14 @@ out:
     return ret;
 }
 
+int libxl__arch_domain_create_finish(libxl__gc *gc,
+                                     libxl_domain_build_info *info,
+                                     uint32_t domid,
+                                     libxl__domain_build_state *state)
+{
+    return 0;
+}
+
 int libxl__arch_extra_memory(libxl__gc *gc,
                              const libxl_domain_build_info *info,
                              uint64_t *out)
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 76310ed..9e150ba 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -665,6 +665,8 @@ fail:
 
 void arch_domain_destroy(struct domain *d)
 {
+    domain_vpl011_deinit(d);
+
     /* IOMMU page table is shared with P2M, always call
      * iommu_domain_destroy() before p2m_teardown().
      */
diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
index 971caec..741679b 100644
--- a/xen/arch/arm/domctl.c
+++ b/xen/arch/arm/domctl.c
@@ -5,13 +5,15 @@
  */
 
 #include <xen/types.h>
-#include <xen/lib.h>
+#include <public/domctl.h>
 #include <xen/errno.h>
-#include <xen/sched.h>
+#include <xen/guest_access.h>
 #include <xen/hypercall.h>
 #include <xen/iocap.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/sched.h>
 #include <xsm/xsm.h>
-#include <public/domctl.h>
 
 void arch_get_domain_info(const struct domain *d,
                           struct xen_domctl_getdomaininfo *info)
@@ -119,6 +121,42 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
         d->disable_migrate = domctl->u.disable_migrate.disable;
         return 0;
 
+    case XEN_DOMCTL_vuart_op:
+    {
+        int rc;
+        struct xen_domctl_vuart_op *vuart_op = &domctl->u.vuart_op;
+
+        switch(vuart_op->cmd)
+        {
+        case XEN_DOMCTL_VUART_OP_INIT_VPL011:
+
+            if ( !d->creation_finished )
+            {
+                struct vpl011_init_info info;
+
+                info.console_domid = vuart_op->console_domid;
+                info.gfn = _gfn(vuart_op->gfn);
+
+                rc = domain_vpl011_init(d, &info);
+                if ( !rc )
+                {
+                    vuart_op->evtchn = info.evtchn;
+                    rc = __copy_to_guest(u_domctl, domctl, 1);
+                }
+            }
+            else
+            {
+                rc = - EPERM;
+            }
+            break;
+
+        default:
+            rc = -EINVAL;
+            break;
+        }
+
+        return rc;
+    }
     default:
     {
         int rc;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index e6cf211..c6ff458 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -36,6 +36,7 @@
 #include "grant_table.h"
 #include "hvm/save.h"
 #include "memory.h"
+#include "event_channel.h"
 
 #define XEN_DOMCTL_INTERFACE_VERSION 0x0000000d
 
@@ -1138,6 +1139,15 @@ struct xen_domctl_psr_cat_op {
     uint32_t target;    /* IN */
     uint64_t data;      /* IN/OUT */
 };
+
+struct xen_domctl_vuart_op {
+#define XEN_DOMCTL_VUART_OP_INIT_VPL011  0
+        uint32_t cmd;           /* XEN_DOMCTL_VUART_OP_* */
+        uint32_t console_domid; /* IN */
+        xen_pfn_t gfn;          /* IN */
+        evtchn_port_t evtchn;   /* OUT */
+};
+
 typedef struct xen_domctl_psr_cat_op xen_domctl_psr_cat_op_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cat_op_t);
 
@@ -1218,6 +1228,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_monitor_op                    77
 #define XEN_DOMCTL_psr_cat_op                    78
 #define XEN_DOMCTL_soft_reset                    79
+#define XEN_DOMCTL_vuart_op                      80
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1280,6 +1291,7 @@ struct xen_domctl {
         struct xen_domctl_psr_cmt_op        psr_cmt_op;
         struct xen_domctl_monitor_op        monitor_op;
         struct xen_domctl_psr_cat_op        psr_cat_op;
+        struct xen_domctl_vuart_op          vuart_op;
         uint8_t                             pad[128];
     } u;
 };
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 07/14 v4] xen/arm: vpl011: Add a new vuart node in the xenstore
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (5 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011 Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-06 23:38   ` Stefano Stabellini
  2017-06-06 17:25 ` [PATCH 08/14 v4] xen/arm: vpl011: Modify xenconsole to define and use a new console structure Bhupinder Thakur
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

Add a new vuart console node to xenstore. This node is added at

/local/domain/$DOMID/vuart/0.

The node contains information such as the ring-ref, event channel,
buffer limit and type of console.

Xenconsole reads the node information to setup the ring buffer and
event channel for sending/receiving vuart data.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- Added a backend node for vpl011.
- Removed libxl__device_vuart_add() for HVM guest. It is called only for PV guest.

 tools/libxl/libxl_console.c          | 44 ++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_create.c           | 12 ++++++++--
 tools/libxl/libxl_device.c           |  9 ++++++--
 tools/libxl/libxl_internal.h         |  4 ++++
 tools/libxl/libxl_types_internal.idl |  1 +
 5 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/tools/libxl/libxl_console.c b/tools/libxl/libxl_console.c
index 853be15..259f865 100644
--- a/tools/libxl/libxl_console.c
+++ b/tools/libxl/libxl_console.c
@@ -344,6 +344,50 @@ out:
     return rc;
 }
 
+int libxl__device_vuart_add(libxl__gc *gc, uint32_t domid,
+                            libxl__device_console *console,
+                            libxl__domain_build_state *state,
+                            libxl__device *device)
+{
+    flexarray_t *ro_front;
+    flexarray_t *back;
+    int rc;
+
+    ro_front = flexarray_make(gc, 16, 1);
+    back = flexarray_make(gc, 16, 1);
+
+    device->backend_devid = console->devid;
+    device->backend_domid = console->backend_domid;
+    device->backend_kind = LIBXL__DEVICE_KIND_VUART;
+    device->devid = console->devid;
+    device->domid = domid;
+    device->kind = LIBXL__DEVICE_KIND_VUART;
+
+    flexarray_append(back, "frontend-id");
+    flexarray_append(back, GCSPRINTF("%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
+    flexarray_append(back, "protocol");
+    flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
+
+    flexarray_append(ro_front, "port");
+    flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->vuart_port));
+    flexarray_append(ro_front, "ring-ref");
+    flexarray_append(ro_front, GCSPRINTF("%lu", state->vuart_gfn));
+    flexarray_append(ro_front, "limit");
+    flexarray_append(ro_front, GCSPRINTF("%d", LIBXL_XENCONSOLE_LIMIT));
+    flexarray_append(ro_front, "type");
+    flexarray_append(ro_front, "xenconsoled");
+
+    rc = libxl__device_generic_add(gc, XBT_NULL, device,
+                                   libxl__xs_kvs_of_flexarray(gc, back),
+                                   NULL,
+                                   libxl__xs_kvs_of_flexarray(gc, ro_front));
+    return rc;
+}
+
 int libxl__init_console_from_channel(libxl__gc *gc,
                                      libxl__device_console *console,
                                      int dev_num,
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index bffbc45..091a661 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -1367,14 +1367,22 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
     }
     case LIBXL_DOMAIN_TYPE_PV:
     {
-        libxl__device_console console;
-        libxl__device device;
+        libxl__device_console console, vuart;
+        libxl__device device, vuart_device;
 
         for (i = 0; i < d_config->num_vfbs; i++) {
             libxl__device_vfb_add(gc, domid, &d_config->vfbs[i]);
             libxl__device_vkb_add(gc, domid, &d_config->vkbs[i]);
         }
 
+        if (d_config->b_info.arch_arm.vuart)
+        {
+            init_console_info(gc, &vuart, 0);
+            vuart.backend_domid = state->console_domid;
+            libxl__device_vuart_add(gc, domid, &vuart, state, &vuart_device);
+            libxl__device_console_dispose(&vuart);
+        }
+
         init_console_info(gc, &console, 0);
         console.backend_domid = state->console_domid;
         libxl__device_console_add(gc, domid, &console, state, &device);
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 5e96676..b110041 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -26,6 +26,9 @@ static char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
     if (device->kind == LIBXL__DEVICE_KIND_CONSOLE && device->devid == 0)
         return GCSPRINTF("%s/console", dom_path);
 
+    if (device->kind == LIBXL__DEVICE_KIND_VUART)
+        return GCSPRINTF("%s/vuart/%d", dom_path, device->devid);
+
     return GCSPRINTF("%s/device/%s/%d", dom_path,
                      libxl__device_kind_to_string(device->kind),
                      device->devid);
@@ -170,7 +173,8 @@ retry_transaction:
          * historically contained other information, such as the
          * vnc-port, which we don't want the guest fiddling with.
          */
-        if (device->kind == LIBXL__DEVICE_KIND_CONSOLE && device->devid == 0)
+        if ((device->kind == LIBXL__DEVICE_KIND_CONSOLE && device->devid == 0) ||
+            (device->kind == LIBXL__DEVICE_KIND_VUART))
             xs_set_permissions(ctx->xsh, t, frontend_path,
                                ro_frontend_perms, ARRAY_SIZE(ro_frontend_perms));
         else
@@ -800,7 +804,8 @@ void libxl__devices_destroy(libxl__egc *egc, libxl__devices_remove_state *drs)
                 dev->domid = domid;
                 dev->kind = kind;
                 dev->devid = atoi(devs[j]);
-                if (dev->backend_kind == LIBXL__DEVICE_KIND_CONSOLE) {
+                if (dev->backend_kind == LIBXL__DEVICE_KIND_CONSOLE ||
+                    dev->backend_kind == LIBXL__DEVICE_KIND_VUART) {
                     /* Currently console devices can be destroyed
                      * synchronously by just removing xenstore entries,
                      * this is what libxl__device_destroy does.
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 4e2c247..7a22db0 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1202,6 +1202,10 @@ _hidden int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
                                       libxl__device_console *console,
                                       libxl__domain_build_state *state,
                                       libxl__device *device);
+_hidden int libxl__device_vuart_add(libxl__gc *gc, uint32_t domid,
+                                    libxl__device_console *console,
+                                    libxl__domain_build_state *state,
+                                    libxl__device *device);
 
 /* Returns 1 if device exists, 0 if not, ERROR_* (<0) on error. */
 _hidden int libxl__device_exists(libxl__gc *gc, xs_transaction_t t,
diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl
index 7dc4d0f..c463c33 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -26,6 +26,7 @@ libxl__device_kind = Enumeration("device_kind", [
     (9, "VUSB"),
     (10, "QUSB"),
     (11, "9PFS"),
+    (12, "VUART"),
     ])
 
 libxl__console_backend = Enumeration("console_backend", [
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 08/14 v4] xen/arm: vpl011: Modify xenconsole to define and use a new console structure
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (6 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 07/14 v4] xen/arm: vpl011: Add a new vuart node in the xenstore Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-07  1:13   ` Stefano Stabellini
  2017-06-06 17:25 ` [PATCH 09/14 v4] xen/arm: vpl011: Modify xenconsole functions to take console structure as input Bhupinder Thakur
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

Xenconsole uses a domain structure which contains console specific fields. This
patch defines a new console structure, which would be used by the xenconsole
functions to perform console specific operations like reading/writing data from/to
the console ring buffer or reading/writing data from/to console tty.

This patch is in preparation to support multiple consoles to support vuart console.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- The changes in xenconsole have been split into four patches. This is the first patch
  which modifies the xenconsole to use a new console structure.

Changes since v2:
- Defined a new function console_create_ring() which sets up the ring buffer and 
  event channel a new console. domain_create_ring() uses this function to setup
  a console.
- This patch does not contain vuart specific changes, which would be introduced in
  the next patch.
- Changes for keeping the PV log file name unchanged.

Changes since v1:
- Split the domain struture to a separate console structure
- Modified the functions to operate on the console struture
- Replaced repetitive per console code with generic code

 tools/console/daemon/io.c | 226 ++++++++++++++++++++++++++--------------------
 1 file changed, 127 insertions(+), 99 deletions(-)

diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index 947f13a..0402ddf 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -89,25 +89,30 @@ struct buffer {
 	size_t max_capacity;
 };
 
-struct domain {
-	int domid;
+struct console {
 	int master_fd;
 	int master_pollfd_idx;
 	int slave_fd;
 	int log_fd;
-	bool is_dead;
-	unsigned last_seen;
 	struct buffer buffer;
-	struct domain *next;
 	char *conspath;
 	int ring_ref;
 	xenevtchn_port_or_error_t local_port;
 	xenevtchn_port_or_error_t remote_port;
+	struct xencons_interface *interface;
+	struct domain *d;
+};
+
+struct domain {
+	int domid;
+	bool is_dead;
+	unsigned last_seen;
+	struct domain *next;
 	xenevtchn_handle *xce_handle;
 	int xce_pollfd_idx;
-	struct xencons_interface *interface;
 	int event_count;
 	long long next_period;
+	struct console console;
 };
 
 static struct domain *dom_head;
@@ -160,9 +165,10 @@ static int write_with_timestamp(int fd, const char *data, size_t sz,
 
 static void buffer_append(struct domain *dom)
 {
-	struct buffer *buffer = &dom->buffer;
+	struct console *con = &dom->console;
+	struct buffer *buffer = &con->buffer;
 	XENCONS_RING_IDX cons, prod, size;
-	struct xencons_interface *intf = dom->interface;
+	struct xencons_interface *intf = con->interface;
 
 	cons = intf->out_cons;
 	prod = intf->out_prod;
@@ -187,22 +193,22 @@ static void buffer_append(struct domain *dom)
 
 	xen_mb();
 	intf->out_cons = cons;
-	xenevtchn_notify(dom->xce_handle, dom->local_port);
+	xenevtchn_notify(dom->xce_handle, con->local_port);
 
 	/* Get the data to the logfile as early as possible because if
 	 * no one is listening on the console pty then it will fill up
 	 * and handle_tty_write will stop being called.
 	 */
-	if (dom->log_fd != -1) {
+	if (con->log_fd != -1) {
 		int logret;
 		if (log_time_guest) {
 			logret = write_with_timestamp(
-				dom->log_fd,
+				con->log_fd,
 				buffer->data + buffer->size - size,
 				size, &log_time_guest_needts);
 		} else {
 			logret = write_all(
-				dom->log_fd,
+				con->log_fd,
 				buffer->data + buffer->size - size,
 				size);
 		}
@@ -338,14 +344,16 @@ static int create_domain_log(struct domain *dom)
 
 static void domain_close_tty(struct domain *dom)
 {
-	if (dom->master_fd != -1) {
-		close(dom->master_fd);
-		dom->master_fd = -1;
+	struct console *con = &dom->console;
+
+	if (con->master_fd != -1) {
+		close(con->master_fd);
+		con->master_fd = -1;
 	}
 
-	if (dom->slave_fd != -1) {
-		close(dom->slave_fd);
-		dom->slave_fd = -1;
+	if (con->slave_fd != -1) {
+		close(con->slave_fd);
+		con->slave_fd = -1;
 	}
 }
 
@@ -418,11 +426,12 @@ static int domain_create_tty(struct domain *dom)
 	char *data;
 	unsigned int len;
 	struct termios term;
+	struct console *con = &dom->console;
 
-	assert(dom->slave_fd == -1);
-	assert(dom->master_fd == -1);
+	assert(con->slave_fd == -1);
+	assert(con->master_fd == -1);
 
-	if (openpty(&dom->master_fd, &dom->slave_fd, NULL, NULL, NULL) < 0) {
+	if (openpty(&con->master_fd, &con->slave_fd, NULL, NULL, NULL) < 0) {
 		err = errno;
 		dolog(LOG_ERR, "Failed to create tty for domain-%d "
 		      "(errno = %i, %s)",
@@ -430,7 +439,7 @@ static int domain_create_tty(struct domain *dom)
 		return 0;
 	}
 
-	if (tcgetattr(dom->slave_fd, &term) < 0) {
+	if (tcgetattr(con->slave_fd, &term) < 0) {
 		err = errno;
 		dolog(LOG_ERR, "Failed to get tty attributes for domain-%d "
 			"(errno = %i, %s)",
@@ -438,7 +447,7 @@ static int domain_create_tty(struct domain *dom)
 		goto out;
 	}
 	cfmakeraw(&term);
-	if (tcsetattr(dom->slave_fd, TCSANOW, &term) < 0) {
+	if (tcsetattr(con->slave_fd, TCSANOW, &term) < 0) {
 		err = errno;
 		dolog(LOG_ERR, "Failed to set tty attributes for domain-%d "
 			"(errno = %i, %s)",
@@ -446,7 +455,7 @@ static int domain_create_tty(struct domain *dom)
 		goto out;
 	}
 
-	if ((slave = ptsname(dom->master_fd)) == NULL) {
+	if ((slave = ptsname(con->master_fd)) == NULL) {
 		err = errno;
 		dolog(LOG_ERR, "Failed to get slave name for domain-%d "
 		      "(errno = %i, %s)",
@@ -454,18 +463,18 @@ static int domain_create_tty(struct domain *dom)
 		goto out;
 	}
 
-	success = asprintf(&path, "%s/limit", dom->conspath) !=
+	success = asprintf(&path, "%s/limit", con->conspath) !=
 		-1;
 	if (!success)
 		goto out;
 	data = xs_read(xs, XBT_NULL, path, &len);
 	if (data) {
-		dom->buffer.max_capacity = strtoul(data, 0, 0);
+		con->buffer.max_capacity = strtoul(data, 0, 0);
 		free(data);
 	}
 	free(path);
 
-	success = (asprintf(&path, "%s/tty", dom->conspath) != -1);
+	success = (asprintf(&path, "%s/tty", con->conspath) != -1);
 	if (!success)
 		goto out;
 	success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
@@ -473,7 +482,7 @@ static int domain_create_tty(struct domain *dom)
 	if (!success)
 		goto out;
 
-	if (fcntl(dom->master_fd, F_SETFL, O_NONBLOCK) == -1)
+	if (fcntl(con->master_fd, F_SETFL, O_NONBLOCK) == -1)
 		goto out;
 
 	return 1;
@@ -519,29 +528,32 @@ static int xs_gather(struct xs_handle *xs, const char *dir, ...)
 
 static void domain_unmap_interface(struct domain *dom)
 {
-	if (dom->interface == NULL)
+	struct console *con = &dom->console;
+
+	if (con->interface == NULL)
 		return;
-	if (xgt_handle && dom->ring_ref == -1)
-		xengnttab_unmap(xgt_handle, dom->interface, 1);
+	if (xgt_handle && con->ring_ref == -1)
+		xengnttab_unmap(xgt_handle, con->interface, 1);
 	else
-		munmap(dom->interface, XC_PAGE_SIZE);
-	dom->interface = NULL;
-	dom->ring_ref = -1;
+		munmap(con->interface, XC_PAGE_SIZE);
+	con->interface = NULL;
+	con->ring_ref = -1;
 }
  
 static int domain_create_ring(struct domain *dom)
 {
 	int err, remote_port, ring_ref, rc;
 	char *type, path[PATH_MAX];
+	struct console *con = &dom->console;
 
-	err = xs_gather(xs, dom->conspath,
+	err = xs_gather(xs, con->conspath,
 			"ring-ref", "%u", &ring_ref,
 			"port", "%i", &remote_port,
 			NULL);
 	if (err)
 		goto out;
 
-	snprintf(path, sizeof(path), "%s/type", dom->conspath);
+	snprintf(path, sizeof(path), "%s/type", con->conspath);
 	type = xs_read(xs, XBT_NULL, path, NULL);
 	if (type && strcmp(type, "xenconsoled") != 0) {
 		free(type);
@@ -550,41 +562,41 @@ static int domain_create_ring(struct domain *dom)
 	free(type);
 
 	/* If using ring_ref and it has changed, remap */
-	if (ring_ref != dom->ring_ref && dom->ring_ref != -1)
+	if (ring_ref != con->ring_ref && con->ring_ref != -1)
 		domain_unmap_interface(dom);
 
-	if (!dom->interface && xgt_handle) {
+	if (!con->interface && xgt_handle) {
 		/* Prefer using grant table */
-		dom->interface = xengnttab_map_grant_ref(xgt_handle,
+		con->interface = xengnttab_map_grant_ref(xgt_handle,
 			dom->domid, GNTTAB_RESERVED_CONSOLE,
 			PROT_READ|PROT_WRITE);
-		dom->ring_ref = -1;
+		con->ring_ref = -1;
 	}
-	if (!dom->interface) {
+	if (!con->interface) {
 		/* Fall back to xc_map_foreign_range */
-		dom->interface = xc_map_foreign_range(
+		con->interface = xc_map_foreign_range(
 			xc, dom->domid, XC_PAGE_SIZE,
 			PROT_READ|PROT_WRITE,
 			(unsigned long)ring_ref);
-		if (dom->interface == NULL) {
+		if (con->interface == NULL) {
 			err = EINVAL;
 			goto out;
 		}
-		dom->ring_ref = ring_ref;
+		con->ring_ref = ring_ref;
 	}
 
 	/* Go no further if port has not changed and we are still bound. */
-	if (remote_port == dom->remote_port) {
+	if (remote_port == con->remote_port) {
 		xc_evtchn_status_t status = {
 			.dom = DOMID_SELF,
-			.port = dom->local_port };
+			.port = con->local_port };
 		if ((xc_evtchn_status(xc, &status) == 0) &&
 		    (status.status == EVTCHNSTAT_interdomain))
 			goto out;
 	}
 
-	dom->local_port = -1;
-	dom->remote_port = -1;
+	con->local_port = -1;
+	con->remote_port = -1;
 	if (dom->xce_handle != NULL)
 		xenevtchn_close(dom->xce_handle);
 
@@ -605,22 +617,22 @@ static int domain_create_ring(struct domain *dom)
 		dom->xce_handle = NULL;
 		goto out;
 	}
-	dom->local_port = rc;
-	dom->remote_port = remote_port;
+	con->local_port = rc;
+	con->remote_port = remote_port;
 
-	if (dom->master_fd == -1) {
+	if (con->master_fd == -1) {
 		if (!domain_create_tty(dom)) {
 			err = errno;
 			xenevtchn_close(dom->xce_handle);
 			dom->xce_handle = NULL;
-			dom->local_port = -1;
-			dom->remote_port = -1;
+			con->local_port = -1;
+			con->remote_port = -1;
 			goto out;
 		}
 	}
 
-	if (log_guest && (dom->log_fd == -1))
-		dom->log_fd = create_domain_log(dom);
+	if (log_guest && (con->log_fd == -1))
+		con->log_fd = create_domain_log(dom);
 
  out:
 	return err;
@@ -630,16 +642,17 @@ static bool watch_domain(struct domain *dom, bool watch)
 {
 	char domid_str[3 + MAX_STRLEN(dom->domid)];
 	bool success;
+	struct console *con = &dom->console;
 
 	snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid);
 	if (watch) {
-		success = xs_watch(xs, dom->conspath, domid_str);
+		success = xs_watch(xs, con->conspath, domid_str);
 		if (success)
 			domain_create_ring(dom);
 		else
-			xs_unwatch(xs, dom->conspath, domid_str);
+			xs_unwatch(xs, con->conspath, domid_str);
 	} else {
-		success = xs_unwatch(xs, dom->conspath, domid_str);
+		success = xs_unwatch(xs, con->conspath, domid_str);
 	}
 
 	return success;
@@ -651,6 +664,7 @@ static struct domain *create_domain(int domid)
 	struct domain *dom;
 	char *s;
 	struct timespec ts;
+	struct console *con;
 
 	if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
 		dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d",
@@ -667,25 +681,26 @@ static struct domain *create_domain(int domid)
 
 	dom->domid = domid;
 
-	dom->conspath = xs_get_domain_path(xs, dom->domid);
-	s = realloc(dom->conspath, strlen(dom->conspath) +
+	con = &dom->console;
+	con->conspath = xs_get_domain_path(xs, dom->domid);
+	s = realloc(con->conspath, strlen(con->conspath) +
 		    strlen("/console") + 1);
 	if (s == NULL)
 		goto out;
-	dom->conspath = s;
-	strcat(dom->conspath, "/console");
+	con->conspath = s;
+	strcat(con->conspath, "/console");
 
-	dom->master_fd = -1;
-	dom->master_pollfd_idx = -1;
-	dom->slave_fd = -1;
-	dom->log_fd = -1;
+	con->master_fd = -1;
+	con->master_pollfd_idx = -1;
+	con->slave_fd = -1;
+	con->log_fd = -1;
 	dom->xce_pollfd_idx = -1;
 
 	dom->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD;
 
-	dom->ring_ref = -1;
-	dom->local_port = -1;
-	dom->remote_port = -1;
+	con->ring_ref = -1;
+	con->local_port = -1;
+	con->remote_port = -1;
 
 	if (!watch_domain(dom, true))
 		goto out;
@@ -697,7 +712,7 @@ static struct domain *create_domain(int domid)
 
 	return dom;
  out:
-	free(dom->conspath);
+	free(con->conspath);
 	free(dom);
 	return NULL;
 }
@@ -729,18 +744,20 @@ static void remove_domain(struct domain *dom)
 
 static void cleanup_domain(struct domain *d)
 {
+	struct console *con = &d->console;
+
 	domain_close_tty(d);
 
-	if (d->log_fd != -1) {
-		close(d->log_fd);
-		d->log_fd = -1;
+	if (con->log_fd != -1) {
+		close(con->log_fd);
+		con->log_fd = -1;
 	}
 
-	free(d->buffer.data);
-	d->buffer.data = NULL;
+	free(con->buffer.data);
+	con->buffer.data = NULL;
 
-	free(d->conspath);
-	d->conspath = NULL;
+	free(con->conspath);
+	con->conspath = NULL;
 
 	remove_domain(d);
 }
@@ -782,7 +799,8 @@ static void enum_domains(void)
 
 static int ring_free_bytes(struct domain *dom)
 {
-	struct xencons_interface *intf = dom->interface;
+	struct console *con = &dom->console;
+	struct xencons_interface *intf = con->interface;
 	XENCONS_RING_IDX cons, prod, space;
 
 	cons = intf->in_cons;
@@ -812,7 +830,8 @@ static void handle_tty_read(struct domain *dom)
 	ssize_t len = 0;
 	char msg[80];
 	int i;
-	struct xencons_interface *intf = dom->interface;
+	struct console *con = &dom->console;
+	struct xencons_interface *intf = con->interface;
 	XENCONS_RING_IDX prod;
 
 	if (dom->is_dead)
@@ -825,7 +844,7 @@ static void handle_tty_read(struct domain *dom)
 	if (len > sizeof(msg))
 		len = sizeof(msg);
 
-	len = read(dom->master_fd, msg, len);
+	len = read(con->master_fd, msg, len);
 	/*
 	 * Note: on Solaris, len == 0 means the slave closed, and this
 	 * is no problem, but Linux can't handle this usefully, so we
@@ -841,7 +860,7 @@ static void handle_tty_read(struct domain *dom)
 		}
 		xen_wmb();
 		intf->in_prod = prod;
-		xenevtchn_notify(dom->xce_handle, dom->local_port);
+		xenevtchn_notify(dom->xce_handle, con->local_port);
 	} else {
 		domain_close_tty(dom);
 		shutdown_domain(dom);
@@ -851,18 +870,19 @@ static void handle_tty_read(struct domain *dom)
 static void handle_tty_write(struct domain *dom)
 {
 	ssize_t len;
+	struct console *con = &dom->console;
 
 	if (dom->is_dead)
 		return;
 
-	len = write(dom->master_fd, dom->buffer.data + dom->buffer.consumed,
-		    dom->buffer.size - dom->buffer.consumed);
+	len = write(con->master_fd, con->buffer.data + con->buffer.consumed,
+		    con->buffer.size - con->buffer.consumed);
  	if (len < 1) {
 		dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
 		      dom->domid, len, errno);
 		domain_handle_broken_tty(dom, domain_is_valid(dom->domid));
 	} else {
-		buffer_advance(&dom->buffer, len);
+		buffer_advance(&con->buffer, len);
 	}
 }
 
@@ -948,9 +968,11 @@ static void handle_log_reload(void)
 	if (log_guest) {
 		struct domain *d;
 		for (d = dom_head; d; d = d->next) {
-			if (d->log_fd != -1)
-				close(d->log_fd);
-			d->log_fd = create_domain_log(d);
+			struct console *con = &d->console;
+
+			if (con->log_fd != -1)
+				close(con->log_fd);
+			con->log_fd = create_domain_log(d);
 		}
 	}
 
@@ -1059,6 +1081,8 @@ void handle_io(void)
 		/* Re-calculate any event counter allowances & unblock
 		   domains with new allowance */
 		for (d = dom_head; d; d = d->next) {
+			struct console *con = &d->console;
+
 			/* CS 16257:955ee4fa1345 introduces a 5ms fuzz
 			 * for select(), it is not clear poll() has
 			 * similar behavior (returning a couple of ms
@@ -1068,13 +1092,15 @@ void handle_io(void)
 			if ((now+5) > d->next_period) {
 				d->next_period = now + RATE_LIMIT_PERIOD;
 				if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
-					(void)xenevtchn_unmask(d->xce_handle, d->local_port);
+					(void)xenevtchn_unmask(d->xce_handle, con->local_port);
 				}
 				d->event_count = 0;
 			}
 		}
 
 		for (d = dom_head; d; d = d->next) {
+			struct console *con = &d->console;
+
 			if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
 				/* Determine if we're going to be the next time slice to expire */
 				if (!next_timeout ||
@@ -1082,25 +1108,25 @@ void handle_io(void)
 					next_timeout = d->next_period;
 			} else if (d->xce_handle != NULL) {
 				if (discard_overflowed_data ||
-				    !d->buffer.max_capacity ||
-				    d->buffer.size < d->buffer.max_capacity) {
+				    !con->buffer.max_capacity ||
+				    con->buffer.size < con->buffer.max_capacity) {
 					int evtchn_fd = xenevtchn_fd(d->xce_handle);
 					d->xce_pollfd_idx = set_fds(evtchn_fd,
 								    POLLIN|POLLPRI);
 				}
 			}
 
-			if (d->master_fd != -1) {
+			if (con->master_fd != -1) {
 				short events = 0;
 				if (!d->is_dead && ring_free_bytes(d))
 					events |= POLLIN;
 
-				if (!buffer_empty(&d->buffer))
+				if (!buffer_empty(&con->buffer))
 					events |= POLLOUT;
 
 				if (events)
-					d->master_pollfd_idx =
-						set_fds(d->master_fd,
+					con->master_pollfd_idx =
+						set_fds(con->master_fd,
 							events|POLLPRI);
 			}
 		}
@@ -1159,6 +1185,8 @@ void handle_io(void)
 		}
 
 		for (d = dom_head; d; d = n) {
+			struct console *con = &d->console;
+
 			n = d->next;
 			if (d->event_count < RATE_LIMIT_ALLOWANCE) {
 				if (d->xce_handle != NULL &&
@@ -1170,22 +1198,22 @@ void handle_io(void)
 				    handle_ring_read(d);
 			}
 
-			if (d->master_fd != -1 && d->master_pollfd_idx != -1) {
-				if (fds[d->master_pollfd_idx].revents &
+			if (con->master_fd != -1 && con->master_pollfd_idx != -1) {
+				if (fds[con->master_pollfd_idx].revents &
 				    ~(POLLIN|POLLOUT|POLLPRI))
 					domain_handle_broken_tty(d,
 						   domain_is_valid(d->domid));
 				else {
-					if (fds[d->master_pollfd_idx].revents &
+					if (fds[con->master_pollfd_idx].revents &
 					    POLLIN)
 						handle_tty_read(d);
-					if (fds[d->master_pollfd_idx].revents &
+					if (fds[con->master_pollfd_idx].revents &
 					    POLLOUT)
 						handle_tty_write(d);
 				}
 			}
 
-			d->xce_pollfd_idx = d->master_pollfd_idx = -1;
+			d->xce_pollfd_idx = con->master_pollfd_idx = -1;
 
 			if (d->last_seen != enum_pass)
 				shutdown_domain(d);
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 09/14 v4] xen/arm: vpl011: Modify xenconsole functions to take console structure as input
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (7 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 08/14 v4] xen/arm: vpl011: Modify xenconsole to define and use a new console structure Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-07  0:43   ` Stefano Stabellini
  2017-06-06 17:25 ` [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles Bhupinder Thakur
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

Xenconsole functions take domain structure as input. These functions shall be
modified to take console structure as input since these functions typically perform
console specific operations.

Also the console specific functions starting with prefix "domain_" shall be modified
to "console_" to indicate that these are console specific functions.

This patch is in preparation to support multiple consoles to support vuart console.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- The changes in xenconsole have been split into four patches. This is the second patch.

 tools/console/daemon/io.c | 82 +++++++++++++++++++++++------------------------
 1 file changed, 41 insertions(+), 41 deletions(-)

diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index 0402ddf..c5dd08d 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -163,10 +163,10 @@ static int write_with_timestamp(int fd, const char *data, size_t sz,
 	return 0;
 }
 
-static void buffer_append(struct domain *dom)
+static void buffer_append(struct console *con)
 {
-	struct console *con = &dom->console;
 	struct buffer *buffer = &con->buffer;
+	struct domain *dom = con->d;
 	XENCONS_RING_IDX cons, prod, size;
 	struct xencons_interface *intf = con->interface;
 
@@ -296,12 +296,13 @@ static int create_hv_log(void)
 	return fd;
 }
 
-static int create_domain_log(struct domain *dom)
+static int create_console_log(struct console *con)
 {
 	char logfile[PATH_MAX];
 	char *namepath, *data, *s;
 	int fd;
 	unsigned int len;
+	struct domain *dom = con->d;
 
 	namepath = xs_get_domain_path(xs, dom->domid);
 	s = realloc(namepath, strlen(namepath) + 6);
@@ -342,10 +343,8 @@ static int create_domain_log(struct domain *dom)
 	return fd;
 }
 
-static void domain_close_tty(struct domain *dom)
+static void console_close_tty(struct console *con)
 {
-	struct console *con = &dom->console;
-
 	if (con->master_fd != -1) {
 		close(con->master_fd);
 		con->master_fd = -1;
@@ -417,7 +416,7 @@ void cfmakeraw(struct termios *termios_p)
 }
 #endif /* __sun__ */
 
-static int domain_create_tty(struct domain *dom)
+static int console_create_tty(struct console *con)
 {
 	const char *slave;
 	char *path;
@@ -426,7 +425,7 @@ static int domain_create_tty(struct domain *dom)
 	char *data;
 	unsigned int len;
 	struct termios term;
-	struct console *con = &dom->console;
+	struct domain *dom = con->d;
 
 	assert(con->slave_fd == -1);
 	assert(con->master_fd == -1);
@@ -487,7 +486,7 @@ static int domain_create_tty(struct domain *dom)
 
 	return 1;
 out:
-	domain_close_tty(dom);
+	console_close_tty(con);
 	return 0;
 }
  
@@ -526,10 +525,8 @@ static int xs_gather(struct xs_handle *xs, const char *dir, ...)
 	return ret;
 }
 
-static void domain_unmap_interface(struct domain *dom)
+static void console_unmap_interface(struct console *con)
 {
-	struct console *con = &dom->console;
-
 	if (con->interface == NULL)
 		return;
 	if (xgt_handle && con->ring_ref == -1)
@@ -540,11 +537,11 @@ static void domain_unmap_interface(struct domain *dom)
 	con->ring_ref = -1;
 }
  
-static int domain_create_ring(struct domain *dom)
+static int console_create_ring(struct console *con)
 {
 	int err, remote_port, ring_ref, rc;
 	char *type, path[PATH_MAX];
-	struct console *con = &dom->console;
+	struct domain *dom = con->d;
 
 	err = xs_gather(xs, con->conspath,
 			"ring-ref", "%u", &ring_ref,
@@ -563,7 +560,7 @@ static int domain_create_ring(struct domain *dom)
 
 	/* If using ring_ref and it has changed, remap */
 	if (ring_ref != con->ring_ref && con->ring_ref != -1)
-		domain_unmap_interface(dom);
+		console_unmap_interface(con);
 
 	if (!con->interface && xgt_handle) {
 		/* Prefer using grant table */
@@ -621,7 +618,7 @@ static int domain_create_ring(struct domain *dom)
 	con->remote_port = remote_port;
 
 	if (con->master_fd == -1) {
-		if (!domain_create_tty(dom)) {
+		if (!console_create_tty(con)) {
 			err = errno;
 			xenevtchn_close(dom->xce_handle);
 			dom->xce_handle = NULL;
@@ -632,7 +629,7 @@ static int domain_create_ring(struct domain *dom)
 	}
 
 	if (log_guest && (con->log_fd == -1))
-		con->log_fd = create_domain_log(dom);
+		con->log_fd = create_console_log(con);
 
  out:
 	return err;
@@ -648,7 +645,7 @@ static bool watch_domain(struct domain *dom, bool watch)
 	if (watch) {
 		success = xs_watch(xs, con->conspath, domid_str);
 		if (success)
-			domain_create_ring(dom);
+			console_create_ring(con);
 		else
 			xs_unwatch(xs, con->conspath, domid_str);
 	} else {
@@ -694,6 +691,7 @@ static struct domain *create_domain(int domid)
 	con->master_pollfd_idx = -1;
 	con->slave_fd = -1;
 	con->log_fd = -1;
+	con->d = dom;
 	dom->xce_pollfd_idx = -1;
 
 	dom->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD;
@@ -746,7 +744,7 @@ static void cleanup_domain(struct domain *d)
 {
 	struct console *con = &d->console;
 
-	domain_close_tty(d);
+	console_close_tty(con);
 
 	if (con->log_fd != -1) {
 		close(con->log_fd);
@@ -764,9 +762,11 @@ static void cleanup_domain(struct domain *d)
 
 static void shutdown_domain(struct domain *d)
 {
+	struct console *con = &d->console;
+
 	d->is_dead = true;
 	watch_domain(d, false);
-	domain_unmap_interface(d);
+	console_unmap_interface(con);
 	if (d->xce_handle != NULL)
 		xenevtchn_close(d->xce_handle);
 	d->xce_handle = NULL;
@@ -797,9 +797,8 @@ static void enum_domains(void)
 	}
 }
 
-static int ring_free_bytes(struct domain *dom)
+static int ring_free_bytes(struct console *con)
 {
-	struct console *con = &dom->console;
 	struct xencons_interface *intf = con->interface;
 	XENCONS_RING_IDX cons, prod, space;
 
@@ -814,30 +813,30 @@ static int ring_free_bytes(struct domain *dom)
 	return (sizeof(intf->in) - space);
 }
 
-static void domain_handle_broken_tty(struct domain *dom, int recreate)
+static void console_handle_broken_tty(struct console *con, int recreate)
 {
-	domain_close_tty(dom);
+	console_close_tty(con);
 
 	if (recreate) {
-		domain_create_tty(dom);
+		console_create_tty(con);
 	} else {
-		shutdown_domain(dom);
+		shutdown_domain(con->d);
 	}
 }
 
-static void handle_tty_read(struct domain *dom)
+static void handle_tty_read(struct console *con)
 {
 	ssize_t len = 0;
 	char msg[80];
 	int i;
-	struct console *con = &dom->console;
 	struct xencons_interface *intf = con->interface;
+	struct domain *dom = con->d;
 	XENCONS_RING_IDX prod;
 
 	if (dom->is_dead)
 		return;
 
-	len = ring_free_bytes(dom);
+	len = ring_free_bytes(con);
 	if (len == 0)
 		return;
 
@@ -851,7 +850,7 @@ static void handle_tty_read(struct domain *dom)
 	 * keep the slave open for the duration.
 	 */
 	if (len < 0) {
-		domain_handle_broken_tty(dom, domain_is_valid(dom->domid));
+		console_handle_broken_tty(con, domain_is_valid(dom->domid));
 	} else if (domain_is_valid(dom->domid)) {
 		prod = intf->in_prod;
 		for (i = 0; i < len; i++) {
@@ -862,15 +861,15 @@ static void handle_tty_read(struct domain *dom)
 		intf->in_prod = prod;
 		xenevtchn_notify(dom->xce_handle, con->local_port);
 	} else {
-		domain_close_tty(dom);
+		console_close_tty(con);
 		shutdown_domain(dom);
 	}
 }
 
-static void handle_tty_write(struct domain *dom)
+static void handle_tty_write(struct console *con)
 {
 	ssize_t len;
-	struct console *con = &dom->console;
+	struct domain *dom = con->d;
 
 	if (dom->is_dead)
 		return;
@@ -880,7 +879,7 @@ static void handle_tty_write(struct domain *dom)
  	if (len < 1) {
 		dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
 		      dom->domid, len, errno);
-		domain_handle_broken_tty(dom, domain_is_valid(dom->domid));
+		console_handle_broken_tty(con, domain_is_valid(dom->domid));
 	} else {
 		buffer_advance(&con->buffer, len);
 	}
@@ -889,6 +888,7 @@ static void handle_tty_write(struct domain *dom)
 static void handle_ring_read(struct domain *dom)
 {
 	xenevtchn_port_or_error_t port;
+	struct console *con = &dom->console;
 
 	if (dom->is_dead)
 		return;
@@ -898,7 +898,7 @@ static void handle_ring_read(struct domain *dom)
 
 	dom->event_count++;
 
-	buffer_append(dom);
+	buffer_append(con);
 
 	if (dom->event_count < RATE_LIMIT_ALLOWANCE)
 		(void)xenevtchn_unmask(dom->xce_handle, port);
@@ -922,7 +922,7 @@ static void handle_xs(void)
 		/* We may get watches firing for domains that have recently
 		   been removed, so dom may be NULL here. */
 		if (dom && dom->is_dead == false)
-			domain_create_ring(dom);
+			console_create_ring(&dom->console);
 	}
 
 	free(vec);
@@ -972,7 +972,7 @@ static void handle_log_reload(void)
 
 			if (con->log_fd != -1)
 				close(con->log_fd);
-			con->log_fd = create_domain_log(d);
+			con->log_fd = create_console_log(con);
 		}
 	}
 
@@ -1118,7 +1118,7 @@ void handle_io(void)
 
 			if (con->master_fd != -1) {
 				short events = 0;
-				if (!d->is_dead && ring_free_bytes(d))
+				if (!d->is_dead && ring_free_bytes(con))
 					events |= POLLIN;
 
 				if (!buffer_empty(&con->buffer))
@@ -1201,15 +1201,15 @@ void handle_io(void)
 			if (con->master_fd != -1 && con->master_pollfd_idx != -1) {
 				if (fds[con->master_pollfd_idx].revents &
 				    ~(POLLIN|POLLOUT|POLLPRI))
-					domain_handle_broken_tty(d,
+					console_handle_broken_tty(con,
 						   domain_is_valid(d->domid));
 				else {
 					if (fds[con->master_pollfd_idx].revents &
 					    POLLIN)
-						handle_tty_read(d);
+						handle_tty_read(con);
 					if (fds[con->master_pollfd_idx].revents &
 					    POLLOUT)
-						handle_tty_write(d);
+						handle_tty_write(con);
 				}
 			}
 
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (8 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 09/14 v4] xen/arm: vpl011: Modify xenconsole functions to take console structure as input Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-07  1:03   ` Stefano Stabellini
  2017-06-06 17:25 ` [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole Bhupinder Thakur
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

This patch adds the support for multiple consoles and introduces the iterator
functions to operate on multiple consoles.

This patch is in preparation to support a new vuart console.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- The changes in xenconsole have been split into four patches. This is the third patch.

 tools/console/daemon/io.c | 364 +++++++++++++++++++++++++++++++++-------------
 1 file changed, 263 insertions(+), 101 deletions(-)

diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index c5dd08d..db73e10 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -90,12 +90,15 @@ struct buffer {
 };
 
 struct console {
+	char *xsname;
+	char *ttyname;
 	int master_fd;
 	int master_pollfd_idx;
 	int slave_fd;
 	int log_fd;
 	struct buffer buffer;
-	char *conspath;
+	char *xspath;
+	char *log_suffix;
 	int ring_ref;
 	xenevtchn_port_or_error_t local_port;
 	xenevtchn_port_or_error_t remote_port;
@@ -103,6 +106,23 @@ struct console {
 	struct domain *d;
 };
 
+struct console_data {
+	char *xsname;
+	char *ttyname;
+	char *log_suffix;
+};
+
+static struct console_data console_data[] = {
+
+	{
+		.xsname = "/console",
+		.ttyname = "tty",
+		.log_suffix = "",
+	},
+};
+
+#define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data))
+
 struct domain {
 	int domid;
 	bool is_dead;
@@ -112,11 +132,90 @@ struct domain {
 	int xce_pollfd_idx;
 	int event_count;
 	long long next_period;
-	struct console console;
+	struct console console[MAX_CONSOLE];
 };
 
 static struct domain *dom_head;
 
+typedef void (*VOID_ITER_FUNC_ARG1)(struct console *);
+typedef bool (*BOOL_ITER_FUNC_ARG1)(struct console *);
+typedef int (*INT_ITER_FUNC_ARG1)(struct console *);
+typedef void (*VOID_ITER_FUNC_ARG2)(struct console *,  unsigned int);
+typedef int (*INT_ITER_FUNC_ARG3)(struct console *,
+			 struct domain *dom, void **);
+
+static inline bool console_enabled(struct console *con)
+{
+	return con->local_port != -1;
+}
+
+static inline void console_iter_void_arg1(struct domain *d,
+										  VOID_ITER_FUNC_ARG1 iter_func)
+{
+	int i = 0;
+	struct console *con = &(d->console[0]);
+
+	for (i = 0; i < MAX_CONSOLE; i++, con++)
+	{
+		iter_func(con);
+	}
+}
+
+static inline void console_iter_void_arg2(struct domain *d,
+										  VOID_ITER_FUNC_ARG2 iter_func,
+										  unsigned int iter_data)
+{
+	int i = 0;
+	struct console *con = &(d->console[0]);
+
+	for (i = 0; i < MAX_CONSOLE; i++, con++)
+	{
+		iter_func(con, iter_data);
+	}
+}
+
+static inline bool console_iter_bool_arg1(struct domain *d,
+										  BOOL_ITER_FUNC_ARG1 iter_func)
+{
+	int i = 0;
+	struct console *con = &(d->console[0]);
+
+	for (i = 0; i < MAX_CONSOLE; i++, con++)
+	{
+		if (iter_func(con))
+			return true;
+	}
+	return false;
+}
+
+static inline int console_iter_int_arg1(struct domain *d,
+										INT_ITER_FUNC_ARG1 iter_func)
+{
+	int i = 0;
+	struct console *con = &(d->console[0]);
+
+	for (i = 0; i < MAX_CONSOLE; i++, con++)
+	{
+		if (iter_func(con))
+			return 1;
+	}
+	return 0;
+}
+
+static inline int console_iter_int_arg3(struct domain *d,
+										INT_ITER_FUNC_ARG3 iter_func,
+										void *iter_data)
+{
+	int i = 0;
+	struct console *con = &(d->console[0]);
+
+	for (i = 0; i < MAX_CONSOLE; i++, con++)
+	{
+		if (iter_func(con, d, iter_data))
+			return 1;
+	}
+	return 0;
+}
 static int write_all(int fd, const char* buf, size_t len)
 {
 	while (len) {
@@ -163,12 +262,27 @@ static int write_with_timestamp(int fd, const char *data, size_t sz,
 	return 0;
 }
 
-static void buffer_append(struct console *con)
+static inline bool buffer_available(struct console *con)
+{
+	if (discard_overflowed_data ||
+		!con->buffer.max_capacity ||
+		con->buffer.size < con->buffer.max_capacity)
+		return true;
+	else
+		return false;
+}
+
+static void buffer_append(struct console *con, unsigned int data)
 {
 	struct buffer *buffer = &con->buffer;
+	struct xencons_interface *intf = con->interface;
+	xenevtchn_port_or_error_t rxport = (xenevtchn_port_or_error_t)data;
 	struct domain *dom = con->d;
 	XENCONS_RING_IDX cons, prod, size;
-	struct xencons_interface *intf = con->interface;
+
+	/* If incoming data is not for the current console then ignore. */
+	if (con->local_port != rxport)
+		return;
 
 	cons = intf->out_cons;
 	prod = intf->out_prod;
@@ -321,7 +435,7 @@ static int create_console_log(struct console *con)
 		return -1;
 	}
 
-	snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data);
+	snprintf(logfile, PATH_MAX-1, "%s/guest-%s%s.log", log_dir, data, con->log_suffix);
 	free(data);
 	logfile[PATH_MAX-1] = '\0';
 
@@ -427,6 +541,9 @@ static int console_create_tty(struct console *con)
 	struct termios term;
 	struct domain *dom = con->d;
 
+	if (!console_enabled(con))
+		return 1;
+
 	assert(con->slave_fd == -1);
 	assert(con->master_fd == -1);
 
@@ -462,7 +579,7 @@ static int console_create_tty(struct console *con)
 		goto out;
 	}
 
-	success = asprintf(&path, "%s/limit", con->conspath) !=
+	success = asprintf(&path, "%s/limit", con->xspath) !=
 		-1;
 	if (!success)
 		goto out;
@@ -473,7 +590,7 @@ static int console_create_tty(struct console *con)
 	}
 	free(path);
 
-	success = (asprintf(&path, "%s/tty", con->conspath) != -1);
+	success = (asprintf(&path, "%s/%s", con->xspath, con->ttyname) != -1);
 	if (!success)
 		goto out;
 	success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
@@ -543,14 +660,14 @@ static int console_create_ring(struct console *con)
 	char *type, path[PATH_MAX];
 	struct domain *dom = con->d;
 
-	err = xs_gather(xs, con->conspath,
+	err = xs_gather(xs, con->xspath,
 			"ring-ref", "%u", &ring_ref,
 			"port", "%i", &remote_port,
 			NULL);
 	if (err)
 		goto out;
 
-	snprintf(path, sizeof(path), "%s/type", con->conspath);
+	snprintf(path, sizeof(path), "%s/type", con->xspath);
 	type = xs_read(xs, XBT_NULL, path, NULL);
 	if (type && strcmp(type, "xenconsoled") != 0) {
 		free(type);
@@ -594,15 +711,16 @@ static int console_create_ring(struct console *con)
 
 	con->local_port = -1;
 	con->remote_port = -1;
-	if (dom->xce_handle != NULL)
-		xenevtchn_close(dom->xce_handle);
 
-	/* Opening evtchn independently for each console is a bit
-	 * wasteful, but that's how the code is structured... */
-	dom->xce_handle = xenevtchn_open(NULL, 0);
-	if (dom->xce_handle == NULL) {
-		err = errno;
-		goto out;
+	if (dom->xce_handle == NULL)
+	{
+		/* Opening evtchn independently for each console is a bit
+		 * wasteful, but that's how the code is structured... */
+		dom->xce_handle = xenevtchn_open(NULL, 0);
+		if (dom->xce_handle == NULL) {
+			err = errno;
+			goto out;
+		}
 	}
  
 	rc = xenevtchn_bind_interdomain(dom->xce_handle,
@@ -639,29 +757,65 @@ static bool watch_domain(struct domain *dom, bool watch)
 {
 	char domid_str[3 + MAX_STRLEN(dom->domid)];
 	bool success;
-	struct console *con = &dom->console;
+	struct console *con = &dom->console[0];
 
 	snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid);
 	if (watch) {
-		success = xs_watch(xs, con->conspath, domid_str);
+		success = xs_watch(xs, con->xspath, domid_str);
 		if (success)
-			console_create_ring(con);
+			console_iter_int_arg1(dom, console_create_ring);
 		else
-			xs_unwatch(xs, con->conspath, domid_str);
+			xs_unwatch(xs, con->xspath, domid_str);
 	} else {
-		success = xs_unwatch(xs, con->conspath, domid_str);
+		success = xs_unwatch(xs, con->xspath, domid_str);
 	}
 
 	return success;
 }
 
+static int console_init(struct console *con, struct domain *dom, void **data)
+{
+	char *s;
+	int err = -1;
+	struct console_data **con_data = (struct console_data **)data;
+
+	con->master_fd = -1;
+	con->master_pollfd_idx = -1;
+	con->slave_fd = -1;
+	con->log_fd = -1;
+	con->ring_ref = -1;
+	con->local_port = -1;
+	con->remote_port = -1;
+	con->d = dom;
+	con->ttyname = (*con_data)->ttyname;
+	con->log_suffix = (*con_data)->log_suffix;
+	con->xsname = (*con_data)->xsname;
+	con->xspath = xs_get_domain_path(xs, dom->domid);
+	s = realloc(con->xspath, strlen(con->xspath) +
+				strlen(con->xsname) + 1);
+	if (s)
+	{
+		con->xspath = s;
+		strcat(con->xspath, con->xsname);
+		err = 0;
+	}
+
+	(*con_data)++;
+
+	return err;
+}
+
+static void console_free(struct console *con)
+{
+	if (con->xspath)
+		free(con->xspath);
+}
 
 static struct domain *create_domain(int domid)
 {
 	struct domain *dom;
-	char *s;
 	struct timespec ts;
-	struct console *con;
+	struct console_data *con_data = &console_data[0];
 
 	if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
 		dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d",
@@ -678,28 +832,13 @@ static struct domain *create_domain(int domid)
 
 	dom->domid = domid;
 
-	con = &dom->console;
-	con->conspath = xs_get_domain_path(xs, dom->domid);
-	s = realloc(con->conspath, strlen(con->conspath) +
-		    strlen("/console") + 1);
-	if (s == NULL)
+	if (console_iter_int_arg3(dom, console_init, (void **)&con_data))
 		goto out;
-	con->conspath = s;
-	strcat(con->conspath, "/console");
 
-	con->master_fd = -1;
-	con->master_pollfd_idx = -1;
-	con->slave_fd = -1;
-	con->log_fd = -1;
-	con->d = dom;
 	dom->xce_pollfd_idx = -1;
 
 	dom->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD;
 
-	con->ring_ref = -1;
-	con->local_port = -1;
-	con->remote_port = -1;
-
 	if (!watch_domain(dom, true))
 		goto out;
 
@@ -710,7 +849,7 @@ static struct domain *create_domain(int domid)
 
 	return dom;
  out:
-	free(con->conspath);
+	console_iter_void_arg1(dom, console_free);
 	free(dom);
 	return NULL;
 }
@@ -740,33 +879,40 @@ static void remove_domain(struct domain *dom)
 	}
 }
 
-static void cleanup_domain(struct domain *d)
+static void console_cleanup(struct console *con)
 {
-	struct console *con = &d->console;
-
-	console_close_tty(con);
-
 	if (con->log_fd != -1) {
 		close(con->log_fd);
 		con->log_fd = -1;
 	}
 
-	free(con->buffer.data);
-	con->buffer.data = NULL;
+	if (con->buffer.data)
+	{
+		free(con->buffer.data);
+		con->buffer.data = NULL;
+	}
 
-	free(con->conspath);
-	con->conspath = NULL;
+	if (con->xspath)
+	{
+		free(con->xspath);
+		con->xspath = NULL;
+	}
+}
+
+static void cleanup_domain(struct domain *d)
+{
+	console_iter_void_arg1(d, console_close_tty);
+
+	console_iter_void_arg1(d, console_cleanup);
 
 	remove_domain(d);
 }
 
 static void shutdown_domain(struct domain *d)
 {
-	struct console *con = &d->console;
-
 	d->is_dead = true;
 	watch_domain(d, false);
-	console_unmap_interface(con);
+	console_iter_void_arg1(d, console_unmap_interface);
 	if (d->xce_handle != NULL)
 		xenevtchn_close(d->xce_handle);
 	d->xce_handle = NULL;
@@ -885,10 +1031,15 @@ static void handle_tty_write(struct console *con)
 	}
 }
 
+static void console_event_unmask(struct console *con)
+{
+	if (con->local_port != -1)
+		(void)xenevtchn_unmask(con->d->xce_handle, con->local_port);
+}
+
 static void handle_ring_read(struct domain *dom)
 {
 	xenevtchn_port_or_error_t port;
-	struct console *con = &dom->console;
 
 	if (dom->is_dead)
 		return;
@@ -898,10 +1049,10 @@ static void handle_ring_read(struct domain *dom)
 
 	dom->event_count++;
 
-	buffer_append(con);
+	console_iter_void_arg2(dom, buffer_append, port);
 
 	if (dom->event_count < RATE_LIMIT_ALLOWANCE)
-		(void)xenevtchn_unmask(dom->xce_handle, port);
+		console_iter_void_arg1(dom, console_event_unmask);
 }
 
 static void handle_xs(void)
@@ -922,7 +1073,7 @@ static void handle_xs(void)
 		/* We may get watches firing for domains that have recently
 		   been removed, so dom may be NULL here. */
 		if (dom && dom->is_dead == false)
-			console_create_ring(&dom->console);
+			console_iter_int_arg1(dom, console_create_ring);
 	}
 
 	free(vec);
@@ -963,16 +1114,22 @@ static void handle_hv_logs(xenevtchn_handle *xce_handle, bool force)
 		(void)xenevtchn_unmask(xce_handle, port);
 }
 
+static void console_open_log(struct console *con)
+{
+	if (console_enabled(con))
+	{
+		if (con->log_fd != -1)
+			close(con->log_fd);
+		con->log_fd = create_console_log(con);
+	}
+}
+
 static void handle_log_reload(void)
 {
 	if (log_guest) {
 		struct domain *d;
 		for (d = dom_head; d; d = d->next) {
-			struct console *con = &d->console;
-
-			if (con->log_fd != -1)
-				close(con->log_fd);
-			con->log_fd = create_console_log(con);
+			console_iter_void_arg1(d, console_open_log);
 		}
 	}
 
@@ -1024,6 +1181,40 @@ static void reset_fds(void)
 		memset(fds, 0, sizeof(struct pollfd) * current_array_size);
 }
 
+static void add_console_fd(struct console *con)
+{
+	if (con->master_fd != -1) {
+		short events = 0;
+		if (!con->d->is_dead && ring_free_bytes(con))
+			events |= POLLIN;
+
+		if (!buffer_empty(&con->buffer))
+			events |= POLLOUT;
+
+		if (events)
+			con->master_pollfd_idx =
+				set_fds(con->master_fd, events|POLLPRI);
+	}
+}
+
+static void process_console(struct console *con)
+{
+	if (con->master_fd != -1 && con->master_pollfd_idx != -1) {
+		if (fds[con->master_pollfd_idx].revents &
+			~(POLLIN|POLLOUT|POLLPRI))
+			console_handle_broken_tty(con, domain_is_valid(con->d->domid));
+		else {
+			if (fds[con->master_pollfd_idx].revents &
+				POLLIN)
+				handle_tty_read(con);
+			if (fds[con->master_pollfd_idx].revents &
+				POLLOUT)
+				handle_tty_write(con);
+		}
+	}
+	con->master_pollfd_idx = -1;
+}
+
 void handle_io(void)
 {
 	int ret;
@@ -1081,7 +1272,6 @@ void handle_io(void)
 		/* Re-calculate any event counter allowances & unblock
 		   domains with new allowance */
 		for (d = dom_head; d; d = d->next) {
-			struct console *con = &d->console;
 
 			/* CS 16257:955ee4fa1345 introduces a 5ms fuzz
 			 * for select(), it is not clear poll() has
@@ -1092,14 +1282,13 @@ void handle_io(void)
 			if ((now+5) > d->next_period) {
 				d->next_period = now + RATE_LIMIT_PERIOD;
 				if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
-					(void)xenevtchn_unmask(d->xce_handle, con->local_port);
+					console_iter_void_arg1(d, console_event_unmask);
 				}
 				d->event_count = 0;
 			}
 		}
 
 		for (d = dom_head; d; d = d->next) {
-			struct console *con = &d->console;
 
 			if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
 				/* Determine if we're going to be the next time slice to expire */
@@ -1107,28 +1296,15 @@ void handle_io(void)
 				    d->next_period < next_timeout)
 					next_timeout = d->next_period;
 			} else if (d->xce_handle != NULL) {
-				if (discard_overflowed_data ||
-				    !con->buffer.max_capacity ||
-				    con->buffer.size < con->buffer.max_capacity) {
-					int evtchn_fd = xenevtchn_fd(d->xce_handle);
-					d->xce_pollfd_idx = set_fds(evtchn_fd,
-								    POLLIN|POLLPRI);
+					if (console_iter_bool_arg1(d, buffer_available))
+					{
+						int evtchn_fd = xenevtchn_fd(d->xce_handle);
+						d->xce_pollfd_idx = set_fds(evtchn_fd,
+													POLLIN|POLLPRI);
+					}
 				}
-			}
-
-			if (con->master_fd != -1) {
-				short events = 0;
-				if (!d->is_dead && ring_free_bytes(con))
-					events |= POLLIN;
 
-				if (!buffer_empty(&con->buffer))
-					events |= POLLOUT;
-
-				if (events)
-					con->master_pollfd_idx =
-						set_fds(con->master_fd,
-							events|POLLPRI);
-			}
+			console_iter_void_arg1(d, add_console_fd);
 		}
 
 		/* If any domain has been rate limited, we need to work
@@ -1185,7 +1361,6 @@ void handle_io(void)
 		}
 
 		for (d = dom_head; d; d = n) {
-			struct console *con = &d->console;
 
 			n = d->next;
 			if (d->event_count < RATE_LIMIT_ALLOWANCE) {
@@ -1198,22 +1373,9 @@ void handle_io(void)
 				    handle_ring_read(d);
 			}
 
-			if (con->master_fd != -1 && con->master_pollfd_idx != -1) {
-				if (fds[con->master_pollfd_idx].revents &
-				    ~(POLLIN|POLLOUT|POLLPRI))
-					console_handle_broken_tty(con,
-						   domain_is_valid(d->domid));
-				else {
-					if (fds[con->master_pollfd_idx].revents &
-					    POLLIN)
-						handle_tty_read(con);
-					if (fds[con->master_pollfd_idx].revents &
-					    POLLOUT)
-						handle_tty_write(con);
-				}
-			}
+			console_iter_void_arg1(d, process_console);
 
-			d->xce_pollfd_idx = con->master_pollfd_idx = -1;
+			d->xce_pollfd_idx = -1;
 
 			if (d->last_seen != enum_pass)
 				shutdown_domain(d);
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (9 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-07  1:08   ` Stefano Stabellini
  2017-06-07 16:44   ` Wei Liu
  2017-06-06 17:25 ` [PATCH 12/14 v4] xen/arm: vpl011: Add a new vuart console type to xenconsole client Bhupinder Thakur
                   ` (3 subsequent siblings)
  14 siblings, 2 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

This patch finally adds the support for vuart console.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- The changes in xenconsole have been split into four patches. This is the fourth patch.
- The vuart console support is added under CONFIG_VUART_CONSOLE option.

 tools/console/Makefile    |  3 ++-
 tools/console/daemon/io.c | 26 +++++++++++++++++++++++++-
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/tools/console/Makefile b/tools/console/Makefile
index c8b0300..fcee313 100644
--- a/tools/console/Makefile
+++ b/tools/console/Makefile
@@ -11,6 +11,7 @@ LDLIBS += $(SOCKET_LIBS)
 
 LDLIBS_xenconsoled += $(UTIL_LIBS)
 LDLIBS_xenconsoled += -lrt
+VUART_CFLAGS-$(CONFIG_VUART_CONSOLE) = -DCONFIG_VUART_CONSOLE
 
 BIN      = xenconsoled xenconsole
 
@@ -28,7 +29,7 @@ clean:
 distclean: clean
 
 daemon/main.o: daemon/_paths.h
-daemon/io.o: CFLAGS += $(CFLAGS_libxenevtchn) $(CFLAGS_libxengnttab)
+daemon/io.o: CFLAGS += $(CFLAGS_libxenevtchn) $(CFLAGS_libxengnttab) $(VUART_CFLAGS-y)
 xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c))
 	$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_xenconsoled) $(APPEND_LDFLAGS)
 
diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index db73e10..cae2efe 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -104,12 +104,16 @@ struct console {
 	xenevtchn_port_or_error_t remote_port;
 	struct xencons_interface *interface;
 	struct domain *d;
+	bool optional;
+	bool prefer_gnttab;
 };
 
 struct console_data {
 	char *xsname;
 	char *ttyname;
 	char *log_suffix;
+	bool optional;
+	bool prefer_gnttab;
 };
 
 static struct console_data console_data[] = {
@@ -118,7 +122,18 @@ static struct console_data console_data[] = {
 		.xsname = "/console",
 		.ttyname = "tty",
 		.log_suffix = "",
+		.optional = false,
+		.prefer_gnttab = true,
 	},
+#if defined(CONFIG_VUART_CONSOLE)
+	{
+		.xsname = "/vuart/0",
+		.ttyname = "tty",
+		.log_suffix = "-vuart0",
+		.optional = true,
+		.prefer_gnttab = false,
+	},
+#endif
 };
 
 #define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data))
@@ -665,7 +680,12 @@ static int console_create_ring(struct console *con)
 			"port", "%i", &remote_port,
 			NULL);
 	if (err)
+	{
+		/* If the console is optional then do not return an error. */
+		if (con->optional)
+			err = 0;
 		goto out;
+	}
 
 	snprintf(path, sizeof(path), "%s/type", con->xspath);
 	type = xs_read(xs, XBT_NULL, path, NULL);
@@ -679,7 +699,9 @@ static int console_create_ring(struct console *con)
 	if (ring_ref != con->ring_ref && con->ring_ref != -1)
 		console_unmap_interface(con);
 
-	if (!con->interface && xgt_handle) {
+	if (!con->interface && 
+		xgt_handle &&
+		con->prefer_gnttab) {
 		/* Prefer using grant table */
 		con->interface = xengnttab_map_grant_ref(xgt_handle,
 			dom->domid, GNTTAB_RESERVED_CONSOLE,
@@ -789,6 +811,8 @@ static int console_init(struct console *con, struct domain *dom, void **data)
 	con->d = dom;
 	con->ttyname = (*con_data)->ttyname;
 	con->log_suffix = (*con_data)->log_suffix;
+	con->optional = (*con_data)->optional;
+	con->prefer_gnttab = (*con_data)->prefer_gnttab;
 	con->xsname = (*con_data)->xsname;
 	con->xspath = xs_get_domain_path(xs, dom->domid);
 	s = realloc(con->xspath, strlen(con->xspath) +
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 12/14 v4] xen/arm: vpl011: Add a new vuart console type to xenconsole client
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (10 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-06 23:41   ` Stefano Stabellini
  2017-06-06 17:25 ` [PATCH 13/14 v4] xen/arm: vpl011: Add a pl011 uart DT node in the guest device tree Bhupinder Thakur
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

Add a new console type VUART to connect to guest's emualated vuart
console.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

Changes since v3:
- The vuart console support is under CONFIG_VUART_CONSOLE option.
- Since there is a change from last review, I have not included
  reviewed-by tag from Stefano and acked-by tag from Wei.

 tools/console/Makefile      |  1 +
 tools/console/client/main.c | 25 ++++++++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/tools/console/Makefile b/tools/console/Makefile
index fcee313..49c02d4 100644
--- a/tools/console/Makefile
+++ b/tools/console/Makefile
@@ -34,6 +34,7 @@ xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c))
 	$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_xenconsoled) $(APPEND_LDFLAGS)
 
 client/main.o: client/_paths.h
+client/main.o: CFLAGS += $(VUART_CFLAGS-y)
 xenconsole: $(patsubst %.c,%.o,$(wildcard client/*.c))
 	$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_xenconsole) $(APPEND_LDFLAGS)
 
diff --git a/tools/console/client/main.c b/tools/console/client/main.c
index 977779f..8d31fe9 100644
--- a/tools/console/client/main.c
+++ b/tools/console/client/main.c
@@ -76,7 +76,11 @@ static void usage(const char *program) {
 	       "\n"
 	       "  -h, --help       display this help and exit\n"
 	       "  -n, --num N      use console number N\n"
+#ifdef CONFIG_VUART_CONSOLE
+	       "  --type TYPE      console type. must be 'pv', 'serial' or 'vuart'\n"
+#else
 	       "  --type TYPE      console type. must be 'pv' or 'serial'\n"
+#endif
 	       "  --start-notify-fd N file descriptor used to notify parent\n"
 	       , program);
 }
@@ -264,6 +268,9 @@ typedef enum {
        CONSOLE_INVAL,
        CONSOLE_PV,
        CONSOLE_SERIAL,
+#ifdef CONFIG_VUART_CONSOLE
+       CONSOLE_VUART,
+#endif
 } console_type;
 
 static struct termios stdin_old_attr;
@@ -343,6 +350,11 @@ int main(int argc, char **argv)
 	char *end;
 	console_type type = CONSOLE_INVAL;
 	bool interactive = 0;
+#ifdef CONFIG_VUART_CONSOLE
+	char *console_names = "serial, pv, vuart";
+#else
+	char *console_names = "serial, pv";
+#endif
 
 	if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))
 		interactive = 1;
@@ -361,9 +373,14 @@ int main(int argc, char **argv)
 				type = CONSOLE_SERIAL;
 			else if (!strcmp(optarg, "pv"))
 				type = CONSOLE_PV;
+#ifdef CONFIG_VUART_CONSOLE
+			else if (!strcmp(optarg, "vuart"))
+				type = CONSOLE_VUART;
+#endif
 			else {
 				fprintf(stderr, "Invalid type argument\n");
-				fprintf(stderr, "Console types supported are: serial, pv\n");
+				fprintf(stderr, "Console types supported are: %s\n",
+                        console_names);
 				exit(EINVAL);
 			}
 			break;
@@ -436,6 +453,12 @@ int main(int argc, char **argv)
 		else
 			snprintf(path, strlen(dom_path) + strlen("/device/console/%d/tty") + 5, "%s/device/console/%d/tty", dom_path, num);
 	}
+#ifdef CONFIG_VUART_CONSOLE
+	if (type == CONSOLE_VUART) {
+		snprintf(path, strlen(dom_path) + strlen("/vuart/0/tty") + 1,
+				 "%s/vuart/0/tty", dom_path);
+	}
+#endif
 
 	/* FIXME consoled currently does not assume domain-0 doesn't have a
 	   console which is good when we break domain-0 up.  To keep us
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 13/14 v4] xen/arm: vpl011: Add a pl011 uart DT node in the guest device tree
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (11 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 12/14 v4] xen/arm: vpl011: Add a new vuart console type to xenconsole client Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-06 17:25 ` [PATCH 14/14 v4] xen/arm: vpl011: Update documentation for vuart console support Bhupinder Thakur
  2017-06-09 13:58 ` [PATCH 00/14 v4] PL011 emulation support in Xen Julien Grall
  14 siblings, 0 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

The SBSA uart node format is as specified in
Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt and given below:

ARM SBSA defined generic UART
------------------------------
This UART uses a subset of the PL011 registers and consequently lives
in the PL011 driver. It's baudrate and other communication parameters
cannot be adjusted at runtime, so it lacks a clock specifier here.

Required properties:
- compatible: must be "arm,sbsa-uart"
- reg: exactly one register range
- interrupts: exactly one interrupt specifier
- current-speed: the (fixed) baud rate set by the firmware

Currently the baud rate of 115200 has been selected as a default value,
which is one of the valid baud rate setttings. Higher baud rate was
selected since an emulated pl011 can support any valid baud rate without
any limitation of the hardware.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
---
CC: ij
CC: wl
CC: ss
CC: jg

 tools/libxl/libxl_arm.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
index b60dfa9..b59fd9f 100644
--- a/tools/libxl/libxl_arm.c
+++ b/tools/libxl/libxl_arm.c
@@ -44,10 +44,22 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
     uint32_t nr_spis = 0;
     unsigned int i;
 
+    /*
+     * If pl011 vuart is enabled then increment the nr_spis to allow allocation
+     * of SPI VIRQ for pl011.
+     */
+    if (d_config->b_info.arch_arm.vuart)
+        nr_spis += (GUEST_VPL011_SPI - 32) + 1;
+
     for (i = 0; i < d_config->b_info.num_irqs; i++) {
         uint32_t irq = d_config->b_info.irqs[i];
         uint32_t spi;
 
+        if (d_config->b_info.arch_arm.vuart && (irq == GUEST_VPL011_SPI)) {
+            LOG(ERROR, "Physical IRQ %u conflicting with pl011 SPI\n", irq);
+            return ERROR_FAIL;
+        }
+
         if (irq < 32)
             continue;
 
@@ -149,9 +161,10 @@ static struct arch_info {
     const char *guest_type;
     const char *timer_compat;
     const char *cpu_compat;
+    const char *uart_compat;
 } arch_info[] = {
-    {"xen-3.0-armv7l",  "arm,armv7-timer", "arm,cortex-a15" },
-    {"xen-3.0-aarch64", "arm,armv8-timer", "arm,armv8" },
+    {"xen-3.0-armv7l",  "arm,armv7-timer", "arm,cortex-a15", "arm,sbsa-uart" },
+    {"xen-3.0-aarch64", "arm,armv8-timer", "arm,armv8", "arm,sbsa-uart" },
 };
 
 /*
@@ -609,6 +622,38 @@ static int make_hypervisor_node(libxl__gc *gc, void *fdt,
     return 0;
 }
 
+static int make_vpl011_uart_node(libxl__gc *gc, void *fdt,
+                                 const struct arch_info *ainfo,
+                                 struct xc_dom_image *dom)
+{
+    int res;
+    gic_interrupt intr;
+
+    res = fdt_begin_node(fdt, "sbsa-pl011");
+    if (res) return res;
+
+    res = fdt_property_compat(gc, fdt, 1, ainfo->uart_compat);
+    if (res) return res;
+
+    res = fdt_property_regs(gc, fdt, ROOT_ADDRESS_CELLS, ROOT_SIZE_CELLS,
+                            1,
+                            GUEST_PL011_BASE, GUEST_PL011_SIZE);
+    if (res) return res;
+
+    set_interrupt(intr, GUEST_VPL011_SPI, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
+
+    res = fdt_property_interrupts(gc, fdt, &intr, 1);
+    if (res) return res;
+
+    /* Use a default baud rate of 115200. */
+    fdt_property_u32(fdt, "current-speed", 115200);
+
+    res = fdt_end_node(fdt);
+    if (res) return res;
+
+    return 0;
+}
+
 static const struct arch_info *get_arch_info(libxl__gc *gc,
                                              const struct xc_dom_image *dom)
 {
@@ -908,6 +953,9 @@ next_resize:
         FDT( make_timer_node(gc, fdt, ainfo, xc_config->clock_frequency) );
         FDT( make_hypervisor_node(gc, fdt, vers) );
 
+        if (info->arch_arm.vuart)
+            FDT( make_vpl011_uart_node(gc, fdt, ainfo, dom) );
+
         if (pfdt)
             FDT( copy_partial_fdt(gc, fdt, pfdt) );
 
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* [PATCH 14/14 v4] xen/arm: vpl011: Update documentation for vuart console support
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (12 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 13/14 v4] xen/arm: vpl011: Add a pl011 uart DT node in the guest device tree Bhupinder Thakur
@ 2017-06-06 17:25 ` Bhupinder Thakur
  2017-06-09 13:58 ` [PATCH 00/14 v4] PL011 emulation support in Xen Julien Grall
  14 siblings, 0 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 17:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

1. Update documentation for a new vuart option added.
2. Update documentation about SPI irq reserved for vpl011.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Acked-by: Wei Liu <wei.liu2@citrix.com>
---
CC: ij
CC: wl
CC: ss
CC: jg

 docs/man/xl.cfg.pod.5.in |  9 +++++++++
 docs/misc/console.txt    | 44 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/docs/man/xl.cfg.pod.5.in b/docs/man/xl.cfg.pod.5.in
index 13167ff..3397cda 100644
--- a/docs/man/xl.cfg.pod.5.in
+++ b/docs/man/xl.cfg.pod.5.in
@@ -1085,6 +1085,15 @@ Allow a guest to access specific physical IRQs.
 It is recommended to use this option only for trusted VMs under
 administrator control.
 
+If the virtual uart is enabled then irq 32 is reserved for it. By
+default, it is disabled. If the user specifies the following option in
+the VM config file then the vuart gets enabled. Today, only the
+"pl011" model is supported.
+
+vuart = "pl011"
+
+Currently vuart console is available only for ARM64.
+
 =item B<max_event_channels=N>
 
 Limit the guest to using at most N event channels (PV interrupts).
diff --git a/docs/misc/console.txt b/docs/misc/console.txt
index 16da805..48fe914 100644
--- a/docs/misc/console.txt
+++ b/docs/misc/console.txt
@@ -19,7 +19,20 @@ The first PV console path in xenstore remains:
 
 /local/domain/$DOMID/console
 
-the other PV consoles follow the conventional xenstore device path and
+The virtual UART console path in xenstore is defined as:
+
+/local/domain/$DOMID/vuart/0
+
+The vuart console provides access to a virtual pl011 UART on ARM64 systems.
+To enable vuart the following line has to be added to the guest configuration
+file:
+
+vuart = "pl011"
+
+In Linux you can select the virtual pl011 UART by using the "ttyAMA0"
+console instead of "hvc0".
+
+The other PV consoles follow the conventional xenstore device path and
 live in:
 
 /local/domain/$DOMID/device/console/$DEVID.
@@ -61,6 +74,14 @@ output = pty
 The backend will write the pty device name to the "tty" node in the
 console frontend.
 
+For the PV console the tty node is added at
+
+/local/domain/$DOMID/console/tty
+
+For the virtual UART console the tty node is added at
+
+/local/domain/$DOMID/vuart/0/tty
+
 If the toolstack wants a listening Unix domain socket to be created at path
 <path>, a connection accepted and data proxied to the console, it will write:
 
@@ -79,8 +100,8 @@ For example:
 ioemu
 
 The supported values are only xenconsoled or ioemu; xenconsoled has
-several limitations: it can only be used for the first PV console and it
-can only connect to a pty.
+several limitations: it can only be used for the first PV or virtual UART
+console and it can only connect to a pty.
 
 Emulated serials are provided by qemu-dm only to hvm guests; the number
 of emulated serials depends on how many "-serial" command line options
@@ -90,14 +111,15 @@ xenstore in the following path:
 
 /local/domain/$DOMID/serial/$SERIAL_NUM/tty
 
-xenconsole is the tool to connect to a PV console or an emulated serial
-that has a pty as output. Xenconsole takes a domid as parameter plus an
-optional console type (pv for PV consoles or serial for emulated
-serials) and console number. Depending on the type and console
-number, xenconsole will look for the tty node in different xenstore
-paths, as described above.  If the user doesn't specify the console type
-xenconsole will try to guess: if the guest is a pv guest it defaults to
-PV console, if the guest is an hvm guest it defaults to emulated serial.
+xenconsole is the tool to connect to a PV or virtual UART console or an
+emulated serial that has a pty as output. Xenconsole takes a domid as 
+parameter plus an optional console type (pv for PV consoles, vuart for
+virtual UART or serial for emulated serials) and console number. 
+Depending on the type and console number, xenconsole will look for the tty 
+node in different xenstore paths, as described above.  If the user doesn't 
+specify the console type xenconsole will try to guess: if the guest is a pv 
+guest it defaults to PV console, if the guest is an hvm guest it defaults to 
+emulated serial.
 
 By default xl creates a pv console for hvm guests, plus an emulated
 serial if the user specified 'serial = "pty"' in the VM config file.
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-06 17:25 ` [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen Bhupinder Thakur
@ 2017-06-06 23:02   ` Stefano Stabellini
  2017-06-09 13:15     ` Julien Grall
  2017-06-09 13:54   ` Julien Grall
  2017-06-19 10:14   ` Andre Przywara
  2 siblings, 1 reply; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-06 23:02 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: Stefano Stabellini, Wei Liu, Ian Jackson, Julien Grall, xen-devel

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> Add emulation code to emulate read/write access to pl011 registers
> and pl011 interrupts:
> 
>     - Emulate DR read/write by reading and writing from/to the IN
>       and OUT ring buffers and raising an event to the backend when
>       there is data in the OUT ring buffer and injecting an interrupt
>       to the guest when there is data in the IN ring buffer
> 
>     - Other registers are related to interrupt management and
>       essentially control when interrupts are delivered to the guest
> 
> The SBSA compliant pl011 uart is covered in Appendix B of
> https://static.docs.arm.com/den0029/a/Server_Base_System_Architecture_v3_1_ARM_DEN_0029A.pdf
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> CC: kw
> 
> Changes since v3:
> - Moved the call to DEFINE_XEN_FLEX_RING from vpl011.h to public/console.h. This macro defines
>   standard functions to operate on the ring buffer.
> - Lock taken while updating the interrupt mask and clear registers in mmio_write.
> - Use gfn_t instead of xen_pfn_t.
> - vgic_free_virq called if there is any error in vpl011 initialization.
> - mmio handlers freed if there is any error in vpl011 initialization.
> - Removed vpl011->initialized flag usage as the same check could be done 
>   using vpl011->ring-ref.
> - Used return instead of break in the switch handling of emulation of different pl011 registers.
> - Renamed vpl011_update_spi() to vpl011_update().
> 
> Changes since v2:
> - Use generic vreg_reg* for read/write of registers emulating pl011.
> - Use generic ring buffer functions defined using DEFINE_XEN_FLEX_RING.
> - Renamed the SPI injection function to vpl011_update_spi() to reflect level 
>   triggered nature of pl011 interrupts.
> - The pl011 register access address should always be the base address of the
>   corresponding register as per section B of the SBSA document. For this reason,
>   the register range address access is not allowed.
> 
> Changes since v1:
> - Removed the optimiztion related to sendiing events to xenconsole 
> - Use local variables as ring buffer indices while using the ring buffer
> 
>  tools/console/daemon/io.c        |   2 +-
>  xen/arch/arm/Kconfig             |   5 +
>  xen/arch/arm/Makefile            |   1 +
>  xen/arch/arm/vpl011.c            | 418 +++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/domain.h     |   6 +
>  xen/include/asm-arm/pl011-uart.h |   2 +
>  xen/include/asm-arm/vpl011.h     |  74 +++++++
>  xen/include/public/arch-arm.h    |   6 +
>  xen/include/public/io/console.h  |   4 +
>  9 files changed, 517 insertions(+), 1 deletion(-)
>  create mode 100644 xen/arch/arm/vpl011.c
>  create mode 100644 xen/include/asm-arm/vpl011.h
> 
> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> index 7e6a886..947f13a 100644
> --- a/tools/console/daemon/io.c
> +++ b/tools/console/daemon/io.c
> @@ -21,6 +21,7 @@
>  
>  #include "utils.h"
>  #include "io.h"
> +#include <string.h>
>  #include <xenevtchn.h>
>  #include <xengnttab.h>
>  #include <xenstore.h>
> @@ -29,7 +30,6 @@
>  
>  #include <stdlib.h>
>  #include <errno.h>
> -#include <string.h>
>  #include <poll.h>
>  #include <fcntl.h>
>  #include <unistd.h>
> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> index d46b98c..c1a0e7f 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -50,6 +50,11 @@ config HAS_ITS
>          prompt "GICv3 ITS MSI controller support" if EXPERT = "y"
>          depends on HAS_GICV3
>  
> +config VPL011_CONSOLE
> +	bool "Emulated pl011 console support"
> +	default y
> +	---help---
> +	  Allows a guest to use pl011 UART as a console
>  endmenu
>  
>  menu "ARM errata workaround via the alternative framework"
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 49e1fb2..15efc13 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -52,6 +52,7 @@ obj-y += vm_event.o
>  obj-y += vtimer.o
>  obj-y += vpsci.o
>  obj-y += vuart.o
> +obj-$(CONFIG_VPL011_CONSOLE) += vpl011.o
>  
>  #obj-bin-y += ....o
>  
> diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
> new file mode 100644
> index 0000000..9b1f27e
> --- /dev/null
> +++ b/xen/arch/arm/vpl011.c
> @@ -0,0 +1,418 @@
> +/*
> + * arch/arm/vpl011.c
> + *
> + * Virtual PL011 UART
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <xen/errno.h>
> +#include <xen/event.h>
> +#include <xen/guest_access.h>
> +#include <xen/init.h>
> +#include <xen/lib.h>
> +#include <xen/mm.h>
> +#include <xen/sched.h>
> +#include <public/domctl.h>
> +#include <public/io/console.h>
> +#include <asm-arm/pl011-uart.h>
> +#include <asm-arm/vgic-emul.h>
> +#include <asm-arm/vpl011.h>
> +
> +static bool vpl011_reg32_check_access(struct hsr_dabt dabt)
> +{
> +    return (dabt.size != DABT_DOUBLE_WORD);
> +}
> +
> +static void vpl011_update(struct domain *d)
> +{
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    /*
> +     * TODO: PL011 interrupts are level triggered which means
> +     * that interrupt needs to be set/clear instead of being
> +     * injected. However, currently vGIC does not handle level 
> +     * triggered interrupts properly. This function needs to be 
> +     * revisited once vGIC starts handling level triggered 
> +     * interrupts.
> +     */
> +    if ( vpl011->uartris & vpl011->uartimsc )
> +        vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI);
> +}
> +
> +static uint8_t vpl011_read_data(struct domain *d)
> +{
> +    unsigned long flags;
> +    uint8_t data = 0;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX in_cons = intf->in_cons;
> +    XENCONS_RING_IDX in_prod = intf->in_prod;

After reading the indexes, we always need barriers. In this case:

  smp_rmb();


> +    VPL011_LOCK(d, flags);
> +
> +    /*
> +     * 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 )
> +    {
> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
> +        in_cons += 1;
> +        intf->in_cons = in_cons;
> +        smp_mb();
> +    }
> +    else
> +    {
> +        gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer empty\n");
> +    }
> +
> +    if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == 0 )
> +    {
> +        vpl011->uartfr |= RXFE;
> +        vpl011->uartris &= ~RXI;
> +    }
> +    vpl011->uartfr &= ~RXFF;
> +    VPL011_UNLOCK(d, flags);

I am pretty sure that the PV console protocol requires us to notify the
other end even on reads. We need to add a notify_via_xen_event_channel
here, I think.


> +    return data;
> +}
> +
> +static void vpl011_write_data(struct domain *d, uint8_t data)
> +{
> +    unsigned long flags;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX out_cons = intf->out_cons;
> +    XENCONS_RING_IDX out_prod = intf->out_prod;

  smp_mb()


> +    VPL011_LOCK(d, flags);
> +
> +    /*
> +     * It is expected that the ring is not full when this function is called
> +     * as the guest is expected to write to the data register only when the
> +     * TXFF flag is not set.
> +     * In case the guest does write even when the TXFF flag is set then the
> +     * data will be silently dropped.
> +     */
> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) !=
> +         sizeof (intf->out) )
> +    {
> +        intf->out[xencons_mask(out_prod, sizeof(intf->out))] = data;
> +        smp_wmb();
> +        out_prod += 1;
> +        intf->out_prod = out_prod;
> +    }
> +    else
> +    {
> +        gprintk(XENLOG_ERR, "vpl011: Unexpected OUT ring buffer full\n");
> +    }
> +
> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) ==
> +         sizeof (intf->out) )
> +    {
> +        vpl011->uartfr |= TXFF;
> +        vpl011->uartris &= ~TXI;
> +    }
> +
> +    vpl011->uartfr |= BUSY;
> +
> +    vpl011->uartfr &= ~TXFE;
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    /*
> +     * Send an event to console backend to indicate that there is 
> +     * data in the OUT ring buffer.
> +     */
> +    notify_via_xen_event_channel(d, vpl011->evtchn);
> +}
> +
> +static int vpl011_mmio_read(struct vcpu *v,
> +                            mmio_info_t *info,
> +                            register_t *r,
> +                            void *priv)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
> +
> +    switch ( vpl011_reg )
> +    {
> +    case DR:
> +        /*
> +         * Since pl011 registers are 32-bit registers, all registers
> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
> +         * accesses.
> +         */
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011_read_data(v->domain), info);
> +        return 1;
> +
> +    case RSR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        /* It always returns 0 as there are no physical errors. */
> +        *r = 0;
> +        return 1;
> +
> +    case FR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartfr, info);
> +        return 1;
> +
> +    case RIS:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartris, info);
> +        return 1;
> +
> +    case MIS:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartris & 
> +                                vpl011->uartimsc, info);
> +        return 1;
> +
> +    case IMSC:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartimsc, info);
> +        return 1;
> +
> +    case ICR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        /* Only write is valid. */
> +        return 0;
> +
> +    default:
> +        gprintk(XENLOG_ERR, "vpl011: unhandled read r%d offset %#08x\n",
> +                dabt.reg, vpl011_reg);
> +        return 0;
> +    }
> +
> +    return 1;
> +
> +bad_width:
> +    gprintk(XENLOG_ERR, "vpl011: bad read width %d r%d offset %#08x\n",
> +            dabt.size, dabt.reg, vpl011_reg);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +}
> +
> +static int vpl011_mmio_write(struct vcpu *v,
> +                             mmio_info_t *info,
> +                             register_t r,
> +                             void *priv)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
> +    struct domain *d = v->domain;
> +    unsigned long flags;
> +
> +    switch ( vpl011_reg )
> +    {
> +    case DR:
> +    {
> +        uint32_t data = 0;
> +
> +        /*
> +         * Since pl011 registers are 32-bit registers, all registers
> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
> +         * accesses.
> +         */
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        vreg_reg32_update(&data, r, info);
> +        data &= 0xFF;
> +        vpl011_write_data(v->domain, data);
> +        return 1;
> +    }
> +    case RSR: /* Nothing to clear. */
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        return 1; 
> +
> +    case FR:
> +    case RIS:
> +    case MIS:
> +        goto write_ignore;
> +
> +    case IMSC:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        VPL011_LOCK(d, flags);
> +        vreg_reg32_update(&vpl011->uartimsc, r, info);
> +        VPL011_UNLOCK(d, flags);
> +        vpl011_update(v->domain);
> +        return 1;
> +
> +    case ICR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        VPL011_LOCK(d, flags);
> +        vreg_reg32_clearbits(&vpl011->uartris, r, info);
> +        VPL011_UNLOCK(d, flags);
> +        vpl011_update(d);
> +        return 1;
> +
> +    default:
> +        gprintk(XENLOG_ERR, "vpl011: unhandled write r%d offset %#08x\n",
> +                dabt.reg, vpl011_reg);
> +        return 0;
> +    }
> +
> +write_ignore:
> +    return 1;
> +
> +bad_width:
> +    gprintk(XENLOG_ERR, "vpl011: bad write width %d r%d offset %#08x\n",
> +            dabt.size, dabt.reg, vpl011_reg);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +}
> +
> +static const struct mmio_handler_ops vpl011_mmio_handler = {
> +    .read = vpl011_mmio_read,
> +    .write = vpl011_mmio_write,
> +};
> +
> +static void vpl011_data_avail(struct domain *d)
> +{
> +    unsigned long flags;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX in_cons = intf->in_cons;
> +    XENCONS_RING_IDX in_prod = intf->in_prod;
> +    XENCONS_RING_IDX out_cons = intf->out_cons;
> +    XENCONS_RING_IDX out_prod = intf->out_prod;
> +    XENCONS_RING_IDX in_ring_qsize, out_ring_qsize;

  smb_mb()


> +    VPL011_LOCK(d, flags);
> +
> +    in_ring_qsize = xencons_queued(in_prod,
> +                                   in_cons,
> +                                   sizeof(intf->in));
> +
> +    out_ring_qsize = xencons_queued(out_prod,
> +                                    out_cons,
> +                                    sizeof(intf->out));
> +
> +    /* Update the uart rx state if the buffer is not empty. */
> +    if ( in_ring_qsize != 0 )
> +    {
> +        vpl011->uartfr &= ~RXFE;
> +        if ( in_ring_qsize == sizeof(intf->in) )
> +            vpl011->uartfr |= RXFF;
> +        vpl011->uartris |= RXI;
> +    }
> +
> +    /* Update the uart tx state if the buffer is not full. */
> +    if ( out_ring_qsize != sizeof(intf->out) )
> +    {
> +        vpl011->uartfr &= ~TXFF;
> +        vpl011->uartris |= TXI;
> +        if ( out_ring_qsize == 0 )
> +        {
> +            vpl011->uartfr &= ~BUSY;
> +            vpl011->uartfr |= TXFE;
> +        }
> +    }
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    vpl011_update(d);
> +}
> +
> +
> +static void vpl011_notification(struct vcpu *v, unsigned int port)
> +{
> +    vpl011_data_avail(v->domain);
> +}
> +
> +int domain_vpl011_init(struct domain *d, struct vpl011_init_info *info)
> +{
> +    int rc;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    if ( vpl011->ring_buf )
> +        return 0;
> +
> +    /* Map the guest PFN to Xen address space. */
> +    rc =  prepare_ring_for_helper(d,
> +                                  gfn_x(info->gfn),
> +                                  &vpl011->ring_page,
> +                                  &vpl011->ring_buf);
> +    if ( rc < 0 )
> +        goto out;
> +
> +    rc = vgic_reserve_virq(d, GUEST_VPL011_SPI);
> +    if ( !rc )
> +    {
> +        rc = -EINVAL;
> +        goto out1;
> +    }
> +
> +    register_mmio_handler(d, &vpl011_mmio_handler,
> +                          GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);
> +
> +    spin_lock_init(&vpl011->lock);
> +
> +    rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid,
> +                                         vpl011_notification);
> +    if ( rc < 0 )
> +        goto out2;
> +
> +    vpl011->evtchn = info->evtchn = rc;
> +
> +    return 0;
> +
> +out2:
> +    xfree(d->arch.vmmio.handlers);
> +    vgic_free_virq(d, GUEST_VPL011_SPI);
> +
> +out1:
> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
> +
> +out:
> +    return rc;
> +}
> +
> +void domain_vpl011_deinit(struct domain *d)
> +{
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    if ( !vpl011->ring_buf )
> +        return;
> +
> +    free_xen_event_channel(d, vpl011->evtchn);
> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
> +    xfree(d->arch.vmmio.handlers);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 6de8082..91d1061 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -11,6 +11,7 @@
>  #include <public/hvm/params.h>
>  #include <xen/serial.h>
>  #include <xen/rbtree.h>
> +#include <asm-arm/vpl011.h>
>  
>  struct hvm_domain
>  {
> @@ -133,6 +134,11 @@ struct arch_domain
>      struct {
>          uint8_t privileged_call_enabled : 1;
>      } monitor;
> +
> +#ifdef CONFIG_VPL011_CONSOLE
> +    struct vpl011 vpl011;
> +#endif
> +
>  }  __cacheline_aligned;
>  
>  struct arch_vcpu
> diff --git a/xen/include/asm-arm/pl011-uart.h b/xen/include/asm-arm/pl011-uart.h
> index 123f477..57e9ec7 100644
> --- a/xen/include/asm-arm/pl011-uart.h
> +++ b/xen/include/asm-arm/pl011-uart.h
> @@ -49,6 +49,8 @@
>  /* FR bits */
>  #define TXFE   (1<<7) /* TX FIFO empty */
>  #define RXFE   (1<<4) /* RX FIFO empty */
> +#define TXFF   (1<<5) /* TX FIFO full */
> +#define RXFF   (1<<6) /* RX FIFO full */
>  #define BUSY   (1<<3) /* Transmit is not complete */
>  
>  /* LCR_H bits */
> diff --git a/xen/include/asm-arm/vpl011.h b/xen/include/asm-arm/vpl011.h
> new file mode 100644
> index 0000000..b3e332d
> --- /dev/null
> +++ b/xen/include/asm-arm/vpl011.h
> @@ -0,0 +1,74 @@
> +/*
> + * include/xen/vpl011.h
> + *
> + * Virtual PL011 UART
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef _VPL011_H_
> +
> +#define _VPL011_H_
> +
> +#include <public/domctl.h>
> +#include <public/io/ring.h>
> +#include <asm-arm/vreg.h>
> +#include <xen/mm.h>
> +
> +/* helper macros */
> +#define VPL011_LOCK(d,flags) spin_lock_irqsave(&(d)->arch.vpl011.lock, flags)
> +#define VPL011_UNLOCK(d,flags) spin_unlock_irqrestore(&(d)->arch.vpl011.lock, flags)
> +
> +struct vpl011 {
> +    void *ring_buf;
> +    struct page_info *ring_page;
> +    uint32_t    uartfr;     /* Flag register */
> +    uint32_t    uartcr;     /* Control register */
> +    uint32_t    uartimsc;   /* Interrupt mask register*/
> +    uint32_t    uarticr;    /* Interrupt clear register */
> +    uint32_t    uartris;    /* Raw interrupt status register */
> +    uint32_t    uartmis;    /* Masked interrupt register */
> +    spinlock_t  lock;
> +    evtchn_port_t evtchn;
> +};
> +
> +struct vpl011_init_info {
> +    uint32_t console_domid;
> +    gfn_t gfn;
> +    evtchn_port_t evtchn;
> +};
> +
> +#ifdef CONFIG_VPL011_CONSOLE
> +int domain_vpl011_init(struct domain *d,
> +                       struct vpl011_init_info *info);
> +void domain_vpl011_deinit(struct domain *d);
> +#else
> +static inline int domain_vpl011_init(struct domain *d,
> +                                     struct vpl011_init_info *info)
> +{
> +    return -ENOSYS;
> +}
> +
> +static inline void domain_vpl011_deinit(struct domain *d) { }
> +#endif
> +
> +#endif
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
> index bd974fb..85ab665 100644
> --- a/xen/include/public/arch-arm.h
> +++ b/xen/include/public/arch-arm.h
> @@ -410,6 +410,10 @@ typedef uint64_t xen_callback_t;
>  #define GUEST_ACPI_BASE 0x20000000ULL
>  #define GUEST_ACPI_SIZE 0x02000000ULL
>  
> +/* PL011 mappings */
> +#define GUEST_PL011_BASE    0x22000000ULL
> +#define GUEST_PL011_SIZE    0x00001000ULL
> +
>  /*
>   * 16MB == 4096 pages reserved for guest to use as a region to map its
>   * grant table in.
> @@ -444,6 +448,8 @@ typedef uint64_t xen_callback_t;
>  #define GUEST_TIMER_PHYS_NS_PPI 30
>  #define GUEST_EVTCHN_PPI        31
>  
> +#define GUEST_VPL011_SPI        32
> +
>  /* PSCI functions */
>  #define PSCI_cpu_suspend 0
>  #define PSCI_cpu_off     1
> diff --git a/xen/include/public/io/console.h b/xen/include/public/io/console.h
> index e2cd97f..5e45e1c 100644
> --- a/xen/include/public/io/console.h
> +++ b/xen/include/public/io/console.h
> @@ -27,6 +27,8 @@
>  #ifndef __XEN_PUBLIC_IO_CONSOLE_H__
>  #define __XEN_PUBLIC_IO_CONSOLE_H__
>  
> +#include "ring.h"
> +
>  typedef uint32_t XENCONS_RING_IDX;
>  
>  #define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
> @@ -38,6 +40,8 @@ struct xencons_interface {
>      XENCONS_RING_IDX out_cons, out_prod;
>  };
>  
> +DEFINE_XEN_FLEX_RING(xencons);
> +
>  #endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
>  
>  /*
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 04/14 v4] xen/arm: vpl011: Add support for vuart in libxl
  2017-06-06 17:25 ` [PATCH 04/14 v4] xen/arm: vpl011: Add support for vuart in libxl Bhupinder Thakur
@ 2017-06-06 23:07   ` Stefano Stabellini
  0 siblings, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-06 23:07 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> An option is provided in libxl to enable/disable pl011 vuart while
> creating a guest domain.
> 
> Libxl now suppots a generic vuart console and pl011 is a specific type.
> In future support can be added for multiple vuart of different types.
> 
> User can enable pl011 vuart by adding the following line in the guest
> configuration file:
> 
> vuart = "pl011"
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - Added a new config option CONFIG_VUART_CONSOLE to enable/disable vuart console
>   support.
> - Moved libxl_vuart_type to arch-arm part of libxl_domain_build_info
> - Updated xl command help to mention new console type - vuart.
> 
> Changes since v2:
> - Defined vuart option as an enum instead of a string.
> - Removed the domain creation flag defined for vuart and the related code
>   to pass on the information while domain creation. Now vpl011 is initialized
>   independent of domain creation through new DOMCTL APIs.
> 
>  config/arm32.mk              |  1 +
>  config/arm64.mk              |  1 +
>  tools/libxl/libxl.h          |  6 ++++++
>  tools/libxl/libxl_console.c  |  3 +++
>  tools/libxl/libxl_internal.h |  3 +++
>  tools/libxl/libxl_types.idl  |  7 +++++++
>  tools/xl/Makefile            |  4 ++++
>  tools/xl/xl_cmdtable.c       |  4 ++++
>  tools/xl/xl_console.c        | 11 ++++++++++-
>  tools/xl/xl_parse.c          |  8 ++++++++
>  10 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/config/arm32.mk b/config/arm32.mk
> index f95228e..b9f23fe 100644
> --- a/config/arm32.mk
> +++ b/config/arm32.mk
> @@ -1,5 +1,6 @@
>  CONFIG_ARM := y
>  CONFIG_ARM_32 := y
> +CONFIG_VUART_CONSOLE := y
>  CONFIG_ARM_$(XEN_OS) := y
>  
>  CONFIG_XEN_INSTALL_SUFFIX :=
> diff --git a/config/arm64.mk b/config/arm64.mk
> index aa45772..861d0a4 100644
> --- a/config/arm64.mk
> +++ b/config/arm64.mk
> @@ -1,5 +1,6 @@
>  CONFIG_ARM := y
>  CONFIG_ARM_64 := y
> +CONFIG_VUART_CONSOLE := y
>  CONFIG_ARM_$(XEN_OS) := y
>  
>  CONFIG_XEN_INSTALL_SUFFIX :=
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index cf8687a..bcfbb6c 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h
> @@ -306,6 +306,12 @@
>  #define LIBXL_HAVE_BUILDINFO_HVM_ACPI_LAPTOP_SLATE 1
>  
>  /*
> + * LIBXL_HAVE_VUART indicates that xenconsole/client supports
> + * virtual uart.
> + */
> +#define LIBXL_HAVE_VUART 1
> +
> +/*
>   * libxl ABI compatibility
>   *
>   * The only guarantee which libxl makes regarding ABI compatibility
> diff --git a/tools/libxl/libxl_console.c b/tools/libxl/libxl_console.c
> index 446e766..853be15 100644
> --- a/tools/libxl/libxl_console.c
> +++ b/tools/libxl/libxl_console.c
> @@ -67,6 +67,9 @@ int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num,
>      case LIBXL_CONSOLE_TYPE_SERIAL:
>          cons_type_s = "serial";
>          break;
> +    case LIBXL_CONSOLE_TYPE_VUART:
> +        cons_type_s = "vuart";
> +        break;
>      default:
>          goto out;
>      }
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index 5d082c5..4e2c247 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -1135,6 +1135,9 @@ typedef struct {
>      uint32_t num_vmemranges;
>  
>      xc_domain_configuration_t config;
> +
> +    xen_pfn_t vuart_gfn;
> +    evtchn_port_t vuart_port;
>  } libxl__domain_build_state;
>  
>  _hidden int libxl__build_pre(libxl__gc *gc, uint32_t domid,
> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> index 2204425..066aace 100644
> --- a/tools/libxl/libxl_types.idl
> +++ b/tools/libxl/libxl_types.idl
> @@ -105,6 +105,7 @@ libxl_console_type = Enumeration("console_type", [
>      (0, "UNKNOWN"),
>      (1, "SERIAL"),
>      (2, "PV"),
> +    (3, "VUART"),
>      ])
>  
>  libxl_disk_format = Enumeration("disk_format", [
> @@ -240,6 +241,11 @@ libxl_checkpointed_stream = Enumeration("checkpointed_stream", [
>      (2, "COLO"),
>      ])
>  
> +libxl_vuart_type = Enumeration("vuart_type", [
> +    (0, "unknown"),
> +    (1, "pl011"),
> +    ])
> +
>  #
>  # Complex libxl types
>  #
> @@ -580,6 +586,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
>  
>  
>      ("arch_arm", Struct(None, [("gic_version", libxl_gic_version),
> +                               ("vuart", libxl_vuart_type),
>                                ])),
>      # Alternate p2m is not bound to any architecture or guest type, as it is
>      # supported by x86 HVM and ARM support is planned.
> diff --git a/tools/xl/Makefile b/tools/xl/Makefile
> index e16f877..d7c4927 100644
> --- a/tools/xl/Makefile
> +++ b/tools/xl/Makefile
> @@ -15,6 +15,10 @@ LDFLAGS += $(PTHREAD_LDFLAGS)
>  CFLAGS_XL += $(CFLAGS_libxenlight)
>  CFLAGS_XL += -Wshadow
>  
> +ifeq ($(CONFIG_VUART_CONSOLE),y)
> +CFLAGS_XL += -DCONFIG_VUART_CONSOLE
> +endif
> +
>  XL_OBJS = xl.o xl_cmdtable.o xl_sxp.o xl_utils.o
>  XL_OBJS += xl_tmem.o xl_parse.o xl_cpupool.o xl_flask.o
>  XL_OBJS += xl_vtpm.o xl_block.o xl_nic.o xl_usb.o
> diff --git a/tools/xl/xl_cmdtable.c b/tools/xl/xl_cmdtable.c
> index 30eb93c..14f7a50 100644
> --- a/tools/xl/xl_cmdtable.c
> +++ b/tools/xl/xl_cmdtable.c
> @@ -133,7 +133,11 @@ struct cmd_spec cmd_table[] = {
>        &main_console, 0, 0,
>        "Attach to domain's console",
>        "[options] <Domain>\n"
> +#ifdef CONFIG_VUART_CONSOLE
> +      "-t <type>       console type, pv , serial or vuart\n"
> +#else
>        "-t <type>       console type, pv or serial\n"
> +#endif
>        "-n <number>     console number"
>      },
>      { "vncviewer",
> diff --git a/tools/xl/xl_console.c b/tools/xl/xl_console.c
> index 0508dda..d6ca93f 100644
> --- a/tools/xl/xl_console.c
> +++ b/tools/xl/xl_console.c
> @@ -27,6 +27,11 @@ int main_console(int argc, char **argv)
>      uint32_t domid;
>      int opt = 0, num = 0;
>      libxl_console_type type = 0;
> +#ifdef CONFIG_VUART_CONSOLE
> +    char *console_names = "pv, serial, vuart";
> +#else
> +    char *console_names = "pv, serial";
> +#endif
>  
>      SWITCH_FOREACH_OPT(opt, "n:t:", NULL, "console", 1) {
>      case 't':
> @@ -34,8 +39,12 @@ int main_console(int argc, char **argv)
>              type = LIBXL_CONSOLE_TYPE_PV;
>          else if (!strcmp(optarg, "serial"))
>              type = LIBXL_CONSOLE_TYPE_SERIAL;
> +#ifdef CONFIG_VUART_CONSOLE
> +        else if (!strcmp(optarg, "vuart"))
> +            type = LIBXL_CONSOLE_TYPE_VUART;
> +#endif
>          else {
> -            fprintf(stderr, "console type supported are: pv, serial\n");
> +            fprintf(stderr, "console type supported are: %s\n", console_names);
>              return EXIT_FAILURE;
>          }
>          break;

For all these "xl console" changes (affecting xl_console.c and
xl_cmdtable.c), I think we could safely get rid of the "#ifdef
CONFIG_VUART_CONSOLE" and always build the code for vuart, given how
small it is.

If a domain doesn't have a vuart (for any reasons, including that Xen
was not built with vuart support) it won't find any and exit anyway.


> diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
> index 856a304..37581ef 100644
> --- a/tools/xl/xl_parse.c
> +++ b/tools/xl/xl_parse.c
> @@ -916,6 +916,14 @@ void parse_config_data(const char *config_source,
>      if (!xlu_cfg_get_long (config, "maxvcpus", &l, 0))
>          b_info->max_vcpus = l;
>  
> +    if (!xlu_cfg_get_string(config, "vuart", &buf, 0)) {
> +        if (libxl_vuart_type_from_string(buf, &b_info->arch_arm.vuart)) {
> +            fprintf(stderr, "ERROR: invalid value \"%s\" for \"vuart\"\n",
> +                    buf);
> +            exit(1);
> +        }
> +    }
> +
>      parse_vnuma_config(config, b_info);
>  
>      /* Set max_memkb to target_memkb and max_vcpus to avail_vcpus if
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 05/14 v4] xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart
  2017-06-06 17:25 ` [PATCH 05/14 v4] xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart Bhupinder Thakur
@ 2017-06-06 23:17   ` Stefano Stabellini
  2017-06-07 16:43   ` Wei Liu
  1 sibling, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-06 23:17 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> Allocate a new gfn to be used as a ring buffer between xenconsole
> and Xen for sending/receiving pl011 console data.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - Added a new helper function xc_get_vuart_gfn() to return the GFN allocated for
>   vpl011.
> - Since a new function has been added in this patch, I have not included Stefano's
>   reviewed-by and Wei's acked-by tags.
> 
> Changes since v2:
> - Removed the DOMCTL call to set the GFN as now this information is passed
>   in the DOMCTL call to initialize vpl011 emulation.
> 
>  tools/libxc/include/xc_dom.h |  3 +++
>  tools/libxc/xc_dom_arm.c     | 12 +++++++++++-
>  tools/libxc/xc_dom_boot.c    |  2 ++
>  3 files changed, 16 insertions(+), 1 deletion(-)

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> diff --git a/tools/libxc/include/xc_dom.h b/tools/libxc/include/xc_dom.h
> index ce47058..1cde2b7 100644
> --- a/tools/libxc/include/xc_dom.h
> +++ b/tools/libxc/include/xc_dom.h
> @@ -216,6 +216,8 @@ struct xc_dom_image {
>  
>      /* Extra SMBIOS structures passed to HVMLOADER */
>      struct xc_hvm_firmware_module smbios_module;
> +
> +    xen_pfn_t vuart_gfn;
>  };
>  
>  /* --- pluggable kernel loader ------------------------------------- */
> @@ -334,6 +336,7 @@ int xc_dom_gnttab_seed(xc_interface *xch, domid_t domid,
>                         domid_t console_domid,
>                         domid_t xenstore_domid);
>  bool xc_dom_translated(const struct xc_dom_image *dom);
> +xen_pfn_t xc_get_vuart_gfn(void);
>  
>  /* --- debugging bits ---------------------------------------------- */
>  
> diff --git a/tools/libxc/xc_dom_arm.c b/tools/libxc/xc_dom_arm.c
> index e7d4bd0..89d0d37 100644
> --- a/tools/libxc/xc_dom_arm.c
> +++ b/tools/libxc/xc_dom_arm.c
> @@ -26,10 +26,11 @@
>  #include "xg_private.h"
>  #include "xc_dom.h"
>  
> -#define NR_MAGIC_PAGES 3
> +#define NR_MAGIC_PAGES 4
>  #define CONSOLE_PFN_OFFSET 0
>  #define XENSTORE_PFN_OFFSET 1
>  #define MEMACCESS_PFN_OFFSET 2
> +#define VUART_PFN_OFFSET 3
>  
>  #define LPAE_SHIFT 9
>  
> @@ -64,6 +65,13 @@ static int setup_pgtables_arm(struct xc_dom_image *dom)
>  
>  /* ------------------------------------------------------------------------ */
>  
> +xen_pfn_t xc_get_vuart_gfn()
> +{
> +    const xen_pfn_t base = GUEST_MAGIC_BASE >> XC_PAGE_SHIFT;
> +
> +    return base + VUART_PFN_OFFSET;
> +}
> +
>  static int alloc_magic_pages(struct xc_dom_image *dom)
>  {
>      int rc, i;
> @@ -85,10 +93,12 @@ static int alloc_magic_pages(struct xc_dom_image *dom)
>  
>      dom->console_pfn = base + CONSOLE_PFN_OFFSET;
>      dom->xenstore_pfn = base + XENSTORE_PFN_OFFSET;
> +    dom->vuart_gfn = base + VUART_PFN_OFFSET;
>  
>      xc_clear_domain_page(dom->xch, dom->guest_domid, dom->console_pfn);
>      xc_clear_domain_page(dom->xch, dom->guest_domid, dom->xenstore_pfn);
>      xc_clear_domain_page(dom->xch, dom->guest_domid, base + MEMACCESS_PFN_OFFSET);
> +    xc_clear_domain_page(dom->xch, dom->guest_domid, base + VUART_PFN_OFFSET);
>      xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CONSOLE_PFN,
>              dom->console_pfn);
>      xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_STORE_PFN,
> diff --git a/tools/libxc/xc_dom_boot.c b/tools/libxc/xc_dom_boot.c
> index c3b44dd..8a376d0 100644
> --- a/tools/libxc/xc_dom_boot.c
> +++ b/tools/libxc/xc_dom_boot.c
> @@ -226,6 +226,8 @@ int xc_dom_boot_image(struct xc_dom_image *dom)
>          return rc;
>      if ( (rc = clear_page(dom, dom->xenstore_pfn)) != 0 )
>          return rc;
> +    if ( (rc = clear_page(dom, dom->vuart_gfn)) != 0 )
> +        return rc;
>  
>      /* start info page */
>      if ( dom->arch_hooks->start_info )
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-06 17:25 ` [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011 Bhupinder Thakur
@ 2017-06-06 23:26   ` Stefano Stabellini
  2017-06-09 14:06     ` Julien Grall
  2017-06-14  7:35     ` Bhupinder Thakur
  2017-06-09 14:13   ` Julien Grall
  1 sibling, 2 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-06 23:26 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> Add a new domctl API to initialize vpl011. It takes the GFN and console
> backend domid as input and returns an event channel to be used for
> sending and receiving events from Xen.
> 
> Xen will communicate with xenconsole using GFN as the ring buffer and
> the event channel to transmit and receive pl011 data on the guest domain's
> behalf.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - Added a new arch specific function libxl__arch_domain_create_finish(), which
>   calls the vpl011 initialization function. For x86 this function does not do
>   anything.
> - domain_vpl011_init() takes a pointer to a structure which contains all the 
>   required information such as console_domid, gfn instead of passing parameters
>   separately.
> - Dropped a DOMCTL API defined for de-initializing vpl011 as that should be
>   taken care when the domain is destroyed (and not dependent on userspace 
>   libraries/applications).
> 
> Changes since v2:
> - Replaced the DOMCTL APIs defined for get/set of event channel and GFN with 
>   a set of DOMCTL APIs for initializing and de-initializing vpl011 emulation.
> 
>  tools/libxc/include/xenctrl.h | 17 +++++++++++++++++
>  tools/libxc/xc_domain.c       | 23 ++++++++++++++++++++++
>  tools/libxl/libxl_arch.h      |  7 +++++++
>  tools/libxl/libxl_arm.c       | 19 +++++++++++++++++++
>  tools/libxl/libxl_dom.c       |  6 +++++-
>  tools/libxl/libxl_x86.c       |  8 ++++++++
>  xen/arch/arm/domain.c         |  2 ++
>  xen/arch/arm/domctl.c         | 44 ++++++++++++++++++++++++++++++++++++++++---
>  xen/include/public/domctl.h   | 12 ++++++++++++
>  9 files changed, 134 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
> index 1629f41..77425dd 100644
> --- a/tools/libxc/include/xenctrl.h
> +++ b/tools/libxc/include/xenctrl.h
> @@ -884,6 +884,23 @@ int xc_vcpu_getcontext(xc_interface *xch,
>                         uint32_t domid,
>                         uint32_t vcpu,
>                         vcpu_guest_context_any_t *ctxt);
> +/**
> + * This function initializes the vpl011 emulation and returns
> + * the event to be used by the backend for communicating with
> + * the emulation code.
> + *
> + * @parm xch a handle to an open hypervisor interface
> + * @parm domid the domain to get information from
> + * @parm console_domid the domid of the backend console
> + * @parm gfn the guest pfn to be used as the ring buffer
> + * @parm evtchn the event channel to be used for events
> + * @return 0 on success, negative error on failure
> + */
> +int xc_dom_vpl011_init(xc_interface *xch,
> +                       uint32_t domid,
> +                       uint32_t console_domid,
> +                       xen_pfn_t gfn,
> +                       evtchn_port_t *evtchn);
>  
>  /**
>   * This function returns information about the XSAVE state of a particular
> diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
> index 00909ad4..a8efd5e 100644
> --- a/tools/libxc/xc_domain.c
> +++ b/tools/libxc/xc_domain.c
> @@ -343,6 +343,29 @@ int xc_domain_get_guest_width(xc_interface *xch, uint32_t domid,
>      return 0;
>  }
>  
> +int xc_dom_vpl011_init(xc_interface *xch,
> +                       uint32_t domid,
> +                       uint32_t console_domid,
> +                       xen_pfn_t gfn,
> +                       evtchn_port_t *evtchn)
> +{
> +    DECLARE_DOMCTL;
> +    int rc = 0;
> +
> +    domctl.cmd = XEN_DOMCTL_vuart_op;
> +    domctl.domain = (domid_t)domid;
> +    domctl.u.vuart_op.cmd = XEN_DOMCTL_VUART_OP_INIT_VPL011;
> +    domctl.u.vuart_op.console_domid = console_domid;
> +    domctl.u.vuart_op.gfn = gfn;
> +
> +    if ( (rc = do_domctl(xch, &domctl)) < 0 )
> +        return rc;
> +
> +    *evtchn = domctl.u.vuart_op.evtchn;
> +
> +    return rc;
> +}

It looks like this function should be in one of the arm specific files,
such as xc_dom_arm.c (otherwise it becomes available to x86 too).


>  int xc_domain_getinfo(xc_interface *xch,
>                        uint32_t first_domid,
>                        unsigned int max_doms,
> diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
> index 5e1fc60..d1ca9c6 100644
> --- a/tools/libxl/libxl_arch.h
> +++ b/tools/libxl/libxl_arch.h
> @@ -32,6 +32,13 @@ _hidden
>  int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
>                 uint32_t domid);
>  
> +/* arch specific internal domain creation finish function */
> +_hidden
> +int libxl__arch_domain_create_finish(libxl__gc *gc,
> +                                     libxl_domain_build_info *info,
> +                                     uint32_t domid,
> +                                     libxl__domain_build_state *state);
> +
>  /* setup arch specific hardware description, i.e. DTB on ARM */
>  _hidden
>  int libxl__arch_domain_init_hw_description(libxl__gc *gc,
> diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
> index d842d88..b60dfa9 100644
> --- a/tools/libxl/libxl_arm.c
> +++ b/tools/libxl/libxl_arm.c
> @@ -106,6 +106,25 @@ int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
>      return 0;
>  }
>  
> +int libxl__arch_domain_create_finish(libxl__gc *gc,
> +                                     libxl_domain_build_info *info,
> +                                     uint32_t domid,
> +                                     libxl__domain_build_state *state)
> +{
> +    int ret = 0;
> +
> +    if ( info->arch_arm.vuart &&
> +         (ret = xc_dom_vpl011_init(CTX->xch,
> +                                   domid,
> +                                   state->console_domid,
> +                                   xc_get_vuart_gfn(),
> +                                   &state->vuart_port)) != 0 ) {
> +        LOG(ERROR, "xc_dom_vpl011_init failed\n");
> +    }
> +
> +    return ret;
> +}
> +
>  int libxl__arch_extra_memory(libxl__gc *gc,
>                               const libxl_domain_build_info *info,
>                               uint64_t *out)
> diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
> index 5d914a5..187c5bd 100644
> --- a/tools/libxl/libxl_dom.c
> +++ b/tools/libxl/libxl_dom.c
> @@ -587,7 +587,10 @@ retry_transaction:
>              goto retry_transaction;
>      xs_introduce_domain(ctx->xsh, domid, state->store_mfn, state->store_port);
>      free(vm_path);
> -    return 0;
> +
> +    rc = libxl__arch_domain_create_finish(gc, info, domid, state);
> +
> +    return rc;
>  }
>  
>  static int set_vnuma_info(libxl__gc *gc, uint32_t domid,
> @@ -788,6 +791,7 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
>      if (xc_dom_translated(dom)) {
>          state->console_mfn = dom->console_pfn;
>          state->store_mfn = dom->xenstore_pfn;
> +        state->vuart_gfn = dom->vuart_gfn;
>      } else {
>          state->console_mfn = xc_dom_p2m(dom, dom->console_pfn);
>          state->store_mfn = xc_dom_p2m(dom, dom->xenstore_pfn);

vuart_gfn was introduced in patch #4, why are we setting it only now?


> diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
> index 455f6f0..3544028 100644
> --- a/tools/libxl/libxl_x86.c
> +++ b/tools/libxl/libxl_x86.c
> @@ -358,6 +358,14 @@ out:
>      return ret;
>  }
>  
> +int libxl__arch_domain_create_finish(libxl__gc *gc,
> +                                     libxl_domain_build_info *info,
> +                                     uint32_t domid,
> +                                     libxl__domain_build_state *state)
> +{
> +    return 0;
> +}
> +
>  int libxl__arch_extra_memory(libxl__gc *gc,
>                               const libxl_domain_build_info *info,
>                               uint64_t *out)
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 76310ed..9e150ba 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -665,6 +665,8 @@ fail:
>  
>  void arch_domain_destroy(struct domain *d)
>  {
> +    domain_vpl011_deinit(d);
> +
>      /* IOMMU page table is shared with P2M, always call
>       * iommu_domain_destroy() before p2m_teardown().
>       */

I cannot find the definition of domain_vpl011_deinit


> diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
> index 971caec..741679b 100644
> --- a/xen/arch/arm/domctl.c
> +++ b/xen/arch/arm/domctl.c
> @@ -5,13 +5,15 @@
>   */
>  
>  #include <xen/types.h>
> -#include <xen/lib.h>
> +#include <public/domctl.h>
>  #include <xen/errno.h>
> -#include <xen/sched.h>
> +#include <xen/guest_access.h>
>  #include <xen/hypercall.h>
>  #include <xen/iocap.h>
> +#include <xen/lib.h>
> +#include <xen/mm.h>
> +#include <xen/sched.h>
>  #include <xsm/xsm.h>
> -#include <public/domctl.h>
>  
>  void arch_get_domain_info(const struct domain *d,
>                            struct xen_domctl_getdomaininfo *info)
> @@ -119,6 +121,42 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
>          d->disable_migrate = domctl->u.disable_migrate.disable;
>          return 0;
>  
> +    case XEN_DOMCTL_vuart_op:
> +    {
> +        int rc;
> +        struct xen_domctl_vuart_op *vuart_op = &domctl->u.vuart_op;
> +
> +        switch(vuart_op->cmd)
> +        {
> +        case XEN_DOMCTL_VUART_OP_INIT_VPL011:
> +
> +            if ( !d->creation_finished )
> +            {
> +                struct vpl011_init_info info;
> +
> +                info.console_domid = vuart_op->console_domid;
> +                info.gfn = _gfn(vuart_op->gfn);
> +
> +                rc = domain_vpl011_init(d, &info);
> +                if ( !rc )
> +                {
> +                    vuart_op->evtchn = info.evtchn;
> +                    rc = __copy_to_guest(u_domctl, domctl, 1);
> +                }
> +            }
> +            else
> +            {
> +                rc = - EPERM;
> +            }
> +            break;
> +
> +        default:
> +            rc = -EINVAL;
> +            break;
> +        }
> +
> +        return rc;
> +    }
>      default:
>      {
>          int rc;
> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index e6cf211..c6ff458 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -36,6 +36,7 @@
>  #include "grant_table.h"
>  #include "hvm/save.h"
>  #include "memory.h"
> +#include "event_channel.h"
>  
>  #define XEN_DOMCTL_INTERFACE_VERSION 0x0000000d
>  
> @@ -1138,6 +1139,15 @@ struct xen_domctl_psr_cat_op {
>      uint32_t target;    /* IN */
>      uint64_t data;      /* IN/OUT */
>  };
> +
> +struct xen_domctl_vuart_op {
> +#define XEN_DOMCTL_VUART_OP_INIT_VPL011  0
> +        uint32_t cmd;           /* XEN_DOMCTL_VUART_OP_* */
> +        uint32_t console_domid; /* IN */
> +        xen_pfn_t gfn;          /* IN */
> +        evtchn_port_t evtchn;   /* OUT */
> +};
> +
>  typedef struct xen_domctl_psr_cat_op xen_domctl_psr_cat_op_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cat_op_t);
>  
> @@ -1218,6 +1228,7 @@ struct xen_domctl {
>  #define XEN_DOMCTL_monitor_op                    77
>  #define XEN_DOMCTL_psr_cat_op                    78
>  #define XEN_DOMCTL_soft_reset                    79
> +#define XEN_DOMCTL_vuart_op                      80
>  #define XEN_DOMCTL_gdbsx_guestmemio            1000
>  #define XEN_DOMCTL_gdbsx_pausevcpu             1001
>  #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
> @@ -1280,6 +1291,7 @@ struct xen_domctl {
>          struct xen_domctl_psr_cmt_op        psr_cmt_op;
>          struct xen_domctl_monitor_op        monitor_op;
>          struct xen_domctl_psr_cat_op        psr_cat_op;
> +        struct xen_domctl_vuart_op          vuart_op;
>          uint8_t                             pad[128];
>      } u;
>  };
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 07/14 v4] xen/arm: vpl011: Add a new vuart node in the xenstore
  2017-06-06 17:25 ` [PATCH 07/14 v4] xen/arm: vpl011: Add a new vuart node in the xenstore Bhupinder Thakur
@ 2017-06-06 23:38   ` Stefano Stabellini
  0 siblings, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-06 23:38 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> Add a new vuart console node to xenstore. This node is added at
> 
> /local/domain/$DOMID/vuart/0.
> 
> The node contains information such as the ring-ref, event channel,
> buffer limit and type of console.
> 
> Xenconsole reads the node information to setup the ring buffer and
> event channel for sending/receiving vuart data.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - Added a backend node for vpl011.
> - Removed libxl__device_vuart_add() for HVM guest. It is called only for PV guest.
> 
>  tools/libxl/libxl_console.c          | 44 ++++++++++++++++++++++++++++++++++++
>  tools/libxl/libxl_create.c           | 12 ++++++++--
>  tools/libxl/libxl_device.c           |  9 ++++++--
>  tools/libxl/libxl_internal.h         |  4 ++++
>  tools/libxl/libxl_types_internal.idl |  1 +
>  5 files changed, 66 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/libxl/libxl_console.c b/tools/libxl/libxl_console.c
> index 853be15..259f865 100644
> --- a/tools/libxl/libxl_console.c
> +++ b/tools/libxl/libxl_console.c
> @@ -344,6 +344,50 @@ out:
>      return rc;
>  }
>  
> +int libxl__device_vuart_add(libxl__gc *gc, uint32_t domid,
> +                            libxl__device_console *console,
> +                            libxl__domain_build_state *state,
> +                            libxl__device *device)
> +{
> +    flexarray_t *ro_front;
> +    flexarray_t *back;
> +    int rc;
> +
> +    ro_front = flexarray_make(gc, 16, 1);
> +    back = flexarray_make(gc, 16, 1);
> +
> +    device->backend_devid = console->devid;
> +    device->backend_domid = console->backend_domid;
> +    device->backend_kind = LIBXL__DEVICE_KIND_VUART;
> +    device->devid = console->devid;
> +    device->domid = domid;
> +    device->kind = LIBXL__DEVICE_KIND_VUART;
> +
> +    flexarray_append(back, "frontend-id");
> +    flexarray_append(back, GCSPRINTF("%d", domid));
> +    flexarray_append(back, "online");
> +    flexarray_append(back, "1");
> +    flexarray_append(back, "state");
> +    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
> +    flexarray_append(back, "protocol");
> +    flexarray_append(back, LIBXL_XENCONSOLE_PROTOCOL);
> +
> +    flexarray_append(ro_front, "port");
> +    flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->vuart_port));
> +    flexarray_append(ro_front, "ring-ref");
> +    flexarray_append(ro_front, GCSPRINTF("%lu", state->vuart_gfn));
> +    flexarray_append(ro_front, "limit");
> +    flexarray_append(ro_front, GCSPRINTF("%d", LIBXL_XENCONSOLE_LIMIT));
> +    flexarray_append(ro_front, "type");
> +    flexarray_append(ro_front, "xenconsoled");
> +
> +    rc = libxl__device_generic_add(gc, XBT_NULL, device,
> +                                   libxl__xs_kvs_of_flexarray(gc, back),
> +                                   NULL,
> +                                   libxl__xs_kvs_of_flexarray(gc, ro_front));
> +    return rc;
> +}
> +
>  int libxl__init_console_from_channel(libxl__gc *gc,
>                                       libxl__device_console *console,
>                                       int dev_num,
> diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
> index bffbc45..091a661 100644
> --- a/tools/libxl/libxl_create.c
> +++ b/tools/libxl/libxl_create.c
> @@ -1367,14 +1367,22 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *multidev,
>      }
>      case LIBXL_DOMAIN_TYPE_PV:
>      {
> -        libxl__device_console console;
> -        libxl__device device;
> +        libxl__device_console console, vuart;
> +        libxl__device device, vuart_device;
>  
>          for (i = 0; i < d_config->num_vfbs; i++) {
>              libxl__device_vfb_add(gc, domid, &d_config->vfbs[i]);
>              libxl__device_vkb_add(gc, domid, &d_config->vkbs[i]);
>          }
>  
> +        if (d_config->b_info.arch_arm.vuart)
> +        {
> +            init_console_info(gc, &vuart, 0);
> +            vuart.backend_domid = state->console_domid;
> +            libxl__device_vuart_add(gc, domid, &vuart, state, &vuart_device);
> +            libxl__device_console_dispose(&vuart);

We are not using vuart_device anywhere but in libxl__device_vuart_add,
right? If so, it could a local variable in libxl__device_vuart_add.


> +        }
> +
>          init_console_info(gc, &console, 0);
>          console.backend_domid = state->console_domid;
>          libxl__device_console_add(gc, domid, &console, state, &device);
> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
> index 5e96676..b110041 100644
> --- a/tools/libxl/libxl_device.c
> +++ b/tools/libxl/libxl_device.c
> @@ -26,6 +26,9 @@ static char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
>      if (device->kind == LIBXL__DEVICE_KIND_CONSOLE && device->devid == 0)
>          return GCSPRINTF("%s/console", dom_path);
>  
> +    if (device->kind == LIBXL__DEVICE_KIND_VUART)
> +        return GCSPRINTF("%s/vuart/%d", dom_path, device->devid);
> +
>      return GCSPRINTF("%s/device/%s/%d", dom_path,
>                       libxl__device_kind_to_string(device->kind),
>                       device->devid);
> @@ -170,7 +173,8 @@ retry_transaction:
>           * historically contained other information, such as the
>           * vnc-port, which we don't want the guest fiddling with.
>           */
> -        if (device->kind == LIBXL__DEVICE_KIND_CONSOLE && device->devid == 0)
> +        if ((device->kind == LIBXL__DEVICE_KIND_CONSOLE && device->devid == 0) ||
> +            (device->kind == LIBXL__DEVICE_KIND_VUART))
>              xs_set_permissions(ctx->xsh, t, frontend_path,
>                                 ro_frontend_perms, ARRAY_SIZE(ro_frontend_perms));
>          else
> @@ -800,7 +804,8 @@ void libxl__devices_destroy(libxl__egc *egc, libxl__devices_remove_state *drs)
>                  dev->domid = domid;
>                  dev->kind = kind;
>                  dev->devid = atoi(devs[j]);
> -                if (dev->backend_kind == LIBXL__DEVICE_KIND_CONSOLE) {
> +                if (dev->backend_kind == LIBXL__DEVICE_KIND_CONSOLE ||
> +                    dev->backend_kind == LIBXL__DEVICE_KIND_VUART) {
>                      /* Currently console devices can be destroyed
>                       * synchronously by just removing xenstore entries,
>                       * this is what libxl__device_destroy does.
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index 4e2c247..7a22db0 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -1202,6 +1202,10 @@ _hidden int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
>                                        libxl__device_console *console,
>                                        libxl__domain_build_state *state,
>                                        libxl__device *device);
> +_hidden int libxl__device_vuart_add(libxl__gc *gc, uint32_t domid,
> +                                    libxl__device_console *console,
> +                                    libxl__domain_build_state *state,
> +                                    libxl__device *device);
>  
>  /* Returns 1 if device exists, 0 if not, ERROR_* (<0) on error. */
>  _hidden int libxl__device_exists(libxl__gc *gc, xs_transaction_t t,
> diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl
> index 7dc4d0f..c463c33 100644
> --- a/tools/libxl/libxl_types_internal.idl
> +++ b/tools/libxl/libxl_types_internal.idl
> @@ -26,6 +26,7 @@ libxl__device_kind = Enumeration("device_kind", [
>      (9, "VUSB"),
>      (10, "QUSB"),
>      (11, "9PFS"),
> +    (12, "VUART"),
>      ])
>  
>  libxl__console_backend = Enumeration("console_backend", [
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 12/14 v4] xen/arm: vpl011: Add a new vuart console type to xenconsole client
  2017-06-06 17:25 ` [PATCH 12/14 v4] xen/arm: vpl011: Add a new vuart console type to xenconsole client Bhupinder Thakur
@ 2017-06-06 23:41   ` Stefano Stabellini
  0 siblings, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-06 23:41 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> Add a new console type VUART to connect to guest's emualated vuart
> console.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - The vuart console support is under CONFIG_VUART_CONSOLE option.
> - Since there is a change from last review, I have not included
>   reviewed-by tag from Stefano and acked-by tag from Wei.
> 
>  tools/console/Makefile      |  1 +
>  tools/console/client/main.c | 25 ++++++++++++++++++++++++-
>  2 files changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/console/Makefile b/tools/console/Makefile
> index fcee313..49c02d4 100644
> --- a/tools/console/Makefile
> +++ b/tools/console/Makefile
> @@ -34,6 +34,7 @@ xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c))
>  	$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_xenconsoled) $(APPEND_LDFLAGS)
>  
>  client/main.o: client/_paths.h
> +client/main.o: CFLAGS += $(VUART_CFLAGS-y)
>  xenconsole: $(patsubst %.c,%.o,$(wildcard client/*.c))
>  	$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_xenconsole) $(APPEND_LDFLAGS)
>  
> diff --git a/tools/console/client/main.c b/tools/console/client/main.c
> index 977779f..8d31fe9 100644
> --- a/tools/console/client/main.c
> +++ b/tools/console/client/main.c
> @@ -76,7 +76,11 @@ static void usage(const char *program) {
>  	       "\n"
>  	       "  -h, --help       display this help and exit\n"
>  	       "  -n, --num N      use console number N\n"
> +#ifdef CONFIG_VUART_CONSOLE
> +	       "  --type TYPE      console type. must be 'pv', 'serial' or 'vuart'\n"
> +#else
>  	       "  --type TYPE      console type. must be 'pv' or 'serial'\n"
> +#endif
>  	       "  --start-notify-fd N file descriptor used to notify parent\n"
>  	       , program);
>  }
> @@ -264,6 +268,9 @@ typedef enum {
>         CONSOLE_INVAL,
>         CONSOLE_PV,
>         CONSOLE_SERIAL,
> +#ifdef CONFIG_VUART_CONSOLE
> +       CONSOLE_VUART,
> +#endif
>  } console_type;
>  
>  static struct termios stdin_old_attr;
> @@ -343,6 +350,11 @@ int main(int argc, char **argv)
>  	char *end;
>  	console_type type = CONSOLE_INVAL;
>  	bool interactive = 0;
> +#ifdef CONFIG_VUART_CONSOLE
> +	char *console_names = "serial, pv, vuart";
> +#else
> +	char *console_names = "serial, pv";
> +#endif
>  
>  	if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))
>  		interactive = 1;
> @@ -361,9 +373,14 @@ int main(int argc, char **argv)
>  				type = CONSOLE_SERIAL;
>  			else if (!strcmp(optarg, "pv"))
>  				type = CONSOLE_PV;
> +#ifdef CONFIG_VUART_CONSOLE
> +			else if (!strcmp(optarg, "vuart"))
> +				type = CONSOLE_VUART;
> +#endif
>  			else {
>  				fprintf(stderr, "Invalid type argument\n");
> -				fprintf(stderr, "Console types supported are: serial, pv\n");
> +				fprintf(stderr, "Console types supported are: %s\n",
> +                        console_names);

alignment issue


>  				exit(EINVAL);
>  			}
>  			break;
> @@ -436,6 +453,12 @@ int main(int argc, char **argv)
>  		else
>  			snprintf(path, strlen(dom_path) + strlen("/device/console/%d/tty") + 5, "%s/device/console/%d/tty", dom_path, num);
>  	}
> +#ifdef CONFIG_VUART_CONSOLE
> +	if (type == CONSOLE_VUART) {
> +		snprintf(path, strlen(dom_path) + strlen("/vuart/0/tty") + 1,
> +				 "%s/vuart/0/tty", dom_path);
> +	}
> +#endif

I don't think it is worth protecting all this code with
CONFIG_VUART_CONSOLE. It's so small I would compile it always.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 09/14 v4] xen/arm: vpl011: Modify xenconsole functions to take console structure as input
  2017-06-06 17:25 ` [PATCH 09/14 v4] xen/arm: vpl011: Modify xenconsole functions to take console structure as input Bhupinder Thakur
@ 2017-06-07  0:43   ` Stefano Stabellini
  0 siblings, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-07  0:43 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> Xenconsole functions take domain structure as input. These functions shall be
> modified to take console structure as input since these functions typically perform
> console specific operations.
> 
> Also the console specific functions starting with prefix "domain_" shall be modified
> to "console_" to indicate that these are console specific functions.
> 
> This patch is in preparation to support multiple consoles to support vuart console.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - The changes in xenconsole have been split into four patches. This is the second patch.
> 
>  tools/console/daemon/io.c | 82 +++++++++++++++++++++++------------------------
>  1 file changed, 41 insertions(+), 41 deletions(-)
> 
> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> index 0402ddf..c5dd08d 100644
> --- a/tools/console/daemon/io.c
> +++ b/tools/console/daemon/io.c
> @@ -163,10 +163,10 @@ static int write_with_timestamp(int fd, const char *data, size_t sz,
>  	return 0;
>  }
>  
> -static void buffer_append(struct domain *dom)
> +static void buffer_append(struct console *con)
>  {
> -	struct console *con = &dom->console;
>  	struct buffer *buffer = &con->buffer;
> +	struct domain *dom = con->d;
>  	XENCONS_RING_IDX cons, prod, size;
>  	struct xencons_interface *intf = con->interface;
>  
> @@ -296,12 +296,13 @@ static int create_hv_log(void)
>  	return fd;
>  }
>  
> -static int create_domain_log(struct domain *dom)
> +static int create_console_log(struct console *con)
>  {
>  	char logfile[PATH_MAX];
>  	char *namepath, *data, *s;
>  	int fd;
>  	unsigned int len;
> +	struct domain *dom = con->d;
>  
>  	namepath = xs_get_domain_path(xs, dom->domid);
>  	s = realloc(namepath, strlen(namepath) + 6);
> @@ -342,10 +343,8 @@ static int create_domain_log(struct domain *dom)
>  	return fd;
>  }
>  
> -static void domain_close_tty(struct domain *dom)
> +static void console_close_tty(struct console *con)
>  {
> -	struct console *con = &dom->console;
> -
>  	if (con->master_fd != -1) {
>  		close(con->master_fd);
>  		con->master_fd = -1;
> @@ -417,7 +416,7 @@ void cfmakeraw(struct termios *termios_p)
>  }
>  #endif /* __sun__ */
>  
> -static int domain_create_tty(struct domain *dom)
> +static int console_create_tty(struct console *con)
>  {
>  	const char *slave;
>  	char *path;
> @@ -426,7 +425,7 @@ static int domain_create_tty(struct domain *dom)
>  	char *data;
>  	unsigned int len;
>  	struct termios term;
> -	struct console *con = &dom->console;
> +	struct domain *dom = con->d;
>  
>  	assert(con->slave_fd == -1);
>  	assert(con->master_fd == -1);
> @@ -487,7 +486,7 @@ static int domain_create_tty(struct domain *dom)
>  
>  	return 1;
>  out:
> -	domain_close_tty(dom);
> +	console_close_tty(con);
>  	return 0;
>  }
>   
> @@ -526,10 +525,8 @@ static int xs_gather(struct xs_handle *xs, const char *dir, ...)
>  	return ret;
>  }
>  
> -static void domain_unmap_interface(struct domain *dom)
> +static void console_unmap_interface(struct console *con)
>  {
> -	struct console *con = &dom->console;
> -
>  	if (con->interface == NULL)
>  		return;
>  	if (xgt_handle && con->ring_ref == -1)
> @@ -540,11 +537,11 @@ static void domain_unmap_interface(struct domain *dom)
>  	con->ring_ref = -1;
>  }
>   
> -static int domain_create_ring(struct domain *dom)
> +static int console_create_ring(struct console *con)
>  {
>  	int err, remote_port, ring_ref, rc;
>  	char *type, path[PATH_MAX];
> -	struct console *con = &dom->console;
> +	struct domain *dom = con->d;
>  
>  	err = xs_gather(xs, con->conspath,
>  			"ring-ref", "%u", &ring_ref,
> @@ -563,7 +560,7 @@ static int domain_create_ring(struct domain *dom)
>  
>  	/* If using ring_ref and it has changed, remap */
>  	if (ring_ref != con->ring_ref && con->ring_ref != -1)
> -		domain_unmap_interface(dom);
> +		console_unmap_interface(con);
>  
>  	if (!con->interface && xgt_handle) {
>  		/* Prefer using grant table */
> @@ -621,7 +618,7 @@ static int domain_create_ring(struct domain *dom)
>  	con->remote_port = remote_port;
>  
>  	if (con->master_fd == -1) {
> -		if (!domain_create_tty(dom)) {
> +		if (!console_create_tty(con)) {
>  			err = errno;
>  			xenevtchn_close(dom->xce_handle);
>  			dom->xce_handle = NULL;
> @@ -632,7 +629,7 @@ static int domain_create_ring(struct domain *dom)
>  	}
>  
>  	if (log_guest && (con->log_fd == -1))
> -		con->log_fd = create_domain_log(dom);
> +		con->log_fd = create_console_log(con);
>  
>   out:
>  	return err;
> @@ -648,7 +645,7 @@ static bool watch_domain(struct domain *dom, bool watch)
>  	if (watch) {
>  		success = xs_watch(xs, con->conspath, domid_str);
>  		if (success)
> -			domain_create_ring(dom);
> +			console_create_ring(con);
>  		else
>  			xs_unwatch(xs, con->conspath, domid_str);
>  	} else {
> @@ -694,6 +691,7 @@ static struct domain *create_domain(int domid)
>  	con->master_pollfd_idx = -1;
>  	con->slave_fd = -1;
>  	con->log_fd = -1;
> +	con->d = dom;
>  	dom->xce_pollfd_idx = -1;
>  
>  	dom->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD;
> @@ -746,7 +744,7 @@ static void cleanup_domain(struct domain *d)
>  {
>  	struct console *con = &d->console;
>  
> -	domain_close_tty(d);
> +	console_close_tty(con);
>  
>  	if (con->log_fd != -1) {
>  		close(con->log_fd);
> @@ -764,9 +762,11 @@ static void cleanup_domain(struct domain *d)
>  
>  static void shutdown_domain(struct domain *d)
>  {
> +	struct console *con = &d->console;
> +
>  	d->is_dead = true;
>  	watch_domain(d, false);
> -	domain_unmap_interface(d);
> +	console_unmap_interface(con);
>  	if (d->xce_handle != NULL)
>  		xenevtchn_close(d->xce_handle);
>  	d->xce_handle = NULL;
> @@ -797,9 +797,8 @@ static void enum_domains(void)
>  	}
>  }
>  
> -static int ring_free_bytes(struct domain *dom)
> +static int ring_free_bytes(struct console *con)
>  {
> -	struct console *con = &dom->console;
>  	struct xencons_interface *intf = con->interface;
>  	XENCONS_RING_IDX cons, prod, space;
>  
> @@ -814,30 +813,30 @@ static int ring_free_bytes(struct domain *dom)
>  	return (sizeof(intf->in) - space);
>  }
>  
> -static void domain_handle_broken_tty(struct domain *dom, int recreate)
> +static void console_handle_broken_tty(struct console *con, int recreate)
>  {
> -	domain_close_tty(dom);
> +	console_close_tty(con);
>  
>  	if (recreate) {
> -		domain_create_tty(dom);
> +		console_create_tty(con);
>  	} else {
> -		shutdown_domain(dom);
> +		shutdown_domain(con->d);
>  	}
>  }
>  
> -static void handle_tty_read(struct domain *dom)
> +static void handle_tty_read(struct console *con)
>  {
>  	ssize_t len = 0;
>  	char msg[80];
>  	int i;
> -	struct console *con = &dom->console;
>  	struct xencons_interface *intf = con->interface;
> +	struct domain *dom = con->d;
>  	XENCONS_RING_IDX prod;
>  
>  	if (dom->is_dead)
>  		return;
>  
> -	len = ring_free_bytes(dom);
> +	len = ring_free_bytes(con);
>  	if (len == 0)
>  		return;
>  
> @@ -851,7 +850,7 @@ static void handle_tty_read(struct domain *dom)
>  	 * keep the slave open for the duration.
>  	 */
>  	if (len < 0) {
> -		domain_handle_broken_tty(dom, domain_is_valid(dom->domid));
> +		console_handle_broken_tty(con, domain_is_valid(dom->domid));
>  	} else if (domain_is_valid(dom->domid)) {
>  		prod = intf->in_prod;
>  		for (i = 0; i < len; i++) {
> @@ -862,15 +861,15 @@ static void handle_tty_read(struct domain *dom)
>  		intf->in_prod = prod;
>  		xenevtchn_notify(dom->xce_handle, con->local_port);
>  	} else {
> -		domain_close_tty(dom);
> +		console_close_tty(con);
>  		shutdown_domain(dom);
>  	}
>  }
>  
> -static void handle_tty_write(struct domain *dom)
> +static void handle_tty_write(struct console *con)
>  {
>  	ssize_t len;
> -	struct console *con = &dom->console;
> +	struct domain *dom = con->d;
>  
>  	if (dom->is_dead)
>  		return;
> @@ -880,7 +879,7 @@ static void handle_tty_write(struct domain *dom)
>   	if (len < 1) {
>  		dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
>  		      dom->domid, len, errno);
> -		domain_handle_broken_tty(dom, domain_is_valid(dom->domid));
> +		console_handle_broken_tty(con, domain_is_valid(dom->domid));
>  	} else {
>  		buffer_advance(&con->buffer, len);
>  	}
> @@ -889,6 +888,7 @@ static void handle_tty_write(struct domain *dom)
>  static void handle_ring_read(struct domain *dom)
>  {
>  	xenevtchn_port_or_error_t port;
> +	struct console *con = &dom->console;
>  
>  	if (dom->is_dead)
>  		return;
> @@ -898,7 +898,7 @@ static void handle_ring_read(struct domain *dom)
>  
>  	dom->event_count++;
>  
> -	buffer_append(dom);
> +	buffer_append(con);
>  
>  	if (dom->event_count < RATE_LIMIT_ALLOWANCE)
>  		(void)xenevtchn_unmask(dom->xce_handle, port);
> @@ -922,7 +922,7 @@ static void handle_xs(void)
>  		/* We may get watches firing for domains that have recently
>  		   been removed, so dom may be NULL here. */
>  		if (dom && dom->is_dead == false)
> -			domain_create_ring(dom);
> +			console_create_ring(&dom->console);
>  	}
>  
>  	free(vec);
> @@ -972,7 +972,7 @@ static void handle_log_reload(void)
>  
>  			if (con->log_fd != -1)
>  				close(con->log_fd);
> -			con->log_fd = create_domain_log(d);
> +			con->log_fd = create_console_log(con);
>  		}
>  	}
>  
> @@ -1118,7 +1118,7 @@ void handle_io(void)
>  
>  			if (con->master_fd != -1) {
>  				short events = 0;
> -				if (!d->is_dead && ring_free_bytes(d))
> +				if (!d->is_dead && ring_free_bytes(con))
>  					events |= POLLIN;
>  
>  				if (!buffer_empty(&con->buffer))
> @@ -1201,15 +1201,15 @@ void handle_io(void)
>  			if (con->master_fd != -1 && con->master_pollfd_idx != -1) {
>  				if (fds[con->master_pollfd_idx].revents &
>  				    ~(POLLIN|POLLOUT|POLLPRI))
> -					domain_handle_broken_tty(d,
> +					console_handle_broken_tty(con,
>  						   domain_is_valid(d->domid));
>  				else {
>  					if (fds[con->master_pollfd_idx].revents &
>  					    POLLIN)
> -						handle_tty_read(d);
> +						handle_tty_read(con);
>  					if (fds[con->master_pollfd_idx].revents &
>  					    POLLOUT)
> -						handle_tty_write(d);
> +						handle_tty_write(con);
>  				}
>  			}
>  
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles
  2017-06-06 17:25 ` [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles Bhupinder Thakur
@ 2017-06-07  1:03   ` Stefano Stabellini
  2017-06-07  3:51     ` Bhupinder Thakur
  0 siblings, 1 reply; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-07  1:03 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> This patch adds the support for multiple consoles and introduces the iterator
> functions to operate on multiple consoles.
> 
> This patch is in preparation to support a new vuart console.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - The changes in xenconsole have been split into four patches. This is the third patch.
> 
>  tools/console/daemon/io.c | 364 +++++++++++++++++++++++++++++++++-------------
>  1 file changed, 263 insertions(+), 101 deletions(-)
> 
> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> index c5dd08d..db73e10 100644
> --- a/tools/console/daemon/io.c
> +++ b/tools/console/daemon/io.c
> @@ -90,12 +90,15 @@ struct buffer {
>  };
>  
>  struct console {
> +	char *xsname;

How is xsname useful? It doesn't look like it is used anywhere except
init, right?


> +	char *ttyname;
>  	int master_fd;
>  	int master_pollfd_idx;
>  	int slave_fd;
>  	int log_fd;
>  	struct buffer buffer;
> -	char *conspath;
> +	char *xspath;

A simple trick to make patch easier to handle is to separate out changes
like this one: renaming conspath to xspath causes a lot of churn, which
ends up all mixed up with other meaningful changes.


> +	char *log_suffix;
>  	int ring_ref;
>  	xenevtchn_port_or_error_t local_port;
>  	xenevtchn_port_or_error_t remote_port;
> @@ -103,6 +106,23 @@ struct console {
>  	struct domain *d;
>  };
>  
> +struct console_data {
> +	char *xsname;
> +	char *ttyname;
> +	char *log_suffix;
> +};
> +
> +static struct console_data console_data[] = {
> +
> +	{
> +		.xsname = "/console",
> +		.ttyname = "tty",
> +		.log_suffix = "",
> +	},
> +};
> +
> +#define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data))
> +
>  struct domain {
>  	int domid;
>  	bool is_dead;
> @@ -112,11 +132,90 @@ struct domain {
>  	int xce_pollfd_idx;
>  	int event_count;
>  	long long next_period;
> -	struct console console;
> +	struct console console[MAX_CONSOLE];
>  };
>  
> +static void buffer_append(struct console *con, unsigned int data)
>  {
>  	struct buffer *buffer = &con->buffer;
> +	struct xencons_interface *intf = con->interface;
> +	xenevtchn_port_or_error_t rxport = (xenevtchn_port_or_error_t)data;
>  	struct domain *dom = con->d;
>  	XENCONS_RING_IDX cons, prod, size;
> -	struct xencons_interface *intf = con->interface;
> +
> +	/* If incoming data is not for the current console then ignore. */
> +	if (con->local_port != rxport)
> +		return;
>  
>  	cons = intf->out_cons;
>  	prod = intf->out_prod;
> @@ -427,6 +541,9 @@ static int console_create_tty(struct console *con)
>  	struct termios term;
>  	struct domain *dom = con->d;
>  
> +	if (!console_enabled(con))
> +		return 1;

Is this actually useful? It doesn't look like the rest code changed in
regards to console_create_tty.



>  	assert(con->slave_fd == -1);
>  	assert(con->master_fd == -1);
>  
> @@ -594,15 +711,16 @@ static int console_create_ring(struct console *con)
>  
>  	con->local_port = -1;
>  	con->remote_port = -1;
> -	if (dom->xce_handle != NULL)
> -		xenevtchn_close(dom->xce_handle);
>  
> -	/* Opening evtchn independently for each console is a bit
> -	 * wasteful, but that's how the code is structured... */
> -	dom->xce_handle = xenevtchn_open(NULL, 0);
> -	if (dom->xce_handle == NULL) {
> -		err = errno;
> -		goto out;
> +	if (dom->xce_handle == NULL)
> +	{
> +		/* Opening evtchn independently for each console is a bit
> +		 * wasteful, but that's how the code is structured... */
> +		dom->xce_handle = xenevtchn_open(NULL, 0);
> +		if (dom->xce_handle == NULL) {
> +			err = errno;
> +			goto out;
> +		}

I think we need to do this per console actually, see below


>  	}
>   
>  	rc = xenevtchn_bind_interdomain(dom->xce_handle,
> @@ -1092,14 +1282,13 @@ void handle_io(void)
>  			if ((now+5) > d->next_period) {
>  				d->next_period = now + RATE_LIMIT_PERIOD;
>  				if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
> -					(void)xenevtchn_unmask(d->xce_handle, con->local_port);
> +					console_iter_void_arg1(d, console_event_unmask);
>  				}
>  				d->event_count = 0;
>  			}
>  		}
> @@ -1107,28 +1296,15 @@ void handle_io(void)
>  				    d->next_period < next_timeout)
>  					next_timeout = d->next_period;
>  			} else if (d->xce_handle != NULL) {
> -				if (discard_overflowed_data ||
> -				    !con->buffer.max_capacity ||
> -				    con->buffer.size < con->buffer.max_capacity) {
> -					int evtchn_fd = xenevtchn_fd(d->xce_handle);
> -					d->xce_pollfd_idx = set_fds(evtchn_fd,
> -								    POLLIN|POLLPRI);
> +					if (console_iter_bool_arg1(d, buffer_available))
> +					{
> +						int evtchn_fd = xenevtchn_fd(d->xce_handle);
> +						d->xce_pollfd_idx = set_fds(evtchn_fd,
> +													POLLIN|POLLPRI);
> +					}
>  				}

Is there a reason why we have one xce_pollfd_idx, xce_handle,
next_period and event_count per domain, rather than per console?

It is strange to set xce_pollfd_idx if at least one console of the
domain has enough buffer availability. Similarly, it is strange to count
the next_period on a per domain basis, regardless of the number of
consoles. It would be natural to do it at the console level.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole
  2017-06-06 17:25 ` [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole Bhupinder Thakur
@ 2017-06-07  1:08   ` Stefano Stabellini
  2017-06-07 16:44   ` Wei Liu
  1 sibling, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-07  1:08 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> This patch finally adds the support for vuart console.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - The changes in xenconsole have been split into four patches. This is the fourth patch.
> - The vuart console support is added under CONFIG_VUART_CONSOLE option.
> 
>  tools/console/Makefile    |  3 ++-
>  tools/console/daemon/io.c | 26 +++++++++++++++++++++++++-
>  2 files changed, 27 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/console/Makefile b/tools/console/Makefile
> index c8b0300..fcee313 100644
> --- a/tools/console/Makefile
> +++ b/tools/console/Makefile
> @@ -11,6 +11,7 @@ LDLIBS += $(SOCKET_LIBS)
>  
>  LDLIBS_xenconsoled += $(UTIL_LIBS)
>  LDLIBS_xenconsoled += -lrt
> +VUART_CFLAGS-$(CONFIG_VUART_CONSOLE) = -DCONFIG_VUART_CONSOLE
>  
>  BIN      = xenconsoled xenconsole
>  
> @@ -28,7 +29,7 @@ clean:
>  distclean: clean
>  
>  daemon/main.o: daemon/_paths.h
> -daemon/io.o: CFLAGS += $(CFLAGS_libxenevtchn) $(CFLAGS_libxengnttab)
> +daemon/io.o: CFLAGS += $(CFLAGS_libxenevtchn) $(CFLAGS_libxengnttab) $(VUART_CFLAGS-y)
>  xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c))
>  	$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_xenconsoled) $(APPEND_LDFLAGS)
>  
> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> index db73e10..cae2efe 100644
> --- a/tools/console/daemon/io.c
> +++ b/tools/console/daemon/io.c
> @@ -104,12 +104,16 @@ struct console {
>  	xenevtchn_port_or_error_t remote_port;
>  	struct xencons_interface *interface;
>  	struct domain *d;
> +	bool optional;
> +	bool prefer_gnttab;
>  };
>  
>  struct console_data {
>  	char *xsname;
>  	char *ttyname;
>  	char *log_suffix;
> +	bool optional;
> +	bool prefer_gnttab;
>  };
>  
>  static struct console_data console_data[] = {
> @@ -118,7 +122,18 @@ static struct console_data console_data[] = {
>  		.xsname = "/console",
>  		.ttyname = "tty",
>  		.log_suffix = "",
> +		.optional = false,
> +		.prefer_gnttab = true,
>  	},
> +#if defined(CONFIG_VUART_CONSOLE)
> +	{
> +		.xsname = "/vuart/0",
> +		.ttyname = "tty",
> +		.log_suffix = "-vuart0",
> +		.optional = true,
> +		.prefer_gnttab = false,
> +	},
> +#endif
>  };
>  
>  #define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data))
> @@ -665,7 +680,12 @@ static int console_create_ring(struct console *con)
>  			"port", "%i", &remote_port,
>  			NULL);
>  	if (err)
> +	{
> +		/* If the console is optional then do not return an error. */
> +		if (con->optional)
> +			err = 0;
>  		goto out;
> +	}

If the console is optional, this function gets called, but we might find
nothing on xenstore, because the console doesn't actually exist. Thus,
we don't want to return error, but just return. Is that right?

If so, please rephrase this comment:

/* 
 * This is a normal condition for optional consoles: they might not be
 * present on xenstore at all. In that case, just return without error.
 */

The rest looks fine.


>  	snprintf(path, sizeof(path), "%s/type", con->xspath);
>  	type = xs_read(xs, XBT_NULL, path, NULL);
> @@ -679,7 +699,9 @@ static int console_create_ring(struct console *con)
>  	if (ring_ref != con->ring_ref && con->ring_ref != -1)
>  		console_unmap_interface(con);
>  
> -	if (!con->interface && xgt_handle) {
> +	if (!con->interface && 
> +		xgt_handle &&
> +		con->prefer_gnttab) {
>  		/* Prefer using grant table */
>  		con->interface = xengnttab_map_grant_ref(xgt_handle,
>  			dom->domid, GNTTAB_RESERVED_CONSOLE,
> @@ -789,6 +811,8 @@ static int console_init(struct console *con, struct domain *dom, void **data)
>  	con->d = dom;
>  	con->ttyname = (*con_data)->ttyname;
>  	con->log_suffix = (*con_data)->log_suffix;
> +	con->optional = (*con_data)->optional;
> +	con->prefer_gnttab = (*con_data)->prefer_gnttab;
>  	con->xsname = (*con_data)->xsname;
>  	con->xspath = xs_get_domain_path(xs, dom->domid);
>  	s = realloc(con->xspath, strlen(con->xspath) +
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 08/14 v4] xen/arm: vpl011: Modify xenconsole to define and use a new console structure
  2017-06-06 17:25 ` [PATCH 08/14 v4] xen/arm: vpl011: Modify xenconsole to define and use a new console structure Bhupinder Thakur
@ 2017-06-07  1:13   ` Stefano Stabellini
  0 siblings, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-07  1:13 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> Xenconsole uses a domain structure which contains console specific fields. This
> patch defines a new console structure, which would be used by the xenconsole
> functions to perform console specific operations like reading/writing data from/to
> the console ring buffer or reading/writing data from/to console tty.
> 
> This patch is in preparation to support multiple consoles to support vuart console.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - The changes in xenconsole have been split into four patches. This is the first patch
>   which modifies the xenconsole to use a new console structure.
> 
> Changes since v2:
> - Defined a new function console_create_ring() which sets up the ring buffer and 
>   event channel a new console. domain_create_ring() uses this function to setup
>   a console.
> - This patch does not contain vuart specific changes, which would be introduced in
>   the next patch.
> - Changes for keeping the PV log file name unchanged.
> 
> Changes since v1:
> - Split the domain struture to a separate console structure
> - Modified the functions to operate on the console struture
> - Replaced repetitive per console code with generic code
> 
>  tools/console/daemon/io.c | 226 ++++++++++++++++++++++++++--------------------
>  1 file changed, 127 insertions(+), 99 deletions(-)
> 
> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> index 947f13a..0402ddf 100644
> --- a/tools/console/daemon/io.c
> +++ b/tools/console/daemon/io.c
> @@ -89,25 +89,30 @@ struct buffer {
>  	size_t max_capacity;
>  };
>  
> -struct domain {
> -	int domid;
> +struct console {
>  	int master_fd;
>  	int master_pollfd_idx;
>  	int slave_fd;
>  	int log_fd;
> -	bool is_dead;
> -	unsigned last_seen;
>  	struct buffer buffer;
> -	struct domain *next;
>  	char *conspath;
>  	int ring_ref;
>  	xenevtchn_port_or_error_t local_port;
>  	xenevtchn_port_or_error_t remote_port;
> +	struct xencons_interface *interface;
> +	struct domain *d;
> +};
> +
> +struct domain {
> +	int domid;
> +	bool is_dead;
> +	unsigned last_seen;
> +	struct domain *next;
>  	xenevtchn_handle *xce_handle;
>  	int xce_pollfd_idx;
> -	struct xencons_interface *interface;
>  	int event_count;
>  	long long next_period;
> +	struct console console;
>  };

All the mechanical substitutions below look good. It remains to discuss
whether we should keep xce_handle, xce_pollfd_idx, event_count and
next_period in struct domain, see my comments on the other patches.

It is strange to count the number of events and the next_period on a
domain basis, when actually all the action is done at a console level.



>  static struct domain *dom_head;
> @@ -160,9 +165,10 @@ static int write_with_timestamp(int fd, const char *data, size_t sz,
>  
>  static void buffer_append(struct domain *dom)
>  {
> -	struct buffer *buffer = &dom->buffer;
> +	struct console *con = &dom->console;
> +	struct buffer *buffer = &con->buffer;
>  	XENCONS_RING_IDX cons, prod, size;
> -	struct xencons_interface *intf = dom->interface;
> +	struct xencons_interface *intf = con->interface;
>  
>  	cons = intf->out_cons;
>  	prod = intf->out_prod;
> @@ -187,22 +193,22 @@ static void buffer_append(struct domain *dom)
>  
>  	xen_mb();
>  	intf->out_cons = cons;
> -	xenevtchn_notify(dom->xce_handle, dom->local_port);
> +	xenevtchn_notify(dom->xce_handle, con->local_port);
>  
>  	/* Get the data to the logfile as early as possible because if
>  	 * no one is listening on the console pty then it will fill up
>  	 * and handle_tty_write will stop being called.
>  	 */
> -	if (dom->log_fd != -1) {
> +	if (con->log_fd != -1) {
>  		int logret;
>  		if (log_time_guest) {
>  			logret = write_with_timestamp(
> -				dom->log_fd,
> +				con->log_fd,
>  				buffer->data + buffer->size - size,
>  				size, &log_time_guest_needts);
>  		} else {
>  			logret = write_all(
> -				dom->log_fd,
> +				con->log_fd,
>  				buffer->data + buffer->size - size,
>  				size);
>  		}
> @@ -338,14 +344,16 @@ static int create_domain_log(struct domain *dom)
>  
>  static void domain_close_tty(struct domain *dom)
>  {
> -	if (dom->master_fd != -1) {
> -		close(dom->master_fd);
> -		dom->master_fd = -1;
> +	struct console *con = &dom->console;
> +
> +	if (con->master_fd != -1) {
> +		close(con->master_fd);
> +		con->master_fd = -1;
>  	}
>  
> -	if (dom->slave_fd != -1) {
> -		close(dom->slave_fd);
> -		dom->slave_fd = -1;
> +	if (con->slave_fd != -1) {
> +		close(con->slave_fd);
> +		con->slave_fd = -1;
>  	}
>  }
>  
> @@ -418,11 +426,12 @@ static int domain_create_tty(struct domain *dom)
>  	char *data;
>  	unsigned int len;
>  	struct termios term;
> +	struct console *con = &dom->console;
>  
> -	assert(dom->slave_fd == -1);
> -	assert(dom->master_fd == -1);
> +	assert(con->slave_fd == -1);
> +	assert(con->master_fd == -1);
>  
> -	if (openpty(&dom->master_fd, &dom->slave_fd, NULL, NULL, NULL) < 0) {
> +	if (openpty(&con->master_fd, &con->slave_fd, NULL, NULL, NULL) < 0) {
>  		err = errno;
>  		dolog(LOG_ERR, "Failed to create tty for domain-%d "
>  		      "(errno = %i, %s)",
> @@ -430,7 +439,7 @@ static int domain_create_tty(struct domain *dom)
>  		return 0;
>  	}
>  
> -	if (tcgetattr(dom->slave_fd, &term) < 0) {
> +	if (tcgetattr(con->slave_fd, &term) < 0) {
>  		err = errno;
>  		dolog(LOG_ERR, "Failed to get tty attributes for domain-%d "
>  			"(errno = %i, %s)",
> @@ -438,7 +447,7 @@ static int domain_create_tty(struct domain *dom)
>  		goto out;
>  	}
>  	cfmakeraw(&term);
> -	if (tcsetattr(dom->slave_fd, TCSANOW, &term) < 0) {
> +	if (tcsetattr(con->slave_fd, TCSANOW, &term) < 0) {
>  		err = errno;
>  		dolog(LOG_ERR, "Failed to set tty attributes for domain-%d "
>  			"(errno = %i, %s)",
> @@ -446,7 +455,7 @@ static int domain_create_tty(struct domain *dom)
>  		goto out;
>  	}
>  
> -	if ((slave = ptsname(dom->master_fd)) == NULL) {
> +	if ((slave = ptsname(con->master_fd)) == NULL) {
>  		err = errno;
>  		dolog(LOG_ERR, "Failed to get slave name for domain-%d "
>  		      "(errno = %i, %s)",
> @@ -454,18 +463,18 @@ static int domain_create_tty(struct domain *dom)
>  		goto out;
>  	}
>  
> -	success = asprintf(&path, "%s/limit", dom->conspath) !=
> +	success = asprintf(&path, "%s/limit", con->conspath) !=
>  		-1;
>  	if (!success)
>  		goto out;
>  	data = xs_read(xs, XBT_NULL, path, &len);
>  	if (data) {
> -		dom->buffer.max_capacity = strtoul(data, 0, 0);
> +		con->buffer.max_capacity = strtoul(data, 0, 0);
>  		free(data);
>  	}
>  	free(path);
>  
> -	success = (asprintf(&path, "%s/tty", dom->conspath) != -1);
> +	success = (asprintf(&path, "%s/tty", con->conspath) != -1);
>  	if (!success)
>  		goto out;
>  	success = xs_write(xs, XBT_NULL, path, slave, strlen(slave));
> @@ -473,7 +482,7 @@ static int domain_create_tty(struct domain *dom)
>  	if (!success)
>  		goto out;
>  
> -	if (fcntl(dom->master_fd, F_SETFL, O_NONBLOCK) == -1)
> +	if (fcntl(con->master_fd, F_SETFL, O_NONBLOCK) == -1)
>  		goto out;
>  
>  	return 1;
> @@ -519,29 +528,32 @@ static int xs_gather(struct xs_handle *xs, const char *dir, ...)
>  
>  static void domain_unmap_interface(struct domain *dom)
>  {
> -	if (dom->interface == NULL)
> +	struct console *con = &dom->console;
> +
> +	if (con->interface == NULL)
>  		return;
> -	if (xgt_handle && dom->ring_ref == -1)
> -		xengnttab_unmap(xgt_handle, dom->interface, 1);
> +	if (xgt_handle && con->ring_ref == -1)
> +		xengnttab_unmap(xgt_handle, con->interface, 1);
>  	else
> -		munmap(dom->interface, XC_PAGE_SIZE);
> -	dom->interface = NULL;
> -	dom->ring_ref = -1;
> +		munmap(con->interface, XC_PAGE_SIZE);
> +	con->interface = NULL;
> +	con->ring_ref = -1;
>  }
>   
>  static int domain_create_ring(struct domain *dom)
>  {
>  	int err, remote_port, ring_ref, rc;
>  	char *type, path[PATH_MAX];
> +	struct console *con = &dom->console;
>  
> -	err = xs_gather(xs, dom->conspath,
> +	err = xs_gather(xs, con->conspath,
>  			"ring-ref", "%u", &ring_ref,
>  			"port", "%i", &remote_port,
>  			NULL);
>  	if (err)
>  		goto out;
>  
> -	snprintf(path, sizeof(path), "%s/type", dom->conspath);
> +	snprintf(path, sizeof(path), "%s/type", con->conspath);
>  	type = xs_read(xs, XBT_NULL, path, NULL);
>  	if (type && strcmp(type, "xenconsoled") != 0) {
>  		free(type);
> @@ -550,41 +562,41 @@ static int domain_create_ring(struct domain *dom)
>  	free(type);
>  
>  	/* If using ring_ref and it has changed, remap */
> -	if (ring_ref != dom->ring_ref && dom->ring_ref != -1)
> +	if (ring_ref != con->ring_ref && con->ring_ref != -1)
>  		domain_unmap_interface(dom);
>  
> -	if (!dom->interface && xgt_handle) {
> +	if (!con->interface && xgt_handle) {
>  		/* Prefer using grant table */
> -		dom->interface = xengnttab_map_grant_ref(xgt_handle,
> +		con->interface = xengnttab_map_grant_ref(xgt_handle,
>  			dom->domid, GNTTAB_RESERVED_CONSOLE,
>  			PROT_READ|PROT_WRITE);
> -		dom->ring_ref = -1;
> +		con->ring_ref = -1;
>  	}
> -	if (!dom->interface) {
> +	if (!con->interface) {
>  		/* Fall back to xc_map_foreign_range */
> -		dom->interface = xc_map_foreign_range(
> +		con->interface = xc_map_foreign_range(
>  			xc, dom->domid, XC_PAGE_SIZE,
>  			PROT_READ|PROT_WRITE,
>  			(unsigned long)ring_ref);
> -		if (dom->interface == NULL) {
> +		if (con->interface == NULL) {
>  			err = EINVAL;
>  			goto out;
>  		}
> -		dom->ring_ref = ring_ref;
> +		con->ring_ref = ring_ref;
>  	}
>  
>  	/* Go no further if port has not changed and we are still bound. */
> -	if (remote_port == dom->remote_port) {
> +	if (remote_port == con->remote_port) {
>  		xc_evtchn_status_t status = {
>  			.dom = DOMID_SELF,
> -			.port = dom->local_port };
> +			.port = con->local_port };
>  		if ((xc_evtchn_status(xc, &status) == 0) &&
>  		    (status.status == EVTCHNSTAT_interdomain))
>  			goto out;
>  	}
>  
> -	dom->local_port = -1;
> -	dom->remote_port = -1;
> +	con->local_port = -1;
> +	con->remote_port = -1;
>  	if (dom->xce_handle != NULL)
>  		xenevtchn_close(dom->xce_handle);
>  
> @@ -605,22 +617,22 @@ static int domain_create_ring(struct domain *dom)
>  		dom->xce_handle = NULL;
>  		goto out;
>  	}
> -	dom->local_port = rc;
> -	dom->remote_port = remote_port;
> +	con->local_port = rc;
> +	con->remote_port = remote_port;
>  
> -	if (dom->master_fd == -1) {
> +	if (con->master_fd == -1) {
>  		if (!domain_create_tty(dom)) {
>  			err = errno;
>  			xenevtchn_close(dom->xce_handle);
>  			dom->xce_handle = NULL;
> -			dom->local_port = -1;
> -			dom->remote_port = -1;
> +			con->local_port = -1;
> +			con->remote_port = -1;
>  			goto out;
>  		}
>  	}
>  
> -	if (log_guest && (dom->log_fd == -1))
> -		dom->log_fd = create_domain_log(dom);
> +	if (log_guest && (con->log_fd == -1))
> +		con->log_fd = create_domain_log(dom);
>  
>   out:
>  	return err;
> @@ -630,16 +642,17 @@ static bool watch_domain(struct domain *dom, bool watch)
>  {
>  	char domid_str[3 + MAX_STRLEN(dom->domid)];
>  	bool success;
> +	struct console *con = &dom->console;
>  
>  	snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid);
>  	if (watch) {
> -		success = xs_watch(xs, dom->conspath, domid_str);
> +		success = xs_watch(xs, con->conspath, domid_str);
>  		if (success)
>  			domain_create_ring(dom);
>  		else
> -			xs_unwatch(xs, dom->conspath, domid_str);
> +			xs_unwatch(xs, con->conspath, domid_str);
>  	} else {
> -		success = xs_unwatch(xs, dom->conspath, domid_str);
> +		success = xs_unwatch(xs, con->conspath, domid_str);
>  	}
>  
>  	return success;
> @@ -651,6 +664,7 @@ static struct domain *create_domain(int domid)
>  	struct domain *dom;
>  	char *s;
>  	struct timespec ts;
> +	struct console *con;
>  
>  	if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
>  		dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d",
> @@ -667,25 +681,26 @@ static struct domain *create_domain(int domid)
>  
>  	dom->domid = domid;
>  
> -	dom->conspath = xs_get_domain_path(xs, dom->domid);
> -	s = realloc(dom->conspath, strlen(dom->conspath) +
> +	con = &dom->console;
> +	con->conspath = xs_get_domain_path(xs, dom->domid);
> +	s = realloc(con->conspath, strlen(con->conspath) +
>  		    strlen("/console") + 1);
>  	if (s == NULL)
>  		goto out;
> -	dom->conspath = s;
> -	strcat(dom->conspath, "/console");
> +	con->conspath = s;
> +	strcat(con->conspath, "/console");
>  
> -	dom->master_fd = -1;
> -	dom->master_pollfd_idx = -1;
> -	dom->slave_fd = -1;
> -	dom->log_fd = -1;
> +	con->master_fd = -1;
> +	con->master_pollfd_idx = -1;
> +	con->slave_fd = -1;
> +	con->log_fd = -1;
>  	dom->xce_pollfd_idx = -1;
>  
>  	dom->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD;
>  
> -	dom->ring_ref = -1;
> -	dom->local_port = -1;
> -	dom->remote_port = -1;
> +	con->ring_ref = -1;
> +	con->local_port = -1;
> +	con->remote_port = -1;
>  
>  	if (!watch_domain(dom, true))
>  		goto out;
> @@ -697,7 +712,7 @@ static struct domain *create_domain(int domid)
>  
>  	return dom;
>   out:
> -	free(dom->conspath);
> +	free(con->conspath);
>  	free(dom);
>  	return NULL;
>  }
> @@ -729,18 +744,20 @@ static void remove_domain(struct domain *dom)
>  
>  static void cleanup_domain(struct domain *d)
>  {
> +	struct console *con = &d->console;
> +
>  	domain_close_tty(d);
>  
> -	if (d->log_fd != -1) {
> -		close(d->log_fd);
> -		d->log_fd = -1;
> +	if (con->log_fd != -1) {
> +		close(con->log_fd);
> +		con->log_fd = -1;
>  	}
>  
> -	free(d->buffer.data);
> -	d->buffer.data = NULL;
> +	free(con->buffer.data);
> +	con->buffer.data = NULL;
>  
> -	free(d->conspath);
> -	d->conspath = NULL;
> +	free(con->conspath);
> +	con->conspath = NULL;
>  
>  	remove_domain(d);
>  }
> @@ -782,7 +799,8 @@ static void enum_domains(void)
>  
>  static int ring_free_bytes(struct domain *dom)
>  {
> -	struct xencons_interface *intf = dom->interface;
> +	struct console *con = &dom->console;
> +	struct xencons_interface *intf = con->interface;
>  	XENCONS_RING_IDX cons, prod, space;
>  
>  	cons = intf->in_cons;
> @@ -812,7 +830,8 @@ static void handle_tty_read(struct domain *dom)
>  	ssize_t len = 0;
>  	char msg[80];
>  	int i;
> -	struct xencons_interface *intf = dom->interface;
> +	struct console *con = &dom->console;
> +	struct xencons_interface *intf = con->interface;
>  	XENCONS_RING_IDX prod;
>  
>  	if (dom->is_dead)
> @@ -825,7 +844,7 @@ static void handle_tty_read(struct domain *dom)
>  	if (len > sizeof(msg))
>  		len = sizeof(msg);
>  
> -	len = read(dom->master_fd, msg, len);
> +	len = read(con->master_fd, msg, len);
>  	/*
>  	 * Note: on Solaris, len == 0 means the slave closed, and this
>  	 * is no problem, but Linux can't handle this usefully, so we
> @@ -841,7 +860,7 @@ static void handle_tty_read(struct domain *dom)
>  		}
>  		xen_wmb();
>  		intf->in_prod = prod;
> -		xenevtchn_notify(dom->xce_handle, dom->local_port);
> +		xenevtchn_notify(dom->xce_handle, con->local_port);
>  	} else {
>  		domain_close_tty(dom);
>  		shutdown_domain(dom);
> @@ -851,18 +870,19 @@ static void handle_tty_read(struct domain *dom)
>  static void handle_tty_write(struct domain *dom)
>  {
>  	ssize_t len;
> +	struct console *con = &dom->console;
>  
>  	if (dom->is_dead)
>  		return;
>  
> -	len = write(dom->master_fd, dom->buffer.data + dom->buffer.consumed,
> -		    dom->buffer.size - dom->buffer.consumed);
> +	len = write(con->master_fd, con->buffer.data + con->buffer.consumed,
> +		    con->buffer.size - con->buffer.consumed);
>   	if (len < 1) {
>  		dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
>  		      dom->domid, len, errno);
>  		domain_handle_broken_tty(dom, domain_is_valid(dom->domid));
>  	} else {
> -		buffer_advance(&dom->buffer, len);
> +		buffer_advance(&con->buffer, len);
>  	}
>  }
>  
> @@ -948,9 +968,11 @@ static void handle_log_reload(void)
>  	if (log_guest) {
>  		struct domain *d;
>  		for (d = dom_head; d; d = d->next) {
> -			if (d->log_fd != -1)
> -				close(d->log_fd);
> -			d->log_fd = create_domain_log(d);
> +			struct console *con = &d->console;
> +
> +			if (con->log_fd != -1)
> +				close(con->log_fd);
> +			con->log_fd = create_domain_log(d);
>  		}
>  	}
>  
> @@ -1059,6 +1081,8 @@ void handle_io(void)
>  		/* Re-calculate any event counter allowances & unblock
>  		   domains with new allowance */
>  		for (d = dom_head; d; d = d->next) {
> +			struct console *con = &d->console;
> +
>  			/* CS 16257:955ee4fa1345 introduces a 5ms fuzz
>  			 * for select(), it is not clear poll() has
>  			 * similar behavior (returning a couple of ms
> @@ -1068,13 +1092,15 @@ void handle_io(void)
>  			if ((now+5) > d->next_period) {
>  				d->next_period = now + RATE_LIMIT_PERIOD;
>  				if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
> -					(void)xenevtchn_unmask(d->xce_handle, d->local_port);
> +					(void)xenevtchn_unmask(d->xce_handle, con->local_port);
>  				}
>  				d->event_count = 0;
>  			}
>  		}
>  
>  		for (d = dom_head; d; d = d->next) {
> +			struct console *con = &d->console;
> +
>  			if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
>  				/* Determine if we're going to be the next time slice to expire */
>  				if (!next_timeout ||
> @@ -1082,25 +1108,25 @@ void handle_io(void)
>  					next_timeout = d->next_period;
>  			} else if (d->xce_handle != NULL) {
>  				if (discard_overflowed_data ||
> -				    !d->buffer.max_capacity ||
> -				    d->buffer.size < d->buffer.max_capacity) {
> +				    !con->buffer.max_capacity ||
> +				    con->buffer.size < con->buffer.max_capacity) {
>  					int evtchn_fd = xenevtchn_fd(d->xce_handle);
>  					d->xce_pollfd_idx = set_fds(evtchn_fd,
>  								    POLLIN|POLLPRI);
>  				}
>  			}
>  
> -			if (d->master_fd != -1) {
> +			if (con->master_fd != -1) {
>  				short events = 0;
>  				if (!d->is_dead && ring_free_bytes(d))
>  					events |= POLLIN;
>  
> -				if (!buffer_empty(&d->buffer))
> +				if (!buffer_empty(&con->buffer))
>  					events |= POLLOUT;
>  
>  				if (events)
> -					d->master_pollfd_idx =
> -						set_fds(d->master_fd,
> +					con->master_pollfd_idx =
> +						set_fds(con->master_fd,
>  							events|POLLPRI);
>  			}
>  		}
> @@ -1159,6 +1185,8 @@ void handle_io(void)
>  		}
>  
>  		for (d = dom_head; d; d = n) {
> +			struct console *con = &d->console;
> +
>  			n = d->next;
>  			if (d->event_count < RATE_LIMIT_ALLOWANCE) {
>  				if (d->xce_handle != NULL &&
> @@ -1170,22 +1198,22 @@ void handle_io(void)
>  				    handle_ring_read(d);
>  			}
>  
> -			if (d->master_fd != -1 && d->master_pollfd_idx != -1) {
> -				if (fds[d->master_pollfd_idx].revents &
> +			if (con->master_fd != -1 && con->master_pollfd_idx != -1) {
> +				if (fds[con->master_pollfd_idx].revents &
>  				    ~(POLLIN|POLLOUT|POLLPRI))
>  					domain_handle_broken_tty(d,
>  						   domain_is_valid(d->domid));
>  				else {
> -					if (fds[d->master_pollfd_idx].revents &
> +					if (fds[con->master_pollfd_idx].revents &
>  					    POLLIN)
>  						handle_tty_read(d);
> -					if (fds[d->master_pollfd_idx].revents &
> +					if (fds[con->master_pollfd_idx].revents &
>  					    POLLOUT)
>  						handle_tty_write(d);
>  				}
>  			}
>  
> -			d->xce_pollfd_idx = d->master_pollfd_idx = -1;
> +			d->xce_pollfd_idx = con->master_pollfd_idx = -1;
>  
>  			if (d->last_seen != enum_pass)
>  				shutdown_domain(d);
> -- 
> 2.7.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles
  2017-06-07  1:03   ` Stefano Stabellini
@ 2017-06-07  3:51     ` Bhupinder Thakur
  2017-06-07 16:46       ` Wei Liu
  2017-06-07 17:54       ` Stefano Stabellini
  0 siblings, 2 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-07  3:51 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall, Ian Jackson, Wei Liu

Hi Stefano,

Thanks for your comments.

>> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
>> index c5dd08d..db73e10 100644
>> --- a/tools/console/daemon/io.c
>> +++ b/tools/console/daemon/io.c
>> @@ -90,12 +90,15 @@ struct buffer {
>>  };
>>
>>  struct console {
>> +     char *xsname;
>
> How is xsname useful? It doesn't look like it is used anywhere except
> init, right?
Yes. I will remove it from the console structure.

>
>
>> +     char *ttyname;
>>       int master_fd;
>>       int master_pollfd_idx;
>>       int slave_fd;
>>       int log_fd;
>>       struct buffer buffer;
>> -     char *conspath;
>> +     char *xspath;
>
> A simple trick to make patch easier to handle is to separate out changes
> like this one: renaming conspath to xspath causes a lot of churn, which
> ends up all mixed up with other meaningful changes.
>
I thought that xspath is a more appropriate name than conspath because
it tells that it is related to
xenstore. I could keep it unchanged. Let me know. Else I will
introduce this in a separate patch.

>
>> +     char *log_suffix;
>>       int ring_ref;
>>       xenevtchn_port_or_error_t local_port;
>>       xenevtchn_port_or_error_t remote_port;
>> @@ -103,6 +106,23 @@ struct console {
>>       struct domain *d;
>>  };
>>
>> +struct console_data {
>> +     char *xsname;
>> +     char *ttyname;
>> +     char *log_suffix;
>> +};
>> +
>> +static struct console_data console_data[] = {
>> +
>> +     {
>> +             .xsname = "/console",
>> +             .ttyname = "tty",
>> +             .log_suffix = "",
>> +     },
>> +};
>> +
>> +#define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data))
>> +
>>  struct domain {
>>       int domid;
>>       bool is_dead;
>> @@ -112,11 +132,90 @@ struct domain {
>>       int xce_pollfd_idx;
>>       int event_count;
>>       long long next_period;
>> -     struct console console;
>> +     struct console console[MAX_CONSOLE];
>>  };
>>
>> +static void buffer_append(struct console *con, unsigned int data)
>>  {
>>       struct buffer *buffer = &con->buffer;
>> +     struct xencons_interface *intf = con->interface;
>> +     xenevtchn_port_or_error_t rxport = (xenevtchn_port_or_error_t)data;
>>       struct domain *dom = con->d;
>>       XENCONS_RING_IDX cons, prod, size;
>> -     struct xencons_interface *intf = con->interface;
>> +
>> +     /* If incoming data is not for the current console then ignore. */
>> +     if (con->local_port != rxport)
>> +             return;
>>
>>       cons = intf->out_cons;
>>       prod = intf->out_prod;
>> @@ -427,6 +541,9 @@ static int console_create_tty(struct console *con)
>>       struct termios term;
>>       struct domain *dom = con->d;
>>
>> +     if (!console_enabled(con))
>> +             return 1;
>
> Is this actually useful? It doesn't look like the rest code changed in
> regards to console_create_tty.
I think this check in not required as it would be called only if the
console was initialized.
I will remove the check.
>
>
>
>>       assert(con->slave_fd == -1);
>>       assert(con->master_fd == -1);
>>
>> @@ -594,15 +711,16 @@ static int console_create_ring(struct console *con)
>>
>>       con->local_port = -1;
>>       con->remote_port = -1;
>> -     if (dom->xce_handle != NULL)
>> -             xenevtchn_close(dom->xce_handle);
>>
>> -     /* Opening evtchn independently for each console is a bit
>> -      * wasteful, but that's how the code is structured... */
>> -     dom->xce_handle = xenevtchn_open(NULL, 0);
>> -     if (dom->xce_handle == NULL) {
>> -             err = errno;
>> -             goto out;
>> +     if (dom->xce_handle == NULL)
>> +     {
>> +             /* Opening evtchn independently for each console is a bit
>> +              * wasteful, but that's how the code is structured... */
>> +             dom->xce_handle = xenevtchn_open(NULL, 0);
>> +             if (dom->xce_handle == NULL) {
>> +                     err = errno;
>> +                     goto out;
>> +             }
>
> I think we need to do this per console actually, see below
>
>
>>       }
>>
>>       rc = xenevtchn_bind_interdomain(dom->xce_handle,
>> @@ -1092,14 +1282,13 @@ void handle_io(void)
>>                       if ((now+5) > d->next_period) {
>>                               d->next_period = now + RATE_LIMIT_PERIOD;
>>                               if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
>> -                                     (void)xenevtchn_unmask(d->xce_handle, con->local_port);
>> +                                     console_iter_void_arg1(d, console_event_unmask);
>>                               }
>>                               d->event_count = 0;
>>                       }
>>               }
>> @@ -1107,28 +1296,15 @@ void handle_io(void)
>>                                   d->next_period < next_timeout)
>>                                       next_timeout = d->next_period;
>>                       } else if (d->xce_handle != NULL) {
>> -                             if (discard_overflowed_data ||
>> -                                 !con->buffer.max_capacity ||
>> -                                 con->buffer.size < con->buffer.max_capacity) {
>> -                                     int evtchn_fd = xenevtchn_fd(d->xce_handle);
>> -                                     d->xce_pollfd_idx = set_fds(evtchn_fd,
>> -                                                                 POLLIN|POLLPRI);
>> +                                     if (console_iter_bool_arg1(d, buffer_available))
>> +                                     {
>> +                                             int evtchn_fd = xenevtchn_fd(d->xce_handle);
>> +                                             d->xce_pollfd_idx = set_fds(evtchn_fd,
>> +                                                                                                     POLLIN|POLLPRI);
>> +                                     }
>>                               }
>
> Is there a reason why we have one xce_pollfd_idx, xce_handle,
> next_period and event_count per domain, rather than per console?
>
> It is strange to set xce_pollfd_idx if at least one console of the
> domain has enough buffer availability. Similarly, it is strange to count
> the next_period on a per domain basis, regardless of the number of
> consoles. It would be natural to do it at the console level.

I tried to reuse the same event channel for handling multiple consoles
since an event channel can handle multiple connections by allocating
unique local ports. Considering that there will not be many consoles
active at the same time, I thought it might be ok to reuse the same
event channel.

I agree that it is natural to make this per console. Let me know if I
should make it per console.

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 05/14 v4] xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart
  2017-06-06 17:25 ` [PATCH 05/14 v4] xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart Bhupinder Thakur
  2017-06-06 23:17   ` Stefano Stabellini
@ 2017-06-07 16:43   ` Wei Liu
  1 sibling, 0 replies; 65+ messages in thread
From: Wei Liu @ 2017-06-07 16:43 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, Jun 06, 2017 at 10:55:20PM +0530, Bhupinder Thakur wrote:
> Allocate a new gfn to be used as a ring buffer between xenconsole
> and Xen for sending/receiving pl011 console data.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>

Acked-by: Wei Liu <wei.liu2@citrix.com>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole
  2017-06-06 17:25 ` [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole Bhupinder Thakur
  2017-06-07  1:08   ` Stefano Stabellini
@ 2017-06-07 16:44   ` Wei Liu
  1 sibling, 0 replies; 65+ messages in thread
From: Wei Liu @ 2017-06-07 16:44 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Tue, Jun 06, 2017 at 10:55:26PM +0530, Bhupinder Thakur wrote:
> This patch finally adds the support for vuart console.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> 
> Changes since v3:
> - The changes in xenconsole have been split into four patches. This is the fourth patch.
> - The vuart console support is added under CONFIG_VUART_CONSOLE option.
> 
>  tools/console/Makefile    |  3 ++-
>  tools/console/daemon/io.c | 26 +++++++++++++++++++++++++-
>  2 files changed, 27 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/console/Makefile b/tools/console/Makefile
> index c8b0300..fcee313 100644
> --- a/tools/console/Makefile
> +++ b/tools/console/Makefile
> @@ -11,6 +11,7 @@ LDLIBS += $(SOCKET_LIBS)
>  
>  LDLIBS_xenconsoled += $(UTIL_LIBS)
>  LDLIBS_xenconsoled += -lrt
> +VUART_CFLAGS-$(CONFIG_VUART_CONSOLE) = -DCONFIG_VUART_CONSOLE

This should be named CFLAGS_vuart to follow our convention.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles
  2017-06-07  3:51     ` Bhupinder Thakur
@ 2017-06-07 16:46       ` Wei Liu
  2017-06-07 17:54       ` Stefano Stabellini
  1 sibling, 0 replies; 65+ messages in thread
From: Wei Liu @ 2017-06-07 16:46 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Wed, Jun 07, 2017 at 09:21:13AM +0530, Bhupinder Thakur wrote:
> > Is there a reason why we have one xce_pollfd_idx, xce_handle,
> > next_period and event_count per domain, rather than per console?
> >
> > It is strange to set xce_pollfd_idx if at least one console of the
> > domain has enough buffer availability. Similarly, it is strange to count
> > the next_period on a per domain basis, regardless of the number of
> > consoles. It would be natural to do it at the console level.
> 
> I tried to reuse the same event channel for handling multiple consoles
> since an event channel can handle multiple connections by allocating
> unique local ports. Considering that there will not be many consoles
> active at the same time, I thought it might be ok to reuse the same
> event channel.
> 
> I agree that it is natural to make this per console. Let me know if I
> should make it per console.
> 

I suppose by design there is one event channel per console so per
console event channel in xenconsoled makes more sense to me.

> Regards,
> Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles
  2017-06-07  3:51     ` Bhupinder Thakur
  2017-06-07 16:46       ` Wei Liu
@ 2017-06-07 17:54       ` Stefano Stabellini
  1 sibling, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-07 17:54 UTC (permalink / raw)
  To: Bhupinder Thakur
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson, Wei Liu

On Wed, 7 Jun 2017, Bhupinder Thakur wrote:
> Hi Stefano,
> 
> Thanks for your comments.
> 
> >> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> >> index c5dd08d..db73e10 100644
> >> --- a/tools/console/daemon/io.c
> >> +++ b/tools/console/daemon/io.c
> >> @@ -90,12 +90,15 @@ struct buffer {
> >>  };
> >>
> >>  struct console {
> >> +     char *xsname;
> >
> > How is xsname useful? It doesn't look like it is used anywhere except
> > init, right?
> Yes. I will remove it from the console structure.
> 
> >
> >
> >> +     char *ttyname;
> >>       int master_fd;
> >>       int master_pollfd_idx;
> >>       int slave_fd;
> >>       int log_fd;
> >>       struct buffer buffer;
> >> -     char *conspath;
> >> +     char *xspath;
> >
> > A simple trick to make patch easier to handle is to separate out changes
> > like this one: renaming conspath to xspath causes a lot of churn, which
> > ends up all mixed up with other meaningful changes.
> >
> I thought that xspath is a more appropriate name than conspath because
> it tells that it is related to
> xenstore. I could keep it unchanged. Let me know. Else I will
> introduce this in a separate patch.

Yes, rename it but in a separate patch


> >
> >> +     char *log_suffix;
> >>       int ring_ref;
> >>       xenevtchn_port_or_error_t local_port;
> >>       xenevtchn_port_or_error_t remote_port;
> >> @@ -103,6 +106,23 @@ struct console {
> >>       struct domain *d;
> >>  };
> >>
> >> +struct console_data {
> >> +     char *xsname;
> >> +     char *ttyname;
> >> +     char *log_suffix;
> >> +};
> >> +
> >> +static struct console_data console_data[] = {
> >> +
> >> +     {
> >> +             .xsname = "/console",
> >> +             .ttyname = "tty",
> >> +             .log_suffix = "",
> >> +     },
> >> +};
> >> +
> >> +#define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data))
> >> +
> >>  struct domain {
> >>       int domid;
> >>       bool is_dead;
> >> @@ -112,11 +132,90 @@ struct domain {
> >>       int xce_pollfd_idx;
> >>       int event_count;
> >>       long long next_period;
> >> -     struct console console;
> >> +     struct console console[MAX_CONSOLE];
> >>  };
> >>
> >> +static void buffer_append(struct console *con, unsigned int data)
> >>  {
> >>       struct buffer *buffer = &con->buffer;
> >> +     struct xencons_interface *intf = con->interface;
> >> +     xenevtchn_port_or_error_t rxport = (xenevtchn_port_or_error_t)data;
> >>       struct domain *dom = con->d;
> >>       XENCONS_RING_IDX cons, prod, size;
> >> -     struct xencons_interface *intf = con->interface;
> >> +
> >> +     /* If incoming data is not for the current console then ignore. */
> >> +     if (con->local_port != rxport)
> >> +             return;
> >>
> >>       cons = intf->out_cons;
> >>       prod = intf->out_prod;
> >> @@ -427,6 +541,9 @@ static int console_create_tty(struct console *con)
> >>       struct termios term;
> >>       struct domain *dom = con->d;
> >>
> >> +     if (!console_enabled(con))
> >> +             return 1;
> >
> > Is this actually useful? It doesn't look like the rest code changed in
> > regards to console_create_tty.
> I think this check in not required as it would be called only if the
> console was initialized.
> I will remove the check.

OK


> >
> >
> >
> >>       assert(con->slave_fd == -1);
> >>       assert(con->master_fd == -1);
> >>
> >> @@ -594,15 +711,16 @@ static int console_create_ring(struct console *con)
> >>
> >>       con->local_port = -1;
> >>       con->remote_port = -1;
> >> -     if (dom->xce_handle != NULL)
> >> -             xenevtchn_close(dom->xce_handle);
> >>
> >> -     /* Opening evtchn independently for each console is a bit
> >> -      * wasteful, but that's how the code is structured... */
> >> -     dom->xce_handle = xenevtchn_open(NULL, 0);
> >> -     if (dom->xce_handle == NULL) {
> >> -             err = errno;
> >> -             goto out;
> >> +     if (dom->xce_handle == NULL)
> >> +     {
> >> +             /* Opening evtchn independently for each console is a bit
> >> +              * wasteful, but that's how the code is structured... */
> >> +             dom->xce_handle = xenevtchn_open(NULL, 0);
> >> +             if (dom->xce_handle == NULL) {
> >> +                     err = errno;
> >> +                     goto out;
> >> +             }
> >
> > I think we need to do this per console actually, see below
> >
> >
> >>       }
> >>
> >>       rc = xenevtchn_bind_interdomain(dom->xce_handle,
> >> @@ -1092,14 +1282,13 @@ void handle_io(void)
> >>                       if ((now+5) > d->next_period) {
> >>                               d->next_period = now + RATE_LIMIT_PERIOD;
> >>                               if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
> >> -                                     (void)xenevtchn_unmask(d->xce_handle, con->local_port);
> >> +                                     console_iter_void_arg1(d, console_event_unmask);
> >>                               }
> >>                               d->event_count = 0;
> >>                       }
> >>               }
> >> @@ -1107,28 +1296,15 @@ void handle_io(void)
> >>                                   d->next_period < next_timeout)
> >>                                       next_timeout = d->next_period;
> >>                       } else if (d->xce_handle != NULL) {
> >> -                             if (discard_overflowed_data ||
> >> -                                 !con->buffer.max_capacity ||
> >> -                                 con->buffer.size < con->buffer.max_capacity) {
> >> -                                     int evtchn_fd = xenevtchn_fd(d->xce_handle);
> >> -                                     d->xce_pollfd_idx = set_fds(evtchn_fd,
> >> -                                                                 POLLIN|POLLPRI);
> >> +                                     if (console_iter_bool_arg1(d, buffer_available))
> >> +                                     {
> >> +                                             int evtchn_fd = xenevtchn_fd(d->xce_handle);
> >> +                                             d->xce_pollfd_idx = set_fds(evtchn_fd,
> >> +                                                                                                     POLLIN|POLLPRI);
> >> +                                     }
> >>                               }
> >
> > Is there a reason why we have one xce_pollfd_idx, xce_handle,
> > next_period and event_count per domain, rather than per console?
> >
> > It is strange to set xce_pollfd_idx if at least one console of the
> > domain has enough buffer availability. Similarly, it is strange to count
> > the next_period on a per domain basis, regardless of the number of
> > consoles. It would be natural to do it at the console level.
> 
> I tried to reuse the same event channel for handling multiple consoles
> since an event channel can handle multiple connections by allocating
> unique local ports. Considering that there will not be many consoles
> active at the same time, I thought it might be ok to reuse the same
> event channel.
> 
> I agree that it is natural to make this per console. Let me know if I
> should make it per console.
 
Yes, please.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 01/14 v4] xen/arm: vpl011: Move vgic register access functions to vreg.h
  2017-06-06 17:25 ` [PATCH 01/14 v4] xen/arm: vpl011: Move vgic register access functions to vreg.h Bhupinder Thakur
@ 2017-06-09 12:49   ` Julien Grall
  0 siblings, 0 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-09 12:49 UTC (permalink / raw)
  To: Bhupinder Thakur, xen-devel; +Cc: Stefano Stabellini

Hi Bhupinder,

On 06/06/17 18:25, Bhupinder Thakur wrote:
> These functions are generic in nature and can be reused by other emulation
> code in Xen. One recent example is pl011 emulation, which needs similar
> functions to read/write the registers.
>
> This patch moves the register access function definitions from vgic.h to
> vreg.h.
>
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ss
> CC: jg
>
> Changes since v3:
> - Moved the macro call VGIC_REG_HELPERS to vreg.h from vgic.h.
>
>  xen/include/asm-arm/vgic.h | 111 +--------------------------------------------
>  xen/include/asm-arm/vreg.h | 110 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 111 insertions(+), 110 deletions(-)
>
> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> index 544867a..75c716e 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -20,6 +20,7 @@
>
>  #include <xen/bitops.h>
>  #include <asm/mmio.h>
> +#include <asm-arm/vreg.h>

You should include asm/vreg.h and not asm-arm/vreg.h. With that fixed:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h
  2017-06-06 17:25 ` [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h Bhupinder Thakur
@ 2017-06-09 12:54   ` Julien Grall
  2017-06-19  9:33   ` Andre Przywara
  1 sibling, 0 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-09 12:54 UTC (permalink / raw)
  To: Bhupinder Thakur, xen-devel; +Cc: Stefano Stabellini

Hi Bhupinder,

On 06/06/17 18:25, Bhupinder Thakur wrote:
> -/* N-bit register helpers */
> -#define VGIC_REG_HELPERS(sz, offmask)                                   \
> -static inline register_t vgic_reg##sz##_extract(uint##sz##_t reg,       \
> -                                                const mmio_info_t *info)\

[...]

> +#define VREG_REG_HELPERS(sz, offmask)                                           \
> +/* N-bit register helpers */                                                    \
> +static inline register_t vreg_reg##sz##_extract(uint##sz##_t reg,               \
> +                                                  const mmio_info_t *info)      \

Please don't modify the indentation. There is no reason to do that and 
make the review more difficult to do. This patch should *only* replace 
vgic by vreg.

> @@ -211,10 +211,9 @@ static inline void vgic_reg##sz##_clearbits(uint##sz##_t *reg,          \
>   * unsigned long rather than uint64_t
>   */
>  #if BITS_PER_LONG == 64
> -VGIC_REG_HELPERS(64, 0x7);
> +VREG_REG_HELPERS(64, 0x7);
>  #endif
> -VGIC_REG_HELPERS(32, 0x3);
> -

Why did you drop this line?

> -#undef VGIC_REG_HELPERS
> +VREG_REG_HELPERS(32, 0x3);
> +#undef VREG_REG_HELPERS
>
>  #endif /* __ASM_ARM_VREG__ */
>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-06 23:02   ` Stefano Stabellini
@ 2017-06-09 13:15     ` Julien Grall
  2017-06-09 18:02       ` Stefano Stabellini
  2017-06-13  8:58       ` Bhupinder Thakur
  0 siblings, 2 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-09 13:15 UTC (permalink / raw)
  To: Stefano Stabellini, Bhupinder Thakur; +Cc: xen-devel, Ian Jackson, Wei Liu

Hi,

On 07/06/17 00:02, Stefano Stabellini wrote:
> On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
>> +static uint8_t vpl011_read_data(struct domain *d)
>> +{
>> +    unsigned long flags;
>> +    uint8_t data = 0;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>
> After reading the indexes, we always need barriers. In this case:
>
>   smp_rmb();

Well, there are already barrier with the spinlock. However, I am bit 
concern about reading those index without the lock taken. You can have 
concurrent call to vpl011_read_data happening and therefore the indexes 
may have changed when the lock will be taken.

>
>
>> +    VPL011_LOCK(d, flags);
>> +
>> +    /*
>> +     * 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 )
>> +    {
>> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
>> +        in_cons += 1;
>> +        intf->in_cons = in_cons;
>> +        smp_mb();
>> +    }
>> +    else
>> +    {
>> +        gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer empty\n");
>> +    }
>> +
>> +    if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == 0 )
>> +    {
>> +        vpl011->uartfr |= RXFE;
>> +        vpl011->uartris &= ~RXI;
>> +    }
>> +    vpl011->uartfr &= ~RXFF;
>> +    VPL011_UNLOCK(d, flags);
>
> I am pretty sure that the PV console protocol requires us to notify the
> other end even on reads. We need to add a notify_via_xen_event_channel
> here, I think.

I would agree here. On the previous version, I asked Bhupinder to 
explain why it is necessary and he said: "On second thoughs, 
notification is not required".

>
>
>> +    return data;
>> +}
>> +
>> +static void vpl011_write_data(struct domain *d, uint8_t data)
>> +{
>> +    unsigned long flags;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX out_cons = intf->out_cons;
>> +    XENCONS_RING_IDX out_prod = intf->out_prod;
>
>   smp_mb()

Same remark as above.

[...]

>> +static void vpl011_data_avail(struct domain *d)
>> +{
>> +    unsigned long flags;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>> +    XENCONS_RING_IDX out_cons = intf->out_cons;
>> +    XENCONS_RING_IDX out_prod = intf->out_prod;
>> +    XENCONS_RING_IDX in_ring_qsize, out_ring_qsize;
>
>   smb_mb()

Ditto.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-06 17:25 ` [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen Bhupinder Thakur
  2017-06-06 23:02   ` Stefano Stabellini
@ 2017-06-09 13:54   ` Julien Grall
  2017-06-13 10:57     ` Bhupinder Thakur
  2017-06-19 10:14   ` Andre Przywara
  2 siblings, 1 reply; 65+ messages in thread
From: Julien Grall @ 2017-06-09 13:54 UTC (permalink / raw)
  To: Bhupinder Thakur, xen-devel; +Cc: Wei Liu, Stefano Stabellini, Ian Jackson

Hi Bhupinder,

On 06/06/17 18:25, Bhupinder Thakur wrote:
> Add emulation code to emulate read/write access to pl011 registers
> and pl011 interrupts:
>
>     - Emulate DR read/write by reading and writing from/to the IN
>       and OUT ring buffers and raising an event to the backend when
>       there is data in the OUT ring buffer and injecting an interrupt
>       to the guest when there is data in the IN ring buffer
>
>     - Other registers are related to interrupt management and
>       essentially control when interrupts are delivered to the guest
>
> The SBSA compliant pl011 uart is covered in Appendix B of
> https://static.docs.arm.com/den0029/a/Server_Base_System_Architecture_v3_1_ARM_DEN_0029A.pdf
>
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> CC: kw
>
> Changes since v3:
> - Moved the call to DEFINE_XEN_FLEX_RING from vpl011.h to public/console.h. This macro defines
>   standard functions to operate on the ring buffer.
> - Lock taken while updating the interrupt mask and clear registers in mmio_write.
> - Use gfn_t instead of xen_pfn_t.
> - vgic_free_virq called if there is any error in vpl011 initialization.
> - mmio handlers freed if there is any error in vpl011 initialization.
> - Removed vpl011->initialized flag usage as the same check could be done
>   using vpl011->ring-ref.
> - Used return instead of break in the switch handling of emulation of different pl011 registers.
> - Renamed vpl011_update_spi() to vpl011_update().
>
> Changes since v2:
> - Use generic vreg_reg* for read/write of registers emulating pl011.
> - Use generic ring buffer functions defined using DEFINE_XEN_FLEX_RING.
> - Renamed the SPI injection function to vpl011_update_spi() to reflect level
>   triggered nature of pl011 interrupts.
> - The pl011 register access address should always be the base address of the
>   corresponding register as per section B of the SBSA document. For this reason,
>   the register range address access is not allowed.
>
> Changes since v1:
> - Removed the optimiztion related to sendiing events to xenconsole
> - Use local variables as ring buffer indices while using the ring buffer
>
>  tools/console/daemon/io.c        |   2 +-
>  xen/arch/arm/Kconfig             |   5 +
>  xen/arch/arm/Makefile            |   1 +
>  xen/arch/arm/vpl011.c            | 418 +++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/domain.h     |   6 +
>  xen/include/asm-arm/pl011-uart.h |   2 +
>  xen/include/asm-arm/vpl011.h     |  74 +++++++
>  xen/include/public/arch-arm.h    |   6 +
>  xen/include/public/io/console.h  |   4 +

This would require an ACK from Konrad. The addition would also need to 
be justified in the commit message. Although, you probably want to split 
this change in a separate patch.

>  9 files changed, 517 insertions(+), 1 deletion(-)
>  create mode 100644 xen/arch/arm/vpl011.c
>  create mode 100644 xen/include/asm-arm/vpl011.h
>
> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> index 7e6a886..947f13a 100644
> --- a/tools/console/daemon/io.c
> +++ b/tools/console/daemon/io.c

Can you explain why you change the position of the include in io.c?

> @@ -21,6 +21,7 @@
>
>  #include "utils.h"
>  #include "io.h"
> +#include <string.h>
>  #include <xenevtchn.h>
>  #include <xengnttab.h>
>  #include <xenstore.h>
> @@ -29,7 +30,6 @@
>
>  #include <stdlib.h>
>  #include <errno.h>
> -#include <string.h>
>  #include <poll.h>
>  #include <fcntl.h>
>  #include <unistd.h>


[...]

>  menu "ARM errata workaround via the alternative framework"
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 49e1fb2..15efc13 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -52,6 +52,7 @@ obj-y += vm_event.o
>  obj-y += vtimer.o
>  obj-y += vpsci.o
>  obj-y += vuart.o
> +obj-$(CONFIG_VPL011_CONSOLE) += vpl011.o

Please the alphabetical order. Just noticed vtimer is not correctly 
positioned. I will send a patch for that.

>
>  #obj-bin-y += ....o
>
> diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
> new file mode 100644
> index 0000000..9b1f27e
> --- /dev/null
> +++ b/xen/arch/arm/vpl011.c
> @@ -0,0 +1,418 @@
> +/*
> + * arch/arm/vpl011.c
> + *
> + * Virtual PL011 UART
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <xen/errno.h>
> +#include <xen/event.h>
> +#include <xen/guest_access.h>
> +#include <xen/init.h>
> +#include <xen/lib.h>
> +#include <xen/mm.h>
> +#include <xen/sched.h>
> +#include <public/domctl.h>
> +#include <public/io/console.h>
> +#include <asm-arm/pl011-uart.h>
> +#include <asm-arm/vgic-emul.h>
> +#include <asm-arm/vpl011.h>
> +
> +static bool vpl011_reg32_check_access(struct hsr_dabt dabt)
> +{
> +    return (dabt.size != DABT_DOUBLE_WORD);

Again, please add a comment explaining why we allow all the sizes but 
64-bit.

> +}
> +
> +static void vpl011_update(struct domain *d)
> +{
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    /*
> +     * TODO: PL011 interrupts are level triggered which means
> +     * that interrupt needs to be set/clear instead of being
> +     * injected. However, currently vGIC does not handle level
> +     * triggered interrupts properly. This function needs to be
> +     * revisited once vGIC starts handling level triggered
> +     * interrupts.
> +     */
> +    if ( vpl011->uartris & vpl011->uartimsc )

The write in uartirs and uartimsc are protected by a lock. Shouldn't it 
be the case here too? More that they are not updated atomically.

You probably want to call vpl011_update with vpl011 lock taken to make 
sure you don't have any synchronization issue.

> +        vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI);
> +}
> +
> +static uint8_t vpl011_read_data(struct domain *d)
> +{
> +    unsigned long flags;
> +    uint8_t data = 0;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX in_cons = intf->in_cons;
> +    XENCONS_RING_IDX in_prod = intf->in_prod;

See my answer on Stefano's e-mail regarding the barrier here. 
(<fa3e5003-5c7f-0886-d437-6b643347b4c5@arm.com>)

> +
> +    VPL011_LOCK(d, flags);
> +
> +    /*
> +     * 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 )
> +    {
> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
> +        in_cons += 1;
> +        intf->in_cons = in_cons;
> +        smp_mb();

I don't understand why you moved the barrier from between reading the 
data and intf->in_cons. You have to ensure the character is read before 
updating in_cons.

> +    }
> +    else
> +    {
> +        gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer empty\n");
> +    }

The {} are not necessary.

> +
> +    if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == 0 )

What if the other end of the ring has put more data whilst reading one 
character?

> +    {
> +        vpl011->uartfr |= RXFE;
> +        vpl011->uartris &= ~RXI;
> +    }
> +    vpl011->uartfr &= ~RXFF;
> +    VPL011_UNLOCK(d, flags);
> +
> +    return data;
> +}
> +
> +static void vpl011_write_data(struct domain *d, uint8_t data)
> +{
> +    unsigned long flags;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX out_cons = intf->out_cons;
> +    XENCONS_RING_IDX out_prod = intf->out_prod;

See my remark above.

> +
> +    VPL011_LOCK(d, flags);
> +
> +    /*
> +     * It is expected that the ring is not full when this function is called
> +     * as the guest is expected to write to the data register only when the
> +     * TXFF flag is not set.
> +     * In case the guest does write even when the TXFF flag is set then the
> +     * data will be silently dropped.
> +     */
> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) !=
> +         sizeof (intf->out) )
> +    {
> +        intf->out[xencons_mask(out_prod, sizeof(intf->out))] = data;
> +        smp_wmb();
> +        out_prod += 1;
> +        intf->out_prod = out_prod;
> +    }
> +    else
> +    {
> +        gprintk(XENLOG_ERR, "vpl011: Unexpected OUT ring buffer full\n");
> +    }

The {} are not necessary.

> +
> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) ==
> +         sizeof (intf->out) )

Ditto here.

> +    {
> +        vpl011->uartfr |= TXFF;
> +        vpl011->uartris &= ~TXI;
> +    }
> +
> +    vpl011->uartfr |= BUSY;
> +
> +    vpl011->uartfr &= ~TXFE;
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    /*
> +     * Send an event to console backend to indicate that there is
> +     * data in the OUT ring buffer.
> +     */
> +    notify_via_xen_event_channel(d, vpl011->evtchn);
> +}
> +
> +static int vpl011_mmio_read(struct vcpu *v,
> +                            mmio_info_t *info,
> +                            register_t *r,
> +                            void *priv)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
> +
> +    switch ( vpl011_reg )
> +    {
> +    case DR:
> +        /*
> +         * Since pl011 registers are 32-bit registers, all registers
> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
> +         * accesses.
> +         */

This comment should be on top of the declaration of 
vpl011_reg32_check_access.

> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011_read_data(v->domain), info);
> +        return 1;
> +
> +    case RSR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        /* It always returns 0 as there are no physical errors. */
> +        *r = 0;
> +        return 1;
> +
> +    case FR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartfr, info);

You need to ensure that uartfr is read only once because 
vreg_reg32_extract does not currently ensure that.

> +        return 1;
> +
> +    case RIS:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartris, info);

Ditto.

> +        return 1;
> +
> +    case MIS:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartris &
> +                                vpl011->uartimsc, info);

Ditto.

> +        return 1;
> +
> +    case IMSC:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartimsc, info);

Ditto.

> +        return 1;
> +
> +    case ICR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        /* Only write is valid. */
> +        return 0;
> +
> +    default:
> +        gprintk(XENLOG_ERR, "vpl011: unhandled read r%d offset %#08x\n",
> +                dabt.reg, vpl011_reg);
> +        return 0;
> +    }
> +
> +    return 1;
> +
> +bad_width:
> +    gprintk(XENLOG_ERR, "vpl011: bad read width %d r%d offset %#08x\n",
> +            dabt.size, dabt.reg, vpl011_reg);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +}
> +
> +static int vpl011_mmio_write(struct vcpu *v,
> +                             mmio_info_t *info,
> +                             register_t r,
> +                             void *priv)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
> +    struct domain *d = v->domain;
> +    unsigned long flags;
> +
> +    switch ( vpl011_reg )
> +    {
> +    case DR:
> +    {
> +        uint32_t data = 0;
> +
> +        /*
> +         * Since pl011 registers are 32-bit registers, all registers
> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
> +         * accesses.
> +         */

See above.

> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        vreg_reg32_update(&data, r, info);
> +        data &= 0xFF;
> +        vpl011_write_data(v->domain, data);
> +        return 1;
> +    }
> +    case RSR: /* Nothing to clear. */
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        return 1;
> +
> +    case FR:
> +    case RIS:
> +    case MIS:
> +        goto write_ignore;
> +
> +    case IMSC:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        VPL011_LOCK(d, flags);
> +        vreg_reg32_update(&vpl011->uartimsc, r, info);
> +        VPL011_UNLOCK(d, flags);
> +        vpl011_update(v->domain);

I think this should be call with under the lock.

> +        return 1;
> +
> +    case ICR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        VPL011_LOCK(d, flags);
> +        vreg_reg32_clearbits(&vpl011->uartris, r, info);
> +        VPL011_UNLOCK(d, flags);
> +        vpl011_update(d);

Ditto.

> +        return 1;
> +
> +    default:
> +        gprintk(XENLOG_ERR, "vpl011: unhandled write r%d offset %#08x\n",
> +                dabt.reg, vpl011_reg);
> +        return 0;
> +    }
> +
> +write_ignore:
> +    return 1;
> +
> +bad_width:
> +    gprintk(XENLOG_ERR, "vpl011: bad write width %d r%d offset %#08x\n",
> +            dabt.size, dabt.reg, vpl011_reg);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +}
> +
> +static const struct mmio_handler_ops vpl011_mmio_handler = {
> +    .read = vpl011_mmio_read,
> +    .write = vpl011_mmio_write,
> +};
> +
> +static void vpl011_data_avail(struct domain *d)
> +{
> +    unsigned long flags;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX in_cons = intf->in_cons;
> +    XENCONS_RING_IDX in_prod = intf->in_prod;
> +    XENCONS_RING_IDX out_cons = intf->out_cons;
> +    XENCONS_RING_IDX out_prod = intf->out_prod;

Same as above for the barrier.

> +    XENCONS_RING_IDX in_ring_qsize, out_ring_qsize;
> +
> +    VPL011_LOCK(d, flags);
> +
> +    in_ring_qsize = xencons_queued(in_prod,
> +                                   in_cons,
> +                                   sizeof(intf->in));
> +
> +    out_ring_qsize = xencons_queued(out_prod,
> +                                    out_cons,
> +                                    sizeof(intf->out));
> +
> +    /* Update the uart rx state if the buffer is not empty. */
> +    if ( in_ring_qsize != 0 )
> +    {
> +        vpl011->uartfr &= ~RXFE;
> +        if ( in_ring_qsize == sizeof(intf->in) )
> +            vpl011->uartfr |= RXFF;
> +        vpl011->uartris |= RXI;
> +    }
> +
> +    /* Update the uart tx state if the buffer is not full. */
> +    if ( out_ring_qsize != sizeof(intf->out) )
> +    {
> +        vpl011->uartfr &= ~TXFF;
> +        vpl011->uartris |= TXI;
> +        if ( out_ring_qsize == 0 )
> +        {
> +            vpl011->uartfr &= ~BUSY;
> +            vpl011->uartfr |= TXFE;
> +        }
> +    }
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    vpl011_update(d);

See my comment above for the calling vpl011_update

> +}
> +
> +
> +static void vpl011_notification(struct vcpu *v, unsigned int port)
> +{
> +    vpl011_data_avail(v->domain);
> +}
> +
> +int domain_vpl011_init(struct domain *d, struct vpl011_init_info *info)
> +{
> +    int rc;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    if ( vpl011->ring_buf )
> +        return 0;

IHMO, you should return an error if the PL011 is already initialized. 
This should never happen.

> +
> +    /* Map the guest PFN to Xen address space. */
> +    rc =  prepare_ring_for_helper(d,
> +                                  gfn_x(info->gfn),
> +                                  &vpl011->ring_page,
> +                                  &vpl011->ring_buf);
> +    if ( rc < 0 )
> +        goto out;
> +
> +    rc = vgic_reserve_virq(d, GUEST_VPL011_SPI);
> +    if ( !rc )
> +    {
> +        rc = -EINVAL;
> +        goto out1;
> +    }
> +
> +    register_mmio_handler(d, &vpl011_mmio_handler,
> +                          GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);

Again, you register MMIO handler but never remove them. So if this call 
fail, you will end up with the handlers existing but the rest 
half-initialized which likely lead to a segfault, or worst leaking data.

> +
> +    spin_lock_init(&vpl011->lock);
> +
> +    rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid,
> +                                         vpl011_notification);
> +    if ( rc < 0 )
You
> +        goto out2;
> +
> +    vpl011->evtchn = info->evtchn = rc;
> +
> +    return 0;
> +
> +out2:
> +    xfree(d->arch.vmmio.handlers);
> +    vgic_free_virq(d, GUEST_VPL011_SPI);
> +
> +out1:
> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
> +
> +out:
> +    return rc;
> +}
> +
> +void domain_vpl011_deinit(struct domain *d)
> +{
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    if ( !vpl011->ring_buf )

You will bail out if ring_buf is NULL. However, if you called 
domain_vpl011_init first and it failed, you may have ring_buf set but 
the rest not fully updated. This means that you will free garbagge.

I think this could be solved by reinitialize ring_buf if an error occur 
in domain_vpl011_init.

> +        return;
> +
> +    free_xen_event_channel(d, vpl011->evtchn);
> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
> +    xfree(d->arch.vmmio.handlers);
> +}

[...]

> diff --git a/xen/include/asm-arm/vpl011.h b/xen/include/asm-arm/vpl011.h
> new file mode 100644
> index 0000000..b3e332d
> --- /dev/null
> +++ b/xen/include/asm-arm/vpl011.h
> @@ -0,0 +1,74 @@
> +/*
> + * include/xen/vpl011.h
> + *
> + * Virtual PL011 UART
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef _VPL011_H_
> +

We tend to keep #ifndef and #define together. So please drop the newline 
here.

> +#ifdef CONFIG_VPL011_CONSOLE
> +int domain_vpl011_init(struct domain *d,
> +                       struct vpl011_init_info *info);
> +void domain_vpl011_deinit(struct domain *d);
> +#else
> +static inline int domain_vpl011_init(struct domain *d,
> +                                     struct vpl011_init_info *info)
> +{
> +    return -ENOSYS;
> +}
> +
> +static inline void domain_vpl011_deinit(struct domain *d) { }
> +#endif
> +
> +#endif
> +

Please drop this newline.

> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 00/14 v4] PL011 emulation support in Xen
  2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
                   ` (13 preceding siblings ...)
  2017-06-06 17:25 ` [PATCH 14/14 v4] xen/arm: vpl011: Update documentation for vuart console support Bhupinder Thakur
@ 2017-06-09 13:58 ` Julien Grall
  14 siblings, 0 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-09 13:58 UTC (permalink / raw)
  To: Bhupinder Thakur, xen-devel; +Cc: Wei Liu, Stefano Stabellini, Ian Jackson

Hi Bhupinder,

On 06/06/17 18:25, Bhupinder Thakur wrote:
> The vpl011 changes available at the following repo:
>
> url: ssh://git@git.linaro.org:/people/bhupinder.thakur/xen.git

This address can only be access by Linaro employee/assignee. Please 
provide an URL accessible by everyone so we can test.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-06 23:26   ` Stefano Stabellini
@ 2017-06-09 14:06     ` Julien Grall
  2017-06-09 18:32       ` Stefano Stabellini
  2017-06-14  7:35     ` Bhupinder Thakur
  1 sibling, 1 reply; 65+ messages in thread
From: Julien Grall @ 2017-06-09 14:06 UTC (permalink / raw)
  To: Stefano Stabellini, Bhupinder Thakur; +Cc: xen-devel, Ian Jackson, Wei Liu

Hi Stefano,

On 07/06/17 00:26, Stefano Stabellini wrote:
>> diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
>> index 00909ad4..a8efd5e 100644
>> --- a/tools/libxc/xc_domain.c
>> +++ b/tools/libxc/xc_domain.c
>> @@ -343,6 +343,29 @@ int xc_domain_get_guest_width(xc_interface *xch, uint32_t domid,
>>      return 0;
>>  }
>>
>> +int xc_dom_vpl011_init(xc_interface *xch,
>> +                       uint32_t domid,
>> +                       uint32_t console_domid,
>> +                       xen_pfn_t gfn,
>> +                       evtchn_port_t *evtchn)
>> +{
>> +    DECLARE_DOMCTL;
>> +    int rc = 0;
>> +
>> +    domctl.cmd = XEN_DOMCTL_vuart_op;
>> +    domctl.domain = (domid_t)domid;
>> +    domctl.u.vuart_op.cmd = XEN_DOMCTL_VUART_OP_INIT_VPL011;
>> +    domctl.u.vuart_op.console_domid = console_domid;
>> +    domctl.u.vuart_op.gfn = gfn;
>> +
>> +    if ( (rc = do_domctl(xch, &domctl)) < 0 )
>> +        return rc;
>> +
>> +    *evtchn = domctl.u.vuart_op.evtchn;
>> +
>> +    return rc;
>> +}
>
> It looks like this function should be in one of the arm specific files,
> such as xc_dom_arm.c (otherwise it becomes available to x86 too).

AFAICT xc_dom_arm.c has a completely different purpose. Looking at other 
helpers, it seems the usage if too #ifdef helpers (see 
xc_vcpu_get_extstate or xc_domain_set_memory_map).

[...]

>> +int libxl__arch_domain_create_finish(libxl__gc *gc,
>> +                                     libxl_domain_build_info *info,
>> +                                     uint32_t domid,
>> +                                     libxl__domain_build_state *state)
>> +{
>> +    return 0;
>> +}
>> +
>>  int libxl__arch_extra_memory(libxl__gc *gc,
>>                               const libxl_domain_build_info *info,
>>                               uint64_t *out)
>> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
>> index 76310ed..9e150ba 100644
>> --- a/xen/arch/arm/domain.c
>> +++ b/xen/arch/arm/domain.c
>> @@ -665,6 +665,8 @@ fail:
>>
>>  void arch_domain_destroy(struct domain *d)
>>  {
>> +    domain_vpl011_deinit(d);
>> +
>>      /* IOMMU page table is shared with P2M, always call
>>       * iommu_domain_destroy() before p2m_teardown().
>>       */
>
> I cannot find the definition of domain_vpl011_deinit

See patch #3.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-06 17:25 ` [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011 Bhupinder Thakur
  2017-06-06 23:26   ` Stefano Stabellini
@ 2017-06-09 14:13   ` Julien Grall
  2017-06-14  9:16     ` Bhupinder Thakur
  1 sibling, 1 reply; 65+ messages in thread
From: Julien Grall @ 2017-06-09 14:13 UTC (permalink / raw)
  To: Bhupinder Thakur, xen-devel; +Cc: Wei Liu, Stefano Stabellini, Ian Jackson

Hi Bhupinder,

On 06/06/17 18:25, Bhupinder Thakur wrote:
> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
> index 1629f41..77425dd 100644
> --- a/tools/libxc/include/xenctrl.h
> +++ b/tools/libxc/include/xenctrl.h
> @@ -884,6 +884,23 @@ int xc_vcpu_getcontext(xc_interface *xch,
>                         uint32_t domid,
>                         uint32_t vcpu,
>                         vcpu_guest_context_any_t *ctxt);

Newline here please.

[...]

> diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
> index 5e1fc60..d1ca9c6 100644
> --- a/tools/libxl/libxl_arch.h
> +++ b/tools/libxl/libxl_arch.h
> @@ -32,6 +32,13 @@ _hidden
>  int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
>                 uint32_t domid);
>
> +/* arch specific internal domain creation finish function */
> +_hidden
> +int libxl__arch_domain_create_finish(libxl__gc *gc,
> +                                     libxl_domain_build_info *info,
> +                                     uint32_t domid,
> +                                     libxl__domain_build_state *state);

Can you explain why you need a new arch helper rather than using the 
current one?

[...]

> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 76310ed..9e150ba 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -665,6 +665,8 @@ fail:
>
>  void arch_domain_destroy(struct domain *d)
>  {
> +    domain_vpl011_deinit(d);

Please add a comment explain where the initialization has been done (i.e 
via a DOMCTL). This would make easier to know what's going on.

> +
>      /* IOMMU page table is shared with P2M, always call
>       * iommu_domain_destroy() before p2m_teardown().
>       */
> diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
> index 971caec..741679b 100644
> --- a/xen/arch/arm/domctl.c
> +++ b/xen/arch/arm/domctl.c
> @@ -5,13 +5,15 @@
>   */
>
>  #include <xen/types.h>
> -#include <xen/lib.h>
> +#include <public/domctl.h>
>  #include <xen/errno.h>
> -#include <xen/sched.h>
> +#include <xen/guest_access.h>
>  #include <xen/hypercall.h>
>  #include <xen/iocap.h>
> +#include <xen/lib.h>
> +#include <xen/mm.h>
> +#include <xen/sched.h>
>  #include <xsm/xsm.h>
> -#include <public/domctl.h>

Why do you reshuffle the headers? Is it to use the alphabetical order? 
If so, this should really be done in a separate patch.

>
>  void arch_get_domain_info(const struct domain *d,
>                            struct xen_domctl_getdomaininfo *info)
> @@ -119,6 +121,42 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
>          d->disable_migrate = domctl->u.disable_migrate.disable;
>          return 0;
>
> +    case XEN_DOMCTL_vuart_op:
> +    {
> +        int rc;
> +        struct xen_domctl_vuart_op *vuart_op = &domctl->u.vuart_op;
> +
> +        switch(vuart_op->cmd)
> +        {
> +        case XEN_DOMCTL_VUART_OP_INIT_VPL011:
> +
> +            if ( !d->creation_finished )
> +            {
> +                struct vpl011_init_info info;
> +
> +                info.console_domid = vuart_op->console_domid;
> +                info.gfn = _gfn(vuart_op->gfn);
> +
> +                rc = domain_vpl011_init(d, &info);
> +                if ( !rc )
> +                {
> +                    vuart_op->evtchn = info.evtchn;
> +                    rc = __copy_to_guest(u_domctl, domctl, 1);
> +                }
> +            }
> +            else
> +            {
> +                rc = - EPERM;
> +            }

Unecessary {}.

> +            break;
> +
> +        default:
> +            rc = -EINVAL;
> +            break;
> +        }
> +
> +        return rc;
> +    }
>      default:
>      {
>          int rc;

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-09 13:15     ` Julien Grall
@ 2017-06-09 18:02       ` Stefano Stabellini
  2017-06-13  8:58       ` Bhupinder Thakur
  1 sibling, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-09 18:02 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Wei Liu, Ian Jackson, Bhupinder Thakur, xen-devel

On Fri, 9 Jun 2017, Julien Grall wrote:
> Hi,
> 
> On 07/06/17 00:02, Stefano Stabellini wrote:
> > On Tue, 6 Jun 2017, Bhupinder Thakur wrote:
> > > +static uint8_t vpl011_read_data(struct domain *d)
> > > +{
> > > +    unsigned long flags;
> > > +    uint8_t data = 0;
> > > +    struct vpl011 *vpl011 = &d->arch.vpl011;
> > > +    struct xencons_interface *intf = vpl011->ring_buf;
> > > +    XENCONS_RING_IDX in_cons = intf->in_cons;
> > > +    XENCONS_RING_IDX in_prod = intf->in_prod;
> > 
> > After reading the indexes, we always need barriers. In this case:
> > 
> >   smp_rmb();
> 
> Well, there are already barrier with the spinlock. However, I am bit concern
> about reading those index without the lock taken. You can have concurrent call
> to vpl011_read_data happening and therefore the indexes may have changed when
> the lock will be taken.

I don't like to rely on the barriers within spin_lock, which might or
might not change in future implementations, for PV protocols operations,
which need explicit barrier. But it is true the code would work today
from that perspective.

You are also right that with the current implementation vpl011_read_data
(and vpl011_write_data) could be called twice simultaneously. For that
to work correctly, we have to move the indexes reads after VPL011_LOCK.
In addition, we also need the explicit memory barrier

  smp_rmb()

after the indexes reads to be in sync with the other end. In other words:

  VPL011_LOCK(d, flags);

  in_cons = intf->in_cons;
  in_prod = intf->in_prod;

  smp_rmb();

  /* rest of the code */


The same for the other function.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-09 14:06     ` Julien Grall
@ 2017-06-09 18:32       ` Stefano Stabellini
  0 siblings, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-09 18:32 UTC (permalink / raw)
  To: Julien Grall
  Cc: Bhupinder Thakur, xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu

On Fri, 9 Jun 2017, Julien Grall wrote:
> Hi Stefano,
> 
> On 07/06/17 00:26, Stefano Stabellini wrote:
> > > diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
> > > index 00909ad4..a8efd5e 100644
> > > --- a/tools/libxc/xc_domain.c
> > > +++ b/tools/libxc/xc_domain.c
> > > @@ -343,6 +343,29 @@ int xc_domain_get_guest_width(xc_interface *xch,
> > > uint32_t domid,
> > >      return 0;
> > >  }
> > > 
> > > +int xc_dom_vpl011_init(xc_interface *xch,
> > > +                       uint32_t domid,
> > > +                       uint32_t console_domid,
> > > +                       xen_pfn_t gfn,
> > > +                       evtchn_port_t *evtchn)
> > > +{
> > > +    DECLARE_DOMCTL;
> > > +    int rc = 0;
> > > +
> > > +    domctl.cmd = XEN_DOMCTL_vuart_op;
> > > +    domctl.domain = (domid_t)domid;
> > > +    domctl.u.vuart_op.cmd = XEN_DOMCTL_VUART_OP_INIT_VPL011;
> > > +    domctl.u.vuart_op.console_domid = console_domid;
> > > +    domctl.u.vuart_op.gfn = gfn;
> > > +
> > > +    if ( (rc = do_domctl(xch, &domctl)) < 0 )
> > > +        return rc;
> > > +
> > > +    *evtchn = domctl.u.vuart_op.evtchn;
> > > +
> > > +    return rc;
> > > +}
> > 
> > It looks like this function should be in one of the arm specific files,
> > such as xc_dom_arm.c (otherwise it becomes available to x86 too).
> 
> AFAICT xc_dom_arm.c has a completely different purpose. Looking at other
> helpers, it seems the usage if too #ifdef helpers (see xc_vcpu_get_extstate or
> xc_domain_set_memory_map).

That's true. It's best to continue that pattern and use #ifdefs here.


> > > +int libxl__arch_domain_create_finish(libxl__gc *gc,
> > > +                                     libxl_domain_build_info *info,
> > > +                                     uint32_t domid,
> > > +                                     libxl__domain_build_state *state)
> > > +{
> > > +    return 0;
> > > +}
> > > +
> > >  int libxl__arch_extra_memory(libxl__gc *gc,
> > >                               const libxl_domain_build_info *info,
> > >                               uint64_t *out)
> > > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> > > index 76310ed..9e150ba 100644
> > > --- a/xen/arch/arm/domain.c
> > > +++ b/xen/arch/arm/domain.c
> > > @@ -665,6 +665,8 @@ fail:
> > > 
> > >  void arch_domain_destroy(struct domain *d)
> > >  {
> > > +    domain_vpl011_deinit(d);
> > > +
> > >      /* IOMMU page table is shared with P2M, always call
> > >       * iommu_domain_destroy() before p2m_teardown().
> > >       */
> > 
> > I cannot find the definition of domain_vpl011_deinit
> 
> See patch #3.

All right, thanks. Initially I thought it was weird for this change to
be here, but now I think it makes sense because this patch introduces
the call to domain_vpl011_init. 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-09 13:15     ` Julien Grall
  2017-06-09 18:02       ` Stefano Stabellini
@ 2017-06-13  8:58       ` Bhupinder Thakur
  2017-06-13  9:25         ` Julien Grall
  1 sibling, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-13  8:58 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu

Hi Julien,


>>> +static uint8_t vpl011_read_data(struct domain *d)
>>> +{
>>> +    unsigned long flags;
>>> +    uint8_t data = 0;
>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>> +    struct xencons_interface *intf = vpl011->ring_buf;
>>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>>
>>
>> After reading the indexes, we always need barriers. In this case:
>>
>>   smp_rmb();
>
>
> Well, there are already barrier with the spinlock. However, I am bit concern
> about reading those index without the lock taken. You can have concurrent
> call to vpl011_read_data happening and therefore the indexes may have
> changed when the lock will be taken.

Is there a possibility of concurrent access since this function is
executed as part of
trap handling which will serialize access to this function?
>
>
>>
>>
>>> +    VPL011_LOCK(d, flags);
>>> +
>>> +    /*
>>> +     * 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 )
>>> +    {
>>> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
>>> +        in_cons += 1;
>>> +        intf->in_cons = in_cons;
>>> +        smp_mb();
>>> +    }
>>> +    else
>>> +    {
>>> +        gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer
>>> empty\n");
>>> +    }
>>> +
>>> +    if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == 0 )
>>> +    {
>>> +        vpl011->uartfr |= RXFE;
>>> +        vpl011->uartris &= ~RXI;
>>> +    }
>>> +    vpl011->uartfr &= ~RXFF;
>>> +    VPL011_UNLOCK(d, flags);
>>
>>
>> I am pretty sure that the PV console protocol requires us to notify the
>> other end even on reads. We need to add a notify_via_xen_event_channel
>> here, I think.
>
>
> I would agree here. On the previous version, I asked Bhupinder to explain
> why it is necessary and he said: "On second thoughs, notification is not
> required".
>
I understand that xenconsole is currently using the event notification
as an indication to read
data from the ring buffer. For writing data, it keeps checking
periodically if there is space in the
ring buffer. If there is space then it writes more data.

I agree that as a protocol, it may be a requirement to send the
notifications on read also. I will
add back the notification for this case.

>>
>>
>>> +    return data;
>>> +}
>>> +
>>> +static void vpl011_write_data(struct domain *d, uint8_t data)
>>> +{
>>> +    unsigned long flags;
>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>> +    struct xencons_interface *intf = vpl011->ring_buf;
>>> +    XENCONS_RING_IDX out_cons = intf->out_cons;
>>> +    XENCONS_RING_IDX out_prod = intf->out_prod;
>>
>>
>>   smp_mb()
>
>
> Same remark as above.
>
> [...]
>
>>> +static void vpl011_data_avail(struct domain *d)
>>> +{
>>> +    unsigned long flags;
>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>> +    struct xencons_interface *intf = vpl011->ring_buf;
>>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>>> +    XENCONS_RING_IDX out_cons = intf->out_cons;
>>> +    XENCONS_RING_IDX out_prod = intf->out_prod;
>>> +    XENCONS_RING_IDX in_ring_qsize, out_ring_qsize;
>>
>>
>>   smb_mb()
>
>
> Ditto.
>
Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-13  8:58       ` Bhupinder Thakur
@ 2017-06-13  9:25         ` Julien Grall
  0 siblings, 0 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-13  9:25 UTC (permalink / raw)
  To: Bhupinder Thakur; +Cc: Stefano Stabellini, Wei Liu, Ian Jackson, xen-devel, nd

On 13/06/2017 09:58, Bhupinder Thakur wrote:
> Hi Julien,

Hi Bhupinder,

>>>> +static uint8_t vpl011_read_data(struct domain *d)
>>>> +{
>>>> +    unsigned long flags;
>>>> +    uint8_t data = 0;
>>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>>> +    struct xencons_interface *intf = vpl011->ring_buf;
>>>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>>>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>>>
>>>
>>> After reading the indexes, we always need barriers. In this case:
>>>
>>>   smp_rmb();
>>
>>
>> Well, there are already barrier with the spinlock. However, I am bit concern
>> about reading those index without the lock taken. You can have concurrent
>> call to vpl011_read_data happening and therefore the indexes may have
>> changed when the lock will be taken.
>
> Is there a possibility of concurrent access since this function is
> executed as part of
> trap handling which will serialize access to this function?

There are no locking in the common trap handling. The emulation should 
take care of the locking because multiple vCPU can concurrently access 
the MMIO region.

[....]

>>> I am pretty sure that the PV console protocol requires us to notify the
>>> other end even on reads. We need to add a notify_via_xen_event_channel
>>> here, I think.
>>
>>
>> I would agree here. On the previous version, I asked Bhupinder to explain
>> why it is necessary and he said: "On second thoughs, notification is not
>> required".
>>
> I understand that xenconsole is currently using the event notification
> as an indication to read
> data from the ring buffer. For writing data, it keeps checking
> periodically if there is space in the
> ring buffer. If there is space then it writes more data.

You should not assume that xenconsoled is the only backend console. One 
could decide to implement its own.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-09 13:54   ` Julien Grall
@ 2017-06-13 10:57     ` Bhupinder Thakur
  2017-06-13 12:44       ` Julien Grall
  0 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-13 10:57 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu

Hi Julien,


>>
>>  tools/console/daemon/io.c        |   2 +-
>>  xen/arch/arm/Kconfig             |   5 +
>>  xen/arch/arm/Makefile            |   1 +
>>  xen/arch/arm/vpl011.c            | 418
>> +++++++++++++++++++++++++++++++++++++++
>>  xen/include/asm-arm/domain.h     |   6 +
>>  xen/include/asm-arm/pl011-uart.h |   2 +
>>  xen/include/asm-arm/vpl011.h     |  74 +++++++
>>  xen/include/public/arch-arm.h    |   6 +
>>  xen/include/public/io/console.h  |   4 +
>
>
> This would require an ACK from Konrad. The addition would also need to be
> justified in the commit message. Although, you probably want to split this
> change in a separate patch.
I will send this change in a separate patch.

>
>>  9 files changed, 517 insertions(+), 1 deletion(-)
>>  create mode 100644 xen/arch/arm/vpl011.c
>>  create mode 100644 xen/include/asm-arm/vpl011.h
>>
>> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
>> index 7e6a886..947f13a 100644
>> --- a/tools/console/daemon/io.c
>> +++ b/tools/console/daemon/io.c
>
>
> Can you explain why you change the position of the include in io.c?
Since I am including ring.h in console.h, it needs string.h to be
included first.

>
>> @@ -21,6 +21,7 @@
>>
>>  #include "utils.h"
>>  #include "io.h"
>> +#include <string.h>
>>  #include <xenevtchn.h>
>>  #include <xengnttab.h>
>>  #include <xenstore.h>
>> @@ -29,7 +30,6 @@
>>
>>  #include <stdlib.h>
>>  #include <errno.h>
>> -#include <string.h>
>>  #include <poll.h>
>>  #include <fcntl.h>
>>  #include <unistd.h>
>
>
>
> [...]
>
>>  menu "ARM errata workaround via the alternative framework"
>> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
>> index 49e1fb2..15efc13 100644
>> --- a/xen/arch/arm/Makefile
>> +++ b/xen/arch/arm/Makefile
>> @@ -52,6 +52,7 @@ obj-y += vm_event.o
>>  obj-y += vtimer.o
>>  obj-y += vpsci.o
>>  obj-y += vuart.o
>> +obj-$(CONFIG_VPL011_CONSOLE) += vpl011.o
>
>
> Please the alphabetical order. Just noticed vtimer is not correctly
> positioned. I will send a patch for that.
>
ok.
>
>> +#include <xen/errno.h>
>> +#include <xen/event.h>
>> +#include <xen/guest_access.h>
>> +#include <xen/init.h>
>> +#include <xen/lib.h>
>> +#include <xen/mm.h>
>> +#include <xen/sched.h>
>> +#include <public/domctl.h>
>> +#include <public/io/console.h>
>> +#include <asm-arm/pl011-uart.h>
>> +#include <asm-arm/vgic-emul.h>
>> +#include <asm-arm/vpl011.h>
>> +
>> +static bool vpl011_reg32_check_access(struct hsr_dabt dabt)
>> +{
>> +    return (dabt.size != DABT_DOUBLE_WORD);
>
>
> Again, please add a comment explaining why we allow all the sizes but
> 64-bit.
>
>> +}
>> +
>> +static void vpl011_update(struct domain *d)
>> +{
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +
>> +    /*
>> +     * TODO: PL011 interrupts are level triggered which means
>> +     * that interrupt needs to be set/clear instead of being
>> +     * injected. However, currently vGIC does not handle level
>> +     * triggered interrupts properly. This function needs to be
>> +     * revisited once vGIC starts handling level triggered
>> +     * interrupts.
>> +     */
>> +    if ( vpl011->uartris & vpl011->uartimsc )
>
>
> The write in uartirs and uartimsc are protected by a lock. Shouldn't it be
> the case here too? More that they are not updated atomically.
>
> You probably want to call vpl011_update with vpl011 lock taken to make sure
> you don't have any synchronization issue.

Since we are just reading the values here, I think it is fine to not
take a lock. The
condition will either be true or false.

>
>> +        vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI);
>> +}
>> +
>> +static uint8_t vpl011_read_data(struct domain *d)
>> +{
>> +    unsigned long flags;
>> +    uint8_t data = 0;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>
>
> See my answer on Stefano's e-mail regarding the barrier here.
> (<fa3e5003-5c7f-0886-d437-6b643347b4c5@arm.com>)
>
>> +
>> +    VPL011_LOCK(d, flags);
>> +
>> +    /*
>> +     * 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 )
>> +    {
>> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
>> +        in_cons += 1;
>> +        intf->in_cons = in_cons;
>> +        smp_mb();
>
>
> I don't understand why you moved the barrier from between reading the data
> and intf->in_cons. You have to ensure the character is read before updating
> in_cons.
I thought that since these 3 statements are dependent on in_cons, they
would be executed in order due to data dependency. The memory barrier
after the 3 statements ensures that intf->in_cons is updated before
proceeding ahead.

>
>> +    }
>> +    else
>> +    {
>> +        gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer empty\n");
>> +    }
>
>
> The {} are not necessary.
ok.
>
>> +
>> +    if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == 0 )
>
>
> What if the other end of the ring has put more data whilst reading one
> character?
It will raise an event when the other end puts more data and in the
event handling function data_available(), it will clear the RXFE bit.

>
>> +    {
>> +        vpl011->uartfr |= RXFE;
>> +        vpl011->uartris &= ~RXI;
>> +    }
>> +    vpl011->uartfr &= ~RXFF;
>> +    VPL011_UNLOCK(d, flags);
>> +
>> +    return data;
>> +}
>> +
>> +static void vpl011_write_data(struct domain *d, uint8_t data)
>> +{
>> +    unsigned long flags;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX out_cons = intf->out_cons;
>> +    XENCONS_RING_IDX out_prod = intf->out_prod;
>
>
> See my remark above.
I will move index reading under lock.

>
>> +
>> +    VPL011_LOCK(d, flags);
>> +
>> +    /*
>> +     * It is expected that the ring is not full when this function is
>> called
>> +     * as the guest is expected to write to the data register only when
>> the
>> +     * TXFF flag is not set.
>> +     * In case the guest does write even when the TXFF flag is set then
>> the
>> +     * data will be silently dropped.
>> +     */
>> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) !=
>> +         sizeof (intf->out) )
>> +    {
>> +        intf->out[xencons_mask(out_prod, sizeof(intf->out))] = data;
>> +        smp_wmb();
>> +        out_prod += 1;
>> +        intf->out_prod = out_prod;
>> +    }
>> +    else
>> +    {
>> +        gprintk(XENLOG_ERR, "vpl011: Unexpected OUT ring buffer full\n");
>> +    }
>
>
> The {} are not necessary.
ok.
>
>> +
>> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) ==
>> +         sizeof (intf->out) )
>
>
> Ditto here.
>
>
>> +    {
>> +        vpl011->uartfr |= TXFF;
>> +        vpl011->uartris &= ~TXI;
>> +    }
>> +
>> +    vpl011->uartfr |= BUSY;
>> +
>> +    vpl011->uartfr &= ~TXFE;
>> +
>> +    VPL011_UNLOCK(d, flags);
>> +
>> +    /*
>> +     * Send an event to console backend to indicate that there is
>> +     * data in the OUT ring buffer.
>> +     */
>> +    notify_via_xen_event_channel(d, vpl011->evtchn);
>> +}
>> +
>> +static int vpl011_mmio_read(struct vcpu *v,
>> +                            mmio_info_t *info,
>> +                            register_t *r,
>> +                            void *priv)
>> +{
>> +    struct hsr_dabt dabt = info->dabt;
>> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
>> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
>> +
>> +    switch ( vpl011_reg )
>> +    {
>> +    case DR:
>> +        /*
>> +         * Since pl011 registers are 32-bit registers, all registers
>> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
>> +         * accesses.
>> +         */
>
>
> This comment should be on top of the declaration of
> vpl011_reg32_check_access.
ok.
>
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011_read_data(v->domain), info);
>> +        return 1;
>> +
>> +    case RSR:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        /* It always returns 0 as there are no physical errors. */
>> +        *r = 0;
>> +        return 1;
>> +
>> +    case FR:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011->uartfr, info);
>
>
> You need to ensure that uartfr is read only once because vreg_reg32_extract
> does not currently ensure that.
>
>> +        return 1;
>> +
>> +    case RIS:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011->uartris, info);
>
>
> Ditto.
>
>> +        return 1;
>> +
>> +    case MIS:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011->uartris &
>> +                                vpl011->uartimsc, info);
>
>
> Ditto.
>
>> +        return 1;
>> +
>> +    case IMSC:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011->uartimsc, info);
>
>
> Ditto.
I will read these registers into a local variable and use it.

>
>
>> +        return 1;
>> +
>> +    case ICR:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        /* Only write is valid. */
>> +        return 0;
>> +
>> +    default:
>> +        gprintk(XENLOG_ERR, "vpl011: unhandled read r%d offset %#08x\n",
>> +                dabt.reg, vpl011_reg);
>> +        return 0;
>> +    }
>> +
>> +    return 1;
>> +
>> +bad_width:
>> +    gprintk(XENLOG_ERR, "vpl011: bad read width %d r%d offset %#08x\n",
>> +            dabt.size, dabt.reg, vpl011_reg);
>> +    domain_crash_synchronous();
>> +    return 0;
>> +
>> +}
>> +
>> +static int vpl011_mmio_write(struct vcpu *v,
>> +                             mmio_info_t *info,
>> +                             register_t r,
>> +                             void *priv)
>> +{
>> +    struct hsr_dabt dabt = info->dabt;
>> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
>> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
>> +    struct domain *d = v->domain;
>> +    unsigned long flags;
>> +
>> +    switch ( vpl011_reg )
>> +    {
>> +    case DR:
>> +    {
>> +        uint32_t data = 0;
>> +
>> +        /*
>> +         * Since pl011 registers are 32-bit registers, all registers
>> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
>> +         * accesses.
>> +         */
>
>
> See above.
>
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        vreg_reg32_update(&data, r, info);
>> +        data &= 0xFF;
>> +        vpl011_write_data(v->domain, data);
>> +        return 1;
>> +    }
>> +    case RSR: /* Nothing to clear. */
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        return 1;
>> +
>> +    case FR:
>> +    case RIS:
>> +    case MIS:
>> +        goto write_ignore;
>> +
>> +    case IMSC:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        VPL011_LOCK(d, flags);
>> +        vreg_reg32_update(&vpl011->uartimsc, r, info);
>> +        VPL011_UNLOCK(d, flags);
>> +        vpl011_update(v->domain);
>
>
> I think this should be call with under the lock.
>
>> +        return 1;
>> +
>> +    case ICR:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        VPL011_LOCK(d, flags);
>> +        vreg_reg32_clearbits(&vpl011->uartris, r, info);
>> +        VPL011_UNLOCK(d, flags);
>> +        vpl011_update(d);
>
>
> Ditto.
>
>
>> +        return 1;
>> +
>> +    default:
>> +        gprintk(XENLOG_ERR, "vpl011: unhandled write r%d offset %#08x\n",
>> +                dabt.reg, vpl011_reg);
>> +        return 0;
>> +    }
>> +
>> +write_ignore:
>> +    return 1;
>> +
>> +bad_width:
>> +    gprintk(XENLOG_ERR, "vpl011: bad write width %d r%d offset %#08x\n",
>> +            dabt.size, dabt.reg, vpl011_reg);
>> +    domain_crash_synchronous();
>> +    return 0;
>> +
>> +}
>> +
>> +static const struct mmio_handler_ops vpl011_mmio_handler = {
>> +    .read = vpl011_mmio_read,
>> +    .write = vpl011_mmio_write,
>> +};
>> +
>> +static void vpl011_data_avail(struct domain *d)
>> +{
>> +    unsigned long flags;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>> +    XENCONS_RING_IDX out_cons = intf->out_cons;
>> +    XENCONS_RING_IDX out_prod = intf->out_prod;
>
>
> Same as above for the barrier.
>
>
>> +    XENCONS_RING_IDX in_ring_qsize, out_ring_qsize;
>> +
>> +    VPL011_LOCK(d, flags);
>> +
>> +    in_ring_qsize = xencons_queued(in_prod,
>> +                                   in_cons,
>> +                                   sizeof(intf->in));
>> +
>> +    out_ring_qsize = xencons_queued(out_prod,
>> +                                    out_cons,
>> +                                    sizeof(intf->out));
>> +
>> +    /* Update the uart rx state if the buffer is not empty. */
>> +    if ( in_ring_qsize != 0 )
>> +    {
>> +        vpl011->uartfr &= ~RXFE;
>> +        if ( in_ring_qsize == sizeof(intf->in) )
>> +            vpl011->uartfr |= RXFF;
>> +        vpl011->uartris |= RXI;
>> +    }
>> +
>> +    /* Update the uart tx state if the buffer is not full. */
>> +    if ( out_ring_qsize != sizeof(intf->out) )
>> +    {
>> +        vpl011->uartfr &= ~TXFF;
>> +        vpl011->uartris |= TXI;
>> +        if ( out_ring_qsize == 0 )
>> +        {
>> +            vpl011->uartfr &= ~BUSY;
>> +            vpl011->uartfr |= TXFE;
>> +        }
>> +    }
>> +
>> +    VPL011_UNLOCK(d, flags);
>> +
>> +    vpl011_update(d);
>
>
> See my comment above for the calling vpl011_update
>
>> +}
>> +
>> +
>> +static void vpl011_notification(struct vcpu *v, unsigned int port)
>> +{
>> +    vpl011_data_avail(v->domain);
>> +}
>> +
>> +int domain_vpl011_init(struct domain *d, struct vpl011_init_info *info)
>> +{
>> +    int rc;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +
>> +    if ( vpl011->ring_buf )
>> +        return 0;
>
>
> IHMO, you should return an error if the PL011 is already initialized. This
> should never happen.
ok.
>
>> +
>> +    /* Map the guest PFN to Xen address space. */
>> +    rc =  prepare_ring_for_helper(d,
>> +                                  gfn_x(info->gfn),
>> +                                  &vpl011->ring_page,
>> +                                  &vpl011->ring_buf);
>> +    if ( rc < 0 )
>> +        goto out;
>> +
>> +    rc = vgic_reserve_virq(d, GUEST_VPL011_SPI);
>> +    if ( !rc )
>> +    {
>> +        rc = -EINVAL;
>> +        goto out1;
>> +    }
>> +
>> +    register_mmio_handler(d, &vpl011_mmio_handler,
>> +                          GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);
>
>
> Again, you register MMIO handler but never remove them. So if this call
> fail, you will end up with the handlers existing but the rest
> half-initialized which likely lead to a segfault, or worst leaking data.
This function does not return a status. So there is no way to find out
if the mmio handlers were
registered successfully. I am removing the mmio handlers in the error
legs in domain_vpl011_init().
>
>> +
>> +    spin_lock_init(&vpl011->lock);
>> +
>> +    rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid,
>> +                                         vpl011_notification);
>> +    if ( rc < 0 )
>
> You
I think this is a type.

>>
>> +        goto out2;
>> +
>> +    vpl011->evtchn = info->evtchn = rc;
>> +
>> +    return 0;
>> +
>> +out2:
>> +    xfree(d->arch.vmmio.handlers);
>> +    vgic_free_virq(d, GUEST_VPL011_SPI);
>> +
>> +out1:
>> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
>> +
>> +out:
>> +    return rc;
>> +}
>> +
>> +void domain_vpl011_deinit(struct domain *d)
>> +{
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +
>> +    if ( !vpl011->ring_buf )
>
>
> You will bail out if ring_buf is NULL. However, if you called
> domain_vpl011_init first and it failed, you may have ring_buf set but the
> rest not fully updated. This means that you will free garbagge.
>
> I think this could be solved by reinitialize ring_buf if an error occur in
> domain_vpl011_init.
destroy_ring_for_helper() sets the first parameter to NULL incase it fails.

>
>> +        return;
>> +
>> +    free_xen_event_channel(d, vpl011->evtchn);
>> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
>> +    xfree(d->arch.vmmio.handlers);
>> +}
>
>
> [...]
>
>
>> diff --git a/xen/include/asm-arm/vpl011.h b/xen/include/asm-arm/vpl011.h
>> new file mode 100644
>> index 0000000..b3e332d
>> --- /dev/null
>> +++ b/xen/include/asm-arm/vpl011.h
>> @@ -0,0 +1,74 @@
>> +/*
>> + * include/xen/vpl011.h
>> + *
>> + * Virtual PL011 UART
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> it
>> + * under the terms and conditions of the GNU General Public License,
>> + * version 2, as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#ifndef _VPL011_H_
>> +
>
>
> We tend to keep #ifndef and #define together. So please drop the newline
> here.
>
ok.
>> +#ifdef CONFIG_VPL011_CONSOLE
>> +int domain_vpl011_init(struct domain *d,
>> +                       struct vpl011_init_info *info);
>> +void domain_vpl011_deinit(struct domain *d);
>> +#else
>> +static inline int domain_vpl011_init(struct domain *d,
>> +                                     struct vpl011_init_info *info)
>> +{
>> +    return -ENOSYS;
>> +}
>> +
>> +static inline void domain_vpl011_deinit(struct domain *d) { }
>> +#endif
>> +
>> +#endif
>> +
>
>
> Please drop this newline.
You mean the newline between the #endifs or after the last #endif?
>
Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-13 10:57     ` Bhupinder Thakur
@ 2017-06-13 12:44       ` Julien Grall
  2017-06-13 17:50         ` Stefano Stabellini
  2017-06-14  5:47         ` Bhupinder Thakur
  0 siblings, 2 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-13 12:44 UTC (permalink / raw)
  To: Bhupinder Thakur; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu



On 13/06/17 11:57, Bhupinder Thakur wrote:
> Hi Julien,

Hi Bhupinder,

>
>>>
>>>  tools/console/daemon/io.c        |   2 +-
>>>  xen/arch/arm/Kconfig             |   5 +
>>>  xen/arch/arm/Makefile            |   1 +
>>>  xen/arch/arm/vpl011.c            | 418
>>> +++++++++++++++++++++++++++++++++++++++
>>>  xen/include/asm-arm/domain.h     |   6 +
>>>  xen/include/asm-arm/pl011-uart.h |   2 +
>>>  xen/include/asm-arm/vpl011.h     |  74 +++++++
>>>  xen/include/public/arch-arm.h    |   6 +
>>>  xen/include/public/io/console.h  |   4 +
>>
>>
>> This would require an ACK from Konrad. The addition would also need to be
>> justified in the commit message. Although, you probably want to split this
>> change in a separate patch.
> I will send this change in a separate patch.
>
>>
>>>  9 files changed, 517 insertions(+), 1 deletion(-)
>>>  create mode 100644 xen/arch/arm/vpl011.c
>>>  create mode 100644 xen/include/asm-arm/vpl011.h
>>>
>>> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
>>> index 7e6a886..947f13a 100644
>>> --- a/tools/console/daemon/io.c
>>> +++ b/tools/console/daemon/io.c
>>
>>
>> Can you explain why you change the position of the include in io.c?
> Since I am including ring.h in console.h, it needs string.h to be
> included first.

This should be justified in the commit message.

[...]

>>> +}
>>> +
>>> +static void vpl011_update(struct domain *d)
>>> +{
>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>> +
>>> +    /*
>>> +     * TODO: PL011 interrupts are level triggered which means
>>> +     * that interrupt needs to be set/clear instead of being
>>> +     * injected. However, currently vGIC does not handle level
>>> +     * triggered interrupts properly. This function needs to be
>>> +     * revisited once vGIC starts handling level triggered
>>> +     * interrupts.
>>> +     */
>>> +    if ( vpl011->uartris & vpl011->uartimsc )
>>
>>
>> The write in uartirs and uartimsc are protected by a lock. Shouldn't it be
>> the case here too? More that they are not updated atomically.
>>
>> You probably want to call vpl011_update with vpl011 lock taken to make sure
>> you don't have any synchronization issue.
>
> Since we are just reading the values here, I think it is fine to not
> take a lock. The
> condition will either be true or false.

uartris and uartimsc may not be updated atomically because 
vreg_reg32_update does not guarantee it.

So you may read a wrong value here and potentially inject spurious 
interrupt. This will get much worse when level will fully be supported 
as you may switch the level of the interrupt by mistake.

>
>>
>>> +        vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI);
>>> +}
>>> +
>>> +static uint8_t vpl011_read_data(struct domain *d)
>>> +{
>>> +    unsigned long flags;
>>> +    uint8_t data = 0;
>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>> +    struct xencons_interface *intf = vpl011->ring_buf;
>>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>>
>>
>> See my answer on Stefano's e-mail regarding the barrier here.
>> (<fa3e5003-5c7f-0886-d437-6b643347b4c5@arm.com>)
>>
>>> +
>>> +    VPL011_LOCK(d, flags);
>>> +
>>> +    /*
>>> +     * 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 )
>>> +    {
>>> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
>>> +        in_cons += 1;
>>> +        intf->in_cons = in_cons;
>>> +        smp_mb();
>>
>>
>> I don't understand why you moved the barrier from between reading the data
>> and intf->in_cons. You have to ensure the character is read before updating
>> in_cons.
> I thought that since these 3 statements are dependent on in_cons, they
> would be executed in order due to data dependency.

How do you know the compiler will generate assembly which contain the 
data dependency?

Likely it will not be the case because in_cons will be used indirectly 
as we mask it first.

> The memory barrier
> after the 3 statements ensures that intf->in_cons is updated before
> proceeding ahead.

Can you explain why?

IHMO, what matter here is in_cons to be written after intf->in[...] is 
read. Otherwise the backend may see in_cons before the character has 
effectively been read.

>> What if the other end of the ring has put more data whilst reading one
>> character?
> It will raise an event when the other end puts more data and in the
> event handling function data_available(), it will clear the RXFE bit.

And this is fine because the lock is here to protect uartfr/uartis I guess?

[...]

>>> +
>>> +    /* Map the guest PFN to Xen address space. */
>>> +    rc =  prepare_ring_for_helper(d,
>>> +                                  gfn_x(info->gfn),
>>> +                                  &vpl011->ring_page,
>>> +                                  &vpl011->ring_buf);
>>> +    if ( rc < 0 )
>>> +        goto out;
>>> +
>>> +    rc = vgic_reserve_virq(d, GUEST_VPL011_SPI);
>>> +    if ( !rc )
>>> +    {
>>> +        rc = -EINVAL;
>>> +        goto out1;
>>> +    }
>>> +
>>> +    register_mmio_handler(d, &vpl011_mmio_handler,
>>> +                          GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);
>>
>>
>> Again, you register MMIO handler but never remove them. So if this call
>> fail, you will end up with the handlers existing but the rest
>> half-initialized which likely lead to a segfault, or worst leaking data.
> This function does not return a status. So there is no way to find out
> if the mmio handlers were
> registered successfully.

That's not my point. register_mmio_handler should never fail. However, 
the code below (alloc_unbount_...) may fail. And you bail

> I am removing the mmio handlers in the error
> legs in domain_vpl011_init().

Xen does not have any helper to revert the behavior of 
register_mmio_handler and I don't seem to introduce why. So how do you 
do it?

Anyway, you will not need to worry about removing MMIO handler if you 
move the call after all the call that may fail.

>>
>>> +
>>> +    spin_lock_init(&vpl011->lock);
>>> +
>>> +    rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid,
>>> +                                         vpl011_notification);
>>> +    if ( rc < 0 )
>>
>> You
> I think this is a type.

hmmm likely.

>
>>>
>>> +        goto out2;
>>> +
>>> +    vpl011->evtchn = info->evtchn = rc;
>>> +
>>> +    return 0;
>>> +
>>> +out2:
>>> +    xfree(d->arch.vmmio.handlers);
>>> +    vgic_free_virq(d, GUEST_VPL011_SPI);
>>> +
>>> +out1:
>>> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
>>> +
>>> +out:
>>> +    return rc;
>>> +}
>>> +
>>> +void domain_vpl011_deinit(struct domain *d)
>>> +{
>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>> +
>>> +    if ( !vpl011->ring_buf )
>>
>>
>> You will bail out if ring_buf is NULL. However, if you called
>> domain_vpl011_init first and it failed, you may have ring_buf set but the
>> rest not fully updated. This means that you will free garbagge.
>>
>> I think this could be solved by reinitialize ring_buf if an error occur in
>> domain_vpl011_init.
> destroy_ring_for_helper() sets the first parameter to NULL incase it fails.

Fine. I think it is a bit fragile, but I don't see why someone would 
decide to remove it without checking all the callers.

[...]

>>> +#ifdef CONFIG_VPL011_CONSOLE
>>> +int domain_vpl011_init(struct domain *d,
>>> +                       struct vpl011_init_info *info);
>>> +void domain_vpl011_deinit(struct domain *d);
>>> +#else
>>> +static inline int domain_vpl011_init(struct domain *d,
>>> +                                     struct vpl011_init_info *info)
>>> +{
>>> +    return -ENOSYS;
>>> +}
>>> +
>>> +static inline void domain_vpl011_deinit(struct domain *d) { }
>>> +#endif
>>> +
>>> +#endif
>>> +
>>
>>
>> Please drop this newline.
> You mean the newline between the #endifs or after the last #endif?

Yes.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-13 12:44       ` Julien Grall
@ 2017-06-13 17:50         ` Stefano Stabellini
  2017-06-14  5:47         ` Bhupinder Thakur
  1 sibling, 0 replies; 65+ messages in thread
From: Stefano Stabellini @ 2017-06-13 17:50 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, Wei Liu, Ian Jackson, Bhupinder Thakur, xen-devel

On Tue, 13 Jun 2017, Julien Grall wrote:
> > > >  tools/console/daemon/io.c        |   2 +-
> > > >  xen/arch/arm/Kconfig             |   5 +
> > > >  xen/arch/arm/Makefile            |   1 +
> > > >  xen/arch/arm/vpl011.c            | 418
> > > > +++++++++++++++++++++++++++++++++++++++
> > > >  xen/include/asm-arm/domain.h     |   6 +
> > > >  xen/include/asm-arm/pl011-uart.h |   2 +
> > > >  xen/include/asm-arm/vpl011.h     |  74 +++++++
> > > >  xen/include/public/arch-arm.h    |   6 +
> > > >  xen/include/public/io/console.h  |   4 +
> > > 
> > > 
> > > This would require an ACK from Konrad. The addition would also need to be
> > > justified in the commit message. Although, you probably want to split this
> > > change in a separate patch.
> > I will send this change in a separate patch.
> > 
> > > 
> > > >  9 files changed, 517 insertions(+), 1 deletion(-)
> > > >  create mode 100644 xen/arch/arm/vpl011.c
> > > >  create mode 100644 xen/include/asm-arm/vpl011.h
> > > > 
> > > > diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> > > > index 7e6a886..947f13a 100644
> > > > --- a/tools/console/daemon/io.c
> > > > +++ b/tools/console/daemon/io.c
> > > 
> > > 
> > > Can you explain why you change the position of the include in io.c?
> > Since I am including ring.h in console.h, it needs string.h to be
> > included first.
> 
> This should be justified in the commit message.
> 
> [...]
> 
> > > > +}
> > > > +
> > > > +static void vpl011_update(struct domain *d)
> > > > +{
> > > > +    struct vpl011 *vpl011 = &d->arch.vpl011;
> > > > +
> > > > +    /*
> > > > +     * TODO: PL011 interrupts are level triggered which means
> > > > +     * that interrupt needs to be set/clear instead of being
> > > > +     * injected. However, currently vGIC does not handle level
> > > > +     * triggered interrupts properly. This function needs to be
> > > > +     * revisited once vGIC starts handling level triggered
> > > > +     * interrupts.
> > > > +     */
> > > > +    if ( vpl011->uartris & vpl011->uartimsc )
> > > 
> > > 
> > > The write in uartirs and uartimsc are protected by a lock. Shouldn't it be
> > > the case here too? More that they are not updated atomically.
> > > 
> > > You probably want to call vpl011_update with vpl011 lock taken to make
> > > sure
> > > you don't have any synchronization issue.
> > 
> > Since we are just reading the values here, I think it is fine to not
> > take a lock. The
> > condition will either be true or false.
> 
> uartris and uartimsc may not be updated atomically because vreg_reg32_update
> does not guarantee it.
> 
> So you may read a wrong value here and potentially inject spurious interrupt.
> This will get much worse when level will fully be supported as you may switch
> the level of the interrupt by mistake.
> 
> > 
> > > 
> > > > +        vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI);
> > > > +}
> > > > +
> > > > +static uint8_t vpl011_read_data(struct domain *d)
> > > > +{
> > > > +    unsigned long flags;
> > > > +    uint8_t data = 0;
> > > > +    struct vpl011 *vpl011 = &d->arch.vpl011;
> > > > +    struct xencons_interface *intf = vpl011->ring_buf;
> > > > +    XENCONS_RING_IDX in_cons = intf->in_cons;
> > > > +    XENCONS_RING_IDX in_prod = intf->in_prod;
> > > 
> > > 
> > > See my answer on Stefano's e-mail regarding the barrier here.
> > > (<fa3e5003-5c7f-0886-d437-6b643347b4c5@arm.com>)
> > > 
> > > > +
> > > > +    VPL011_LOCK(d, flags);
> > > > +
> > > > +    /*
> > > > +     * 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 )
> > > > +    {
> > > > +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
> > > > +        in_cons += 1;
> > > > +        intf->in_cons = in_cons;
> > > > +        smp_mb();
> > > 
> > > 
> > > I don't understand why you moved the barrier from between reading the data
> > > and intf->in_cons. You have to ensure the character is read before
> > > updating
> > > in_cons.
> > I thought that since these 3 statements are dependent on in_cons, they
> > would be executed in order due to data dependency.
> 
> How do you know the compiler will generate assembly which contain the data
> dependency?
> 
> Likely it will not be the case because in_cons will be used indirectly as we
> mask it first.
> 
> > The memory barrier
> > after the 3 statements ensures that intf->in_cons is updated before
> > proceeding ahead.
> 
> Can you explain why?
> 
> IHMO, what matter here is in_cons to be written after intf->in[...] is read.
> Otherwise the backend may see in_cons before the character has effectively
> been read.

Julien is right, I missed it in my review. The smp_mb() should be before
increasing intf->in_cons:

  smp_mb();
  intf->in_cons = in_cons;

Like you have done correctly in vpl011_write_data. The reason is that
you need to make sure that the read is complete before increasing the
index, because as soon as you do that the other end could overwrite your
data.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-13 12:44       ` Julien Grall
  2017-06-13 17:50         ` Stefano Stabellini
@ 2017-06-14  5:47         ` Bhupinder Thakur
  2017-06-14  9:33           ` Julien Grall
  1 sibling, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-14  5:47 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu

Hi Julien,


>>>> +}
>>>> +
>>>> +static void vpl011_update(struct domain *d)
>>>> +{
>>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>>> +
>>>> +    /*
>>>> +     * TODO: PL011 interrupts are level triggered which means
>>>> +     * that interrupt needs to be set/clear instead of being
>>>> +     * injected. However, currently vGIC does not handle level
>>>> +     * triggered interrupts properly. This function needs to be
>>>> +     * revisited once vGIC starts handling level triggered
>>>> +     * interrupts.
>>>> +     */
>>>> +    if ( vpl011->uartris & vpl011->uartimsc )
>>>
>>>
>>>
>>> The write in uartirs and uartimsc are protected by a lock. Shouldn't it
>>> be
>>> the case here too? More that they are not updated atomically.
>>>
>>> You probably want to call vpl011_update with vpl011 lock taken to make
>>> sure
>>> you don't have any synchronization issue.
>>
>>
>> Since we are just reading the values here, I think it is fine to not
>> take a lock. The
>> condition will either be true or false.
>
>
> uartris and uartimsc may not be updated atomically because vreg_reg32_update
> does not guarantee it.
>
> So you may read a wrong value here and potentially inject spurious
> interrupt. This will get much worse when level will fully be supported as
> you may switch the level of the interrupt by mistake.
>
Ok. I will check this condition under lock. But should I call
vgic_vcpu_inject_spi() also under the same lock? I think we can do
like this:

vpl011_lock();
mask =  vpl011->uartris & vpl011->uartimsc;
vpl011_unlock();

if ( mask )
   vgic_vcpu_inject_spi();
>

>>> See my answer on Stefano's e-mail regarding the barrier here.
>>> (<fa3e5003-5c7f-0886-d437-6b643347b4c5@arm.com>)
>>>
>>>> +
>>>> +    VPL011_LOCK(d, flags);
>>>> +
>>>> +    /*
>>>> +     * 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 )
>>>> +    {
>>>> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
>>>> +        in_cons += 1;
>>>> +        intf->in_cons = in_cons;
>>>> +        smp_mb();
>>>
>>>
>>>
>>> I don't understand why you moved the barrier from between reading the
>>> data
>>> and intf->in_cons. You have to ensure the character is read before
>>> updating
>>> in_cons.
>>
>> I thought that since these 3 statements are dependent on in_cons, they
>> would be executed in order due to data dependency.
>
>
> How do you know the compiler will generate assembly which contain the data
> dependency?
>
> Likely it will not be the case because in_cons will be used indirectly as we
> mask it first.
>
>> The memory barrier
>> after the 3 statements ensures that intf->in_cons is updated before
>> proceeding ahead.
>
>
> Can you explain why?
>
> IHMO, what matter here is in_cons to be written after intf->in[...] is read.
> Otherwise the backend may see in_cons before the character has effectively
> been read.
>
ok. The issue is that the other end (xenconsole running on maybe some
other CPU) may see the increment operation first before the read
operation could complete (due to some quirk of memory/cache
architecture) even though the CPU running the mmio_read() will see the
effect in the correct order only.

I will move the smp_mb() before index is incremented.

>>> What if the other end of the ring has put more data whilst reading one
>>> character?
>>
>> It will raise an event when the other end puts more data and in the
>> event handling function data_available(), it will clear the RXFE bit.
>
>
> And this is fine because the lock is here to protect uartfr/uartis I guess?
Yes.

>
> [...]
>
>>>> +
>>>> +    /* Map the guest PFN to Xen address space. */
>>>> +    rc =  prepare_ring_for_helper(d,
>>>> +                                  gfn_x(info->gfn),
>>>> +                                  &vpl011->ring_page,
>>>> +                                  &vpl011->ring_buf);
>>>> +    if ( rc < 0 )
>>>> +        goto out;
>>>> +
>>>> +    rc = vgic_reserve_virq(d, GUEST_VPL011_SPI);
>>>> +    if ( !rc )
>>>> +    {
>>>> +        rc = -EINVAL;
>>>> +        goto out1;
>>>> +    }
>>>> +
>>>> +    register_mmio_handler(d, &vpl011_mmio_handler,
>>>> +                          GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);
>>>
>>>
>>>
>>> Again, you register MMIO handler but never remove them. So if this call
>>> fail, you will end up with the handlers existing but the rest
>>> half-initialized which likely lead to a segfault, or worst leaking data.
>>
>> This function does not return a status. So there is no way to find out
>> if the mmio handlers were
>> registered successfully.
>
>
> That's not my point. register_mmio_handler should never fail. However, the
> code below (alloc_unbount_...) may fail. And you bail
>
>> I am removing the mmio handlers in the error
>> legs in domain_vpl011_init().
>
>
> Xen does not have any helper to revert the behavior of register_mmio_handler
> and I don't seem to introduce why. So how do you do it?
>
> Anyway, you will not need to worry about removing MMIO handler if you move
> the call after all the call that may fail.
>
I will move this call to the last.

>>>
>>>> +
>>>> +    spin_lock_init(&vpl011->lock);
>>>> +
>>>> +    rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid,
>>>> +                                         vpl011_notification);
>>>> +    if ( rc < 0 )
>>>
>>>
>>> You
>>
>> I think this is a type.
>
>
> hmmm likely.
>
>
>>
>>>>
>>>> +        goto out2;
>>>> +
>>>> +    vpl011->evtchn = info->evtchn = rc;
>>>> +
>>>> +    return 0;
>>>> +
>>>> +out2:
>>>> +    xfree(d->arch.vmmio.handlers);
>>>> +    vgic_free_virq(d, GUEST_VPL011_SPI);
>>>> +
>>>> +out1:
>>>> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
>>>> +
>>>> +out:
>>>> +    return rc;
>>>> +}
>>>> +
>>>> +void domain_vpl011_deinit(struct domain *d)
>>>> +{
>>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>>> +
>>>> +    if ( !vpl011->ring_buf )
>>>
>>>
>>>
>>> You will bail out if ring_buf is NULL. However, if you called
>>> domain_vpl011_init first and it failed, you may have ring_buf set but the
>>> rest not fully updated. This means that you will free garbagge.
>>>
>>> I think this could be solved by reinitialize ring_buf if an error occur
>>> in
>>> domain_vpl011_init.
>>
>> destroy_ring_for_helper() sets the first parameter to NULL incase it
>> fails.
>
>
> Fine. I think it is a bit fragile, but I don't see why someone would decide
> to remove it without checking all the callers.
>
> [...]
>
>>>> +#ifdef CONFIG_VPL011_CONSOLE
>>>> +int domain_vpl011_init(struct domain *d,
>>>> +                       struct vpl011_init_info *info);
>>>> +void domain_vpl011_deinit(struct domain *d);
>>>> +#else
>>>> +static inline int domain_vpl011_init(struct domain *d,
>>>> +                                     struct vpl011_init_info *info)
>>>> +{
>>>> +    return -ENOSYS;
>>>> +}
>>>> +
>>>> +static inline void domain_vpl011_deinit(struct domain *d) { }
>>>> +#endif
>>>> +
>>>> +#endif
>>>> +
>>>
>>>
>>>
>>> Please drop this newline.
>>
>> You mean the newline between the #endifs or after the last #endif?
>
>
> Yes.
ok. I have removed the newline between the endifs.

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-06 23:26   ` Stefano Stabellini
  2017-06-09 14:06     ` Julien Grall
@ 2017-06-14  7:35     ` Bhupinder Thakur
  2017-06-14  8:34       ` Bhupinder Thakur
  1 sibling, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-14  7:35 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall, Ian Jackson, Wei Liu

Hi Stefano,

On 7 June 2017 at 04:56, Stefano Stabellini <sstabellini@kernel.org> wrote:
>>  static int set_vnuma_info(libxl__gc *gc, uint32_t domid,
>> @@ -788,6 +791,7 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
>>      if (xc_dom_translated(dom)) {
>>          state->console_mfn = dom->console_pfn;
>>          state->store_mfn = dom->xenstore_pfn;
>> +        state->vuart_gfn = dom->vuart_gfn;
>>      } else {
>>          state->console_mfn = xc_dom_p2m(dom, dom->console_pfn);
>>          state->store_mfn = xc_dom_p2m(dom, dom->xenstore_pfn);
>
> vuart_gfn was introduced in patch #4, why are we setting it only now?

I think this change can be moved to patch #5, which initializes
dom->vuart_gfn, which is required for this change.

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-14  7:35     ` Bhupinder Thakur
@ 2017-06-14  8:34       ` Bhupinder Thakur
  0 siblings, 0 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-14  8:34 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall, Ian Jackson, Wei Liu

On 14 June 2017 at 13:05, Bhupinder Thakur <bhupinder.thakur@linaro.org> wrote:
> Hi Stefano,
>
> On 7 June 2017 at 04:56, Stefano Stabellini <sstabellini@kernel.org> wrote:
>>>  static int set_vnuma_info(libxl__gc *gc, uint32_t domid,
>>> @@ -788,6 +791,7 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
>>>      if (xc_dom_translated(dom)) {
>>>          state->console_mfn = dom->console_pfn;
>>>          state->store_mfn = dom->xenstore_pfn;
>>> +        state->vuart_gfn = dom->vuart_gfn;
>>>      } else {
>>>          state->console_mfn = xc_dom_p2m(dom, dom->console_pfn);
>>>          state->store_mfn = xc_dom_p2m(dom, dom->xenstore_pfn);
>>
>> vuart_gfn was introduced in patch #4, why are we setting it only now?
>
> I think this change can be moved to patch #5, which initializes
> dom->vuart_gfn, which is required for this change.

I will move this change to patch #4 only and move patch #4 after patch #5.

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-09 14:13   ` Julien Grall
@ 2017-06-14  9:16     ` Bhupinder Thakur
  2017-06-14 10:15       ` Julien Grall
  0 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-14  9:16 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu

Hi Julien,


>> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
>> index 1629f41..77425dd 100644
>> --- a/tools/libxc/include/xenctrl.h
>> +++ b/tools/libxc/include/xenctrl.h
>> @@ -884,6 +884,23 @@ int xc_vcpu_getcontext(xc_interface *xch,
>>                         uint32_t domid,
>>                         uint32_t vcpu,
>>                         vcpu_guest_context_any_t *ctxt);
>
>
> Newline here please.
>
ok.
> [...]
>
>> diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
>> index 5e1fc60..d1ca9c6 100644
>> --- a/tools/libxl/libxl_arch.h
>> +++ b/tools/libxl/libxl_arch.h
>> @@ -32,6 +32,13 @@ _hidden
>>  int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config
>> *d_config,
>>                 uint32_t domid);
>>
>> +/* arch specific internal domain creation finish function */
>> +_hidden
>> +int libxl__arch_domain_create_finish(libxl__gc *gc,
>> +                                     libxl_domain_build_info *info,
>> +                                     uint32_t domid,
>> +                                     libxl__domain_build_state *state);
>
>
> Can you explain why you need a new arch helper rather than using the current
> one?

libxl__arch_domain_create() is called from libxl__build_pre(). This
function is called before libxl__build_pv(). By this time the domain
has not be created and I found that if I tried to initialize vpl011
from inside libxl__arch_domain_create() then initialization was
failing due to prepare_ring_for_helper() failing.

So I had to create another function which will be called from
libxl__build_post() after domain has been setup.

>
> [...]
>
>> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
>> index 76310ed..9e150ba 100644
>> --- a/xen/arch/arm/domain.c
>> +++ b/xen/arch/arm/domain.c
>> @@ -665,6 +665,8 @@ fail:
>>
>>  void arch_domain_destroy(struct domain *d)
>>  {
>> +    domain_vpl011_deinit(d);
>
>
> Please add a comment explain where the initialization has been done (i.e via
> a DOMCTL). This would make easier to know what's going on.
ok.
>
>> +
>>      /* IOMMU page table is shared with P2M, always call
>>       * iommu_domain_destroy() before p2m_teardown().
>>       */
>> diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
>> index 971caec..741679b 100644
>> --- a/xen/arch/arm/domctl.c
>> +++ b/xen/arch/arm/domctl.c
>> @@ -5,13 +5,15 @@
>>   */
>>
>>  #include <xen/types.h>
>> -#include <xen/lib.h>
>> +#include <public/domctl.h>
>>  #include <xen/errno.h>
>> -#include <xen/sched.h>
>> +#include <xen/guest_access.h>
>>  #include <xen/hypercall.h>
>>  #include <xen/iocap.h>
>> +#include <xen/lib.h>
>> +#include <xen/mm.h>
>> +#include <xen/sched.h>
>>  #include <xsm/xsm.h>
>> -#include <public/domctl.h>
>
>
> Why do you reshuffle the headers? Is it to use the alphabetical order? If
> so, this should really be done in a separate patch.
>
ok. I will introduce a new patch for header files reshuffling.

>
>>
>>  void arch_get_domain_info(const struct domain *d,
>>                            struct xen_domctl_getdomaininfo *info)
>> @@ -119,6 +121,42 @@ long arch_do_domctl(struct xen_domctl *domctl, struct
>> domain *d,
>>          d->disable_migrate = domctl->u.disable_migrate.disable;
>>          return 0;
>>
>> +    case XEN_DOMCTL_vuart_op:
>> +    {
>> +        int rc;
>> +        struct xen_domctl_vuart_op *vuart_op = &domctl->u.vuart_op;
>> +
>> +        switch(vuart_op->cmd)
>> +        {
>> +        case XEN_DOMCTL_VUART_OP_INIT_VPL011:
>> +
>> +            if ( !d->creation_finished )
>> +            {
>> +                struct vpl011_init_info info;
>> +
>> +                info.console_domid = vuart_op->console_domid;
>> +                info.gfn = _gfn(vuart_op->gfn);
>> +
>> +                rc = domain_vpl011_init(d, &info);
>> +                if ( !rc )
>> +                {
>> +                    vuart_op->evtchn = info.evtchn;
>> +                    rc = __copy_to_guest(u_domctl, domctl, 1);
>> +                }
>> +            }
>> +            else
>> +            {
>> +                rc = - EPERM;
>> +            }
>
>
> Unecessary {}.
>
ok.

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-14  5:47         ` Bhupinder Thakur
@ 2017-06-14  9:33           ` Julien Grall
  0 siblings, 0 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-14  9:33 UTC (permalink / raw)
  To: Bhupinder Thakur; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu



On 06/14/2017 06:47 AM, Bhupinder Thakur wrote:
> Hi Julien,

Hi Bhupinder,

> 
>>>>> +}
>>>>> +
>>>>> +static void vpl011_update(struct domain *d)
>>>>> +{
>>>>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>>>>> +
>>>>> +    /*
>>>>> +     * TODO: PL011 interrupts are level triggered which means
>>>>> +     * that interrupt needs to be set/clear instead of being
>>>>> +     * injected. However, currently vGIC does not handle level
>>>>> +     * triggered interrupts properly. This function needs to be
>>>>> +     * revisited once vGIC starts handling level triggered
>>>>> +     * interrupts.
>>>>> +     */
>>>>> +    if ( vpl011->uartris & vpl011->uartimsc )
>>>>
>>>>
>>>>
>>>> The write in uartirs and uartimsc are protected by a lock. Shouldn't it
>>>> be
>>>> the case here too? More that they are not updated atomically.
>>>>
>>>> You probably want to call vpl011_update with vpl011 lock taken to make
>>>> sure
>>>> you don't have any synchronization issue.
>>>
>>>
>>> Since we are just reading the values here, I think it is fine to not
>>> take a lock. The
>>> condition will either be true or false.
>>
>>
>> uartris and uartimsc may not be updated atomically because vreg_reg32_update
>> does not guarantee it.
>>
>> So you may read a wrong value here and potentially inject spurious
>> interrupt. This will get much worse when level will fully be supported as
>> you may switch the level of the interrupt by mistake.
>>
> Ok. I will check this condition under lock. But should I call
> vgic_vcpu_inject_spi() also under the same lock? I think we can do
> like this:
> 
> vpl011_lock();
> mask =  vpl011->uartris & vpl011->uartimsc;
> vpl011_unlock();
> 
> if ( mask )
>     vgic_vcpu_inject_spi();

This is not going to work the day we rework the vGIC to fully support 
level interrupt. If you don't protect vgic_vcpu_inject_spi(), you may 
lower the level by mistake.

As mentioned on a previous mail, I would prefer if vpl011_update is 
called with the lock taken.

[...]

>> How do you know the compiler will generate assembly which contain the data
>> dependency?
>>
>> Likely it will not be the case because in_cons will be used indirectly as we
>> mask it first.
>>
>>> The memory barrier
>>> after the 3 statements ensures that intf->in_cons is updated before
>>> proceeding ahead.
>>
>>
>> Can you explain why?
>>
>> IHMO, what matter here is in_cons to be written after intf->in[...] is read.
>> Otherwise the backend may see in_cons before the character has effectively
>> been read.
>>
> ok. The issue is that the other end (xenconsole running on maybe some
> other CPU) may see the increment operation first before the read
> operation could complete (due to some quirk of memory/cache
> architecture) even though the CPU running the mmio_read() will see the
> effect in the correct order only.

It is not about quirk of memory/cache but data access ordering at the 
processor level. A processor is free to re-order the access if it is 
more efficient. That's why you have the mb/smp_mb barrier to tell the 
processor to no do that.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-14  9:16     ` Bhupinder Thakur
@ 2017-06-14 10:15       ` Julien Grall
  2017-06-15  6:33         ` Bhupinder Thakur
  0 siblings, 1 reply; 65+ messages in thread
From: Julien Grall @ 2017-06-14 10:15 UTC (permalink / raw)
  To: Bhupinder Thakur; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu



On 06/14/2017 10:16 AM, Bhupinder Thakur wrote:
> Hi Julien,

Hi Bhupinder,

> 
>>> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
>>> index 1629f41..77425dd 100644
>>> --- a/tools/libxc/include/xenctrl.h
>>> +++ b/tools/libxc/include/xenctrl.h
>>> @@ -884,6 +884,23 @@ int xc_vcpu_getcontext(xc_interface *xch,
>>>                          uint32_t domid,
>>>                          uint32_t vcpu,
>>>                          vcpu_guest_context_any_t *ctxt);
>>
>>
>> Newline here please.
>>
> ok.
>> [...]
>>
>>> diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
>>> index 5e1fc60..d1ca9c6 100644
>>> --- a/tools/libxl/libxl_arch.h
>>> +++ b/tools/libxl/libxl_arch.h
>>> @@ -32,6 +32,13 @@ _hidden
>>>   int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config
>>> *d_config,
>>>                  uint32_t domid);
>>>
>>> +/* arch specific internal domain creation finish function */
>>> +_hidden
>>> +int libxl__arch_domain_create_finish(libxl__gc *gc,
>>> +                                     libxl_domain_build_info *info,
>>> +                                     uint32_t domid,
>>> +                                     libxl__domain_build_state *state);
>>
>>
>> Can you explain why you need a new arch helper rather than using the current
>> one?
> 
> libxl__arch_domain_create() is called from libxl__build_pre(). This
> function is called before libxl__build_pv(). By this time the domain
> has not be created and I found that if I tried to initialize vpl011
> from inside libxl__arch_domain_create() then initialization was
> failing due to prepare_ring_for_helper() failing.

What do you mean by the domain has not been created? The domain has 
already been created (you have a domid in hand) when you 
libxl__build_pre. So the problem is different.

Looking at the code, I guess the problem is because the vuart pfn will 
be allocated by xc_dom_build_image called by libxl_build_pv -> 
libxl__build_dom.

> 
> So I had to create another function which will be called from
> libxl__build_post() after domain has been setup.

It looks a bit odd to me to create the vpl011 UART that late in the 
process because when you read the code you would expect all the hardware 
to be setup after libxl__arch_domain_finalise_hw_descriptions is called.

But I understand it is not possible to do it as the ring has not yet 
been allocated. So is there a way to allocate the ring before?

Wei, Ian, do you have any opinions on what should the workflow in libxl?

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-14 10:15       ` Julien Grall
@ 2017-06-15  6:33         ` Bhupinder Thakur
  2017-06-19 10:59           ` Bhupinder Thakur
  0 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-15  6:33 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu

Hi Julien,


>>>> diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
>>>> index 5e1fc60..d1ca9c6 100644
>>>> --- a/tools/libxl/libxl_arch.h
>>>> +++ b/tools/libxl/libxl_arch.h
>>>> @@ -32,6 +32,13 @@ _hidden
>>>>   int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config
>>>> *d_config,
>>>>                  uint32_t domid);
>>>>
>>>> +/* arch specific internal domain creation finish function */
>>>> +_hidden
>>>> +int libxl__arch_domain_create_finish(libxl__gc *gc,
>>>> +                                     libxl_domain_build_info *info,
>>>> +                                     uint32_t domid,
>>>> +                                     libxl__domain_build_state *state);
>>>
>>>
>>>
>>> Can you explain why you need a new arch helper rather than using the
>>> current
>>> one?
>>
>>
>> libxl__arch_domain_create() is called from libxl__build_pre(). This
>> function is called before libxl__build_pv(). By this time the domain
>> has not be created and I found that if I tried to initialize vpl011
>> from inside libxl__arch_domain_create() then initialization was
>> failing due to prepare_ring_for_helper() failing.
>
>
> What do you mean by the domain has not been created? The domain has already
> been created (you have a domid in hand) when you libxl__build_pre. So the
> problem is different.
>
> Looking at the code, I guess the problem is because the vuart pfn will be
> allocated by xc_dom_build_image called by libxl_build_pv ->
> libxl__build_dom.
>
>>
>> So I had to create another function which will be called from
>> libxl__build_post() after domain has been setup.
>
>
> It looks a bit odd to me to create the vpl011 UART that late in the process
> because when you read the code you would expect all the hardware to be setup
> after libxl__arch_domain_finalise_hw_descriptions is called.
>
> But I understand it is not possible to do it as the ring has not yet been
> allocated. So is there a way to allocate the ring before?
 >
> Wei, Ian, do you have any opinions on what should the workflow in libxl?

Actually, I had introduced an API xc_get_vuart_gfn() to get the pfn.
Since it is a fixed pfn, the API can
return it even before xc_build_dom_image() is called. I tried after
moving the vpl011_init function to libxl__arch_domain_create() and it
is working.

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h
  2017-06-06 17:25 ` [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h Bhupinder Thakur
  2017-06-09 12:54   ` Julien Grall
@ 2017-06-19  9:33   ` Andre Przywara
  2017-06-19 16:53     ` Bhupinder Thakur
  1 sibling, 1 reply; 65+ messages in thread
From: Andre Przywara @ 2017-06-19  9:33 UTC (permalink / raw)
  To: Bhupinder Thakur, xen-devel; +Cc: Julien Grall, Stefano Stabellini

Hi Bhupinder,

I think the commit message is a bit misleading.
Actually you *rename* functions and their call sites, and also this
touches the VGIC code, so shouldn't it mention both in the first line of
the commit message? After all this patch really has not much to do with
vpl011.

On 06/06/17 18:25, Bhupinder Thakur wrote:
> This patch redefines the vgic_reg* access functions to vreg_reg* functions.
> These are generic functions, which will be used by the vgic emulation code
> to access the vgic registers.
> 
> PL011 emulation code will also use vreg_reg* access functions.

Also I am sorry to be the bearer of bad news (and also for being the
origin of this), but I am afraid you have to rework this when you rebase
it against origin/staging, since the ITS emulation has been merged.
So while actual conflicts seem to be trivial, there are now many new
users of vgic_reg??_* which you have to change as well.
Should be rather mechanical, though.

Cheers,
Andre.

> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ss
> CC: jg
> 
> Changes since v3:
> - Renamed DEFINE_VREG_REG_HELPERS to VREG_REG_HELPERS.
> 
>  xen/arch/arm/vgic-v2.c     |  28 +++++------
>  xen/arch/arm/vgic-v3.c     |  40 ++++++++--------
>  xen/include/asm-arm/vreg.h | 115 ++++++++++++++++++++++-----------------------
>  3 files changed, 91 insertions(+), 92 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
> index dc9f95b..3e35a90 100644
> --- a/xen/arch/arm/vgic-v2.c
> +++ b/xen/arch/arm/vgic-v2.c
> @@ -179,7 +179,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>      case VREG32(GICD_CTLR):
>          if ( dabt.size != DABT_WORD ) goto bad_width;
>          vgic_lock(v);
> -        *r = vgic_reg32_extract(v->domain->arch.vgic.ctlr, info);
> +        *r = vreg_reg32_extract(v->domain->arch.vgic.ctlr, info);
>          vgic_unlock(v);
>          return 1;
>  
> @@ -194,7 +194,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>              | DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32);
>          vgic_unlock(v);
>  
> -        *r = vgic_reg32_extract(typer, info);
> +        *r = vreg_reg32_extract(typer, info);
>  
>          return 1;
>      }
> @@ -205,7 +205,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>           * XXX Do we need a JEP106 manufacturer ID?
>           * Just use the physical h/w value for now
>           */
> -        *r = vgic_reg32_extract(0x0000043b, info);
> +        *r = vreg_reg32_extract(0x0000043b, info);
>          return 1;
>  
>      case VRANGE32(0x00C, 0x01C):
> @@ -226,7 +226,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>          rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ISENABLER, DABT_WORD);
>          if ( rank == NULL) goto read_as_zero;
>          vgic_lock_rank(v, rank, flags);
> -        *r = vgic_reg32_extract(rank->ienable, info);
> +        *r = vreg_reg32_extract(rank->ienable, info);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
>  
> @@ -235,7 +235,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>          rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICENABLER, DABT_WORD);
>          if ( rank == NULL) goto read_as_zero;
>          vgic_lock_rank(v, rank, flags);
> -        *r = vgic_reg32_extract(rank->ienable, info);
> +        *r = vreg_reg32_extract(rank->ienable, info);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
>  
> @@ -262,7 +262,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>                                                       gicd_reg - GICD_IPRIORITYR,
>                                                       DABT_WORD)];
>          vgic_unlock_rank(v, rank, flags);
> -        *r = vgic_reg32_extract(ipriorityr, info);
> +        *r = vreg_reg32_extract(ipriorityr, info);
>  
>          return 1;
>      }
> @@ -280,7 +280,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>          vgic_lock_rank(v, rank, flags);
>          itargetsr = vgic_fetch_itargetsr(rank, gicd_reg - GICD_ITARGETSR);
>          vgic_unlock_rank(v, rank, flags);
> -        *r = vgic_reg32_extract(itargetsr, info);
> +        *r = vreg_reg32_extract(itargetsr, info);
>  
>          return 1;
>      }
> @@ -299,7 +299,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>          icfgr = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR, DABT_WORD)];
>          vgic_unlock_rank(v, rank, flags);
>  
> -        *r = vgic_reg32_extract(icfgr, info);
> +        *r = vreg_reg32_extract(icfgr, info);
>  
>          return 1;
>      }
> @@ -424,7 +424,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>          if ( dabt.size != DABT_WORD ) goto bad_width;
>          /* Ignore all but the enable bit */
>          vgic_lock(v);
> -        vgic_reg32_update(&v->domain->arch.vgic.ctlr, r, info);
> +        vreg_reg32_update(&v->domain->arch.vgic.ctlr, r, info);
>          v->domain->arch.vgic.ctlr &= GICD_CTL_ENABLE;
>          vgic_unlock(v);
>  
> @@ -454,7 +454,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>          if ( rank == NULL) goto write_ignore;
>          vgic_lock_rank(v, rank, flags);
>          tr = rank->ienable;
> -        vgic_reg32_setbits(&rank->ienable, r, info);
> +        vreg_reg32_setbits(&rank->ienable, r, info);
>          vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
> @@ -465,7 +465,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>          if ( rank == NULL) goto write_ignore;
>          vgic_lock_rank(v, rank, flags);
>          tr = rank->ienable;
> -        vgic_reg32_clearbits(&rank->ienable, r, info);
> +        vreg_reg32_clearbits(&rank->ienable, r, info);
>          vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
> @@ -508,7 +508,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>          ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8,
>                                                        gicd_reg - GICD_IPRIORITYR,
>                                                        DABT_WORD)];
> -        vgic_reg32_update(ipriorityr, r, info);
> +        vreg_reg32_update(ipriorityr, r, info);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
>      }
> @@ -529,7 +529,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>          if ( rank == NULL) goto write_ignore;
>          vgic_lock_rank(v, rank, flags);
>          itargetsr = vgic_fetch_itargetsr(rank, gicd_reg - GICD_ITARGETSR);
> -        vgic_reg32_update(&itargetsr, r, info);
> +        vreg_reg32_update(&itargetsr, r, info);
>          vgic_store_itargetsr(v->domain, rank, gicd_reg - GICD_ITARGETSR,
>                               itargetsr);
>          vgic_unlock_rank(v, rank, flags);
> @@ -551,7 +551,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>          rank = vgic_rank_offset(v, 2, gicd_reg - GICD_ICFGR, DABT_WORD);
>          if ( rank == NULL) goto write_ignore;
>          vgic_lock_rank(v, rank, flags);
> -        vgic_reg32_update(&rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR,
> +        vreg_reg32_update(&rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR,
>                                                       DABT_WORD)],
>                            r, info);
>          vgic_unlock_rank(v, rank, flags);
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> index d10757a..e1213d9 100644
> --- a/xen/arch/arm/vgic-v3.c
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -181,7 +181,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
>  
>      case VREG32(GICR_IIDR):
>          if ( dabt.size != DABT_WORD ) goto bad_width;
> -        *r = vgic_reg32_extract(GICV3_GICR_IIDR_VAL, info);
> +        *r = vreg_reg32_extract(GICV3_GICR_IIDR_VAL, info);
>          return 1;
>  
>      case VREG64(GICR_TYPER):
> @@ -199,7 +199,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
>          if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST )
>              typer |= GICR_TYPER_LAST;
>  
> -        *r = vgic_reg64_extract(typer, info);
> +        *r = vreg_reg64_extract(typer, info);
>  
>          return 1;
>      }
> @@ -257,7 +257,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
>      case VREG32(GICR_SYNCR):
>          if ( dabt.size != DABT_WORD ) goto bad_width;
>          /* RO . But when read it always returns busy bito bit[0] */
> -        *r = vgic_reg32_extract(GICR_SYNCR_NOT_BUSY, info);
> +        *r = vreg_reg32_extract(GICR_SYNCR_NOT_BUSY, info);
>          return 1;
>  
>      case 0x00C8:
> @@ -284,7 +284,7 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
>  
>      case VREG32(GICR_PIDR2):
>          if ( dabt.size != DABT_WORD ) goto bad_width;
> -        *r = vgic_reg32_extract(GICV3_GICR_PIDR2, info);
> +        *r = vreg_reg32_extract(GICV3_GICR_PIDR2, info);
>           return 1;
>  
>      case 0xFFEC ... 0xFFFC:
> @@ -328,7 +328,7 @@ read_reserved:
>      return 1;
>  
>  read_unknown:
> -    *r = vgic_reg64_extract(0xdeadbeafdeadbeaf, info);
> +    *r = vreg_reg64_extract(0xdeadbeafdeadbeaf, info);
>      return 1;
>  }
>  
> @@ -489,7 +489,7 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
>          rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
>          if ( rank == NULL ) goto read_as_zero;
>          vgic_lock_rank(v, rank, flags);
> -        *r = vgic_reg32_extract(rank->ienable, info);
> +        *r = vreg_reg32_extract(rank->ienable, info);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
>  
> @@ -498,7 +498,7 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
>          rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
>          if ( rank == NULL ) goto read_as_zero;
>          vgic_lock_rank(v, rank, flags);
> -        *r = vgic_reg32_extract(rank->ienable, info);
> +        *r = vreg_reg32_extract(rank->ienable, info);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
>  
> @@ -525,7 +525,7 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
>                                                       DABT_WORD)];
>          vgic_unlock_rank(v, rank, flags);
>  
> -        *r = vgic_reg32_extract(ipriorityr, info);
> +        *r = vreg_reg32_extract(ipriorityr, info);
>  
>          return 1;
>      }
> @@ -541,7 +541,7 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v,
>          icfgr = rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, DABT_WORD)];
>          vgic_unlock_rank(v, rank, flags);
>  
> -        *r = vgic_reg32_extract(icfgr, info);
> +        *r = vreg_reg32_extract(icfgr, info);
>  
>          return 1;
>      }
> @@ -585,7 +585,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
>          if ( rank == NULL ) goto write_ignore;
>          vgic_lock_rank(v, rank, flags);
>          tr = rank->ienable;
> -        vgic_reg32_setbits(&rank->ienable, r, info);
> +        vreg_reg32_setbits(&rank->ienable, r, info);
>          vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
> @@ -596,7 +596,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
>          if ( rank == NULL ) goto write_ignore;
>          vgic_lock_rank(v, rank, flags);
>          tr = rank->ienable;
> -        vgic_reg32_clearbits(&rank->ienable, r, info);
> +        vreg_reg32_clearbits(&rank->ienable, r, info);
>          vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
> @@ -638,7 +638,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
>          vgic_lock_rank(v, rank, flags);
>          ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8, reg - GICD_IPRIORITYR,
>                                                        DABT_WORD)];
> -        vgic_reg32_update(ipriorityr, r, info);
> +        vreg_reg32_update(ipriorityr, r, info);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
>      }
> @@ -653,7 +653,7 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v,
>          rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD);
>          if ( rank == NULL ) goto write_ignore;
>          vgic_lock_rank(v, rank, flags);
> -        vgic_reg32_update(&rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR,
> +        vreg_reg32_update(&rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR,
>                                                       DABT_WORD)],
>                            r, info);
>          vgic_unlock_rank(v, rank, flags);
> @@ -901,7 +901,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>      case VREG32(GICD_CTLR):
>          if ( dabt.size != DABT_WORD ) goto bad_width;
>          vgic_lock(v);
> -        *r = vgic_reg32_extract(v->domain->arch.vgic.ctlr, info);
> +        *r = vreg_reg32_extract(v->domain->arch.vgic.ctlr, info);
>          vgic_unlock(v);
>          return 1;
>  
> @@ -926,14 +926,14 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>  
>          typer |= (irq_bits - 1) << GICD_TYPE_ID_BITS_SHIFT;
>  
> -        *r = vgic_reg32_extract(typer, info);
> +        *r = vreg_reg32_extract(typer, info);
>  
>          return 1;
>      }
>  
>      case VREG32(GICD_IIDR):
>          if ( dabt.size != DABT_WORD ) goto bad_width;
> -        *r = vgic_reg32_extract(GICV3_GICD_IIDR_VAL, info);
> +        *r = vreg_reg32_extract(GICV3_GICD_IIDR_VAL, info);
>          return 1;
>  
>      case VREG32(0x000C):
> @@ -1026,7 +1026,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>          irouter = vgic_fetch_irouter(rank, gicd_reg - GICD_IROUTER);
>          vgic_unlock_rank(v, rank, flags);
>  
> -        *r = vgic_reg64_extract(irouter, info);
> +        *r = vreg_reg64_extract(irouter, info);
>  
>          return 1;
>      }
> @@ -1044,7 +1044,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
>      case VREG32(GICD_PIDR2):
>          /* GICv3 identification value */
>          if ( dabt.size != DABT_WORD ) goto bad_width;
> -        *r = vgic_reg32_extract(GICV3_GICD_PIDR2, info);
> +        *r = vreg_reg32_extract(GICV3_GICD_PIDR2, info);
>          return 1;
>  
>      case VRANGE32(0xFFEC, 0xFFFC):
> @@ -1107,7 +1107,7 @@ static int vgic_v3_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>  
>          vgic_lock(v);
>  
> -        vgic_reg32_update(&ctlr, r, info);
> +        vreg_reg32_update(&ctlr, r, info);
>  
>          /* Only EnableGrp1A can be changed */
>          if ( ctlr & GICD_CTLR_ENABLE_G1A )
> @@ -1213,7 +1213,7 @@ static int vgic_v3_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
>          if ( rank == NULL ) goto write_ignore;
>          vgic_lock_rank(v, rank, flags);
>          irouter = vgic_fetch_irouter(rank, gicd_reg - GICD_IROUTER);
> -        vgic_reg64_update(&irouter, r, info);
> +        vreg_reg64_update(&irouter, r, info);
>          vgic_store_irouter(v->domain, rank, gicd_reg - GICD_IROUTER, irouter);
>          vgic_unlock_rank(v, rank, flags);
>          return 1;
> diff --git a/xen/include/asm-arm/vreg.h b/xen/include/asm-arm/vreg.h
> index 348584f..16207ce 100644
> --- a/xen/include/asm-arm/vreg.h
> +++ b/xen/include/asm-arm/vreg.h
> @@ -107,102 +107,102 @@ static inline bool vreg_emulate_sysreg64(struct cpu_user_regs *regs, union hsr h
>  
>  #endif
>  
> -#define VGIC_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
> +#define VREG_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
>  
>  /*
>   * The check on the size supported by the register has to be done by
> - * the caller of vgic_regN_*.
> + * the caller of vreg_regN_*.
>   *
> - * vgic_reg_* should never be called directly. Instead use the vgic_regN_*
> + * vreg_reg_* should never be called directly. Instead use the vreg_regN_*
>   * according to size of the emulated register
>   *
>   * Note that the alignment fault will always be taken in the guest
>   * (see B3.12.7 DDI0406.b).
>   */
> -static inline register_t vgic_reg_extract(unsigned long reg,
> +static inline register_t vreg_reg_extract(unsigned long reg,
>                                            unsigned int offset,
>                                            enum dabt_size size)
>  {
>      reg >>= 8 * offset;
> -    reg &= VGIC_REG_MASK(size);
> +    reg &= VREG_REG_MASK(size);
>  
>      return reg;
>  }
>  
> -static inline void vgic_reg_update(unsigned long *reg, register_t val,
> +static inline void vreg_reg_update(unsigned long *reg, register_t val,
>                                     unsigned int offset,
>                                     enum dabt_size size)
>  {
> -    unsigned long mask = VGIC_REG_MASK(size);
> +    unsigned long mask = VREG_REG_MASK(size);
>      int shift = offset * 8;
>  
>      *reg &= ~(mask << shift);
>      *reg |= ((unsigned long)val & mask) << shift;
>  }
>  
> -static inline void vgic_reg_setbits(unsigned long *reg, register_t bits,
> +static inline void vreg_reg_setbits(unsigned long *reg, register_t bits,
>                                      unsigned int offset,
>                                      enum dabt_size size)
>  {
> -    unsigned long mask = VGIC_REG_MASK(size);
> +    unsigned long mask = VREG_REG_MASK(size);
>      int shift = offset * 8;
>  
>      *reg |= ((unsigned long)bits & mask) << shift;
>  }
>  
> -static inline void vgic_reg_clearbits(unsigned long *reg, register_t bits,
> +static inline void vreg_reg_clearbits(unsigned long *reg, register_t bits,
>                                        unsigned int offset,
>                                        enum dabt_size size)
>  {
> -    unsigned long mask = VGIC_REG_MASK(size);
> +    unsigned long mask = VREG_REG_MASK(size);
>      int shift = offset * 8;
>  
>      *reg &= ~(((unsigned long)bits & mask) << shift);
>  }
>  
> -/* N-bit register helpers */
> -#define VGIC_REG_HELPERS(sz, offmask)                                   \
> -static inline register_t vgic_reg##sz##_extract(uint##sz##_t reg,       \
> -                                                const mmio_info_t *info)\
> -{                                                                       \
> -    return vgic_reg_extract(reg, info->gpa & offmask,                   \
> -                            info->dabt.size);                           \
> -}                                                                       \
> -                                                                        \
> -static inline void vgic_reg##sz##_update(uint##sz##_t *reg,             \
> -                                         register_t val,                \
> -                                         const mmio_info_t *info)       \
> -{                                                                       \
> -    unsigned long tmp = *reg;                                           \
> -                                                                        \
> -    vgic_reg_update(&tmp, val, info->gpa & offmask,                     \
> -                    info->dabt.size);                                   \
> -                                                                        \
> -    *reg = tmp;                                                         \
> -}                                                                       \
> -                                                                        \
> -static inline void vgic_reg##sz##_setbits(uint##sz##_t *reg,            \
> -                                          register_t bits,              \
> -                                          const mmio_info_t *info)      \
> -{                                                                       \
> -    unsigned long tmp = *reg;                                           \
> -                                                                        \
> -    vgic_reg_setbits(&tmp, bits, info->gpa & offmask,                   \
> -                     info->dabt.size);                                  \
> -                                                                        \
> -    *reg = tmp;                                                         \
> -}                                                                       \
> -                                                                        \
> -static inline void vgic_reg##sz##_clearbits(uint##sz##_t *reg,          \
> -                                            register_t bits,            \
> -                                            const mmio_info_t *info)    \
> -{                                                                       \
> -    unsigned long tmp = *reg;                                           \
> -                                                                        \
> -    vgic_reg_clearbits(&tmp, bits, info->gpa & offmask,                 \
> -                       info->dabt.size);                                \
> -                                                                        \
> -    *reg = tmp;                                                         \
> +#define VREG_REG_HELPERS(sz, offmask)                                           \
> +/* N-bit register helpers */                                                    \
> +static inline register_t vreg_reg##sz##_extract(uint##sz##_t reg,               \
> +                                                  const mmio_info_t *info)      \
> +{                                                                               \
> +    return vreg_reg_extract(reg, info->gpa & offmask,                           \
> +                            info->dabt.size);                                   \
> +}                                                                               \
> +                                                                                \
> +static inline void vreg_reg##sz##_update(uint##sz##_t *reg,                     \
> +                                           register_t val,                      \
> +                                           const mmio_info_t *info)             \
> +{                                                                               \
> +    unsigned long tmp = *reg;                                                   \
> +                                                                                \
> +    vreg_reg_update(&tmp, val, info->gpa & offmask,                             \
> +                    info->dabt.size);                                           \
> +                                                                                \
> +    *reg = tmp;                                                                 \
> +}                                                                               \
> +                                                                                \
> +static inline void vreg_reg##sz##_setbits(uint##sz##_t *reg,                    \
> +                                            register_t bits,                    \
> +                                            const mmio_info_t *info)            \
> +{                                                                               \
> +    unsigned long tmp = *reg;                                                   \
> +                                                                                \
> +    vreg_reg_setbits(&tmp, bits, info->gpa & offmask,                           \
> +                     info->dabt.size);                                          \
> +                                                                                \
> +    *reg = tmp;                                                                 \
> +}                                                                               \
> +                                                                                \
> +static inline void vreg_reg##sz##_clearbits(uint##sz##_t *reg,                  \
> +                                              register_t bits,                  \
> +                                              const mmio_info_t *info)          \
> +{                                                                               \
> +    unsigned long tmp = *reg;                                                   \
> +                                                                                \
> +    vreg_reg_clearbits(&tmp, bits, info->gpa & offmask,                         \
> +                       info->dabt.size);                                        \
> +                                                                                \
> +    *reg = tmp;                                                                 \
>  }
>  
>  /*
> @@ -211,10 +211,9 @@ static inline void vgic_reg##sz##_clearbits(uint##sz##_t *reg,          \
>   * unsigned long rather than uint64_t
>   */
>  #if BITS_PER_LONG == 64
> -VGIC_REG_HELPERS(64, 0x7);
> +VREG_REG_HELPERS(64, 0x7);
>  #endif
> -VGIC_REG_HELPERS(32, 0x3);
> -
> -#undef VGIC_REG_HELPERS
> +VREG_REG_HELPERS(32, 0x3);
> +#undef VREG_REG_HELPERS
>  
>  #endif /* __ASM_ARM_VREG__ */
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-06 17:25 ` [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen Bhupinder Thakur
  2017-06-06 23:02   ` Stefano Stabellini
  2017-06-09 13:54   ` Julien Grall
@ 2017-06-19 10:14   ` Andre Przywara
  2017-06-22  5:16     ` Bhupinder Thakur
  2017-06-23 12:45     ` Julien Grall
  2 siblings, 2 replies; 65+ messages in thread
From: Andre Przywara @ 2017-06-19 10:14 UTC (permalink / raw)
  To: Bhupinder Thakur, xen-devel
  Cc: Ian Jackson, Julien Grall, Stefano Stabellini, Wei Liu

Hi,

On 06/06/17 18:25, Bhupinder Thakur wrote:
> Add emulation code to emulate read/write access to pl011 registers
> and pl011 interrupts:
> 
>     - Emulate DR read/write by reading and writing from/to the IN
>       and OUT ring buffers and raising an event to the backend when
>       there is data in the OUT ring buffer and injecting an interrupt
>       to the guest when there is data in the IN ring buffer
> 
>     - Other registers are related to interrupt management and
>       essentially control when interrupts are delivered to the guest
> 
> The SBSA compliant pl011 uart is covered in Appendix B of
> https://static.docs.arm.com/den0029/a/Server_Base_System_Architecture_v3_1_ARM_DEN_0029A.pdf
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> CC: ij
> CC: wl
> CC: ss
> CC: jg
> CC: kw
> 
> Changes since v3:
> - Moved the call to DEFINE_XEN_FLEX_RING from vpl011.h to public/console.h. This macro defines
>   standard functions to operate on the ring buffer.
> - Lock taken while updating the interrupt mask and clear registers in mmio_write.
> - Use gfn_t instead of xen_pfn_t.
> - vgic_free_virq called if there is any error in vpl011 initialization.
> - mmio handlers freed if there is any error in vpl011 initialization.
> - Removed vpl011->initialized flag usage as the same check could be done 
>   using vpl011->ring-ref.
> - Used return instead of break in the switch handling of emulation of different pl011 registers.
> - Renamed vpl011_update_spi() to vpl011_update().
> 
> Changes since v2:
> - Use generic vreg_reg* for read/write of registers emulating pl011.
> - Use generic ring buffer functions defined using DEFINE_XEN_FLEX_RING.
> - Renamed the SPI injection function to vpl011_update_spi() to reflect level 
>   triggered nature of pl011 interrupts.
> - The pl011 register access address should always be the base address of the
>   corresponding register as per section B of the SBSA document. For this reason,
>   the register range address access is not allowed.
> 
> Changes since v1:
> - Removed the optimiztion related to sendiing events to xenconsole 
> - Use local variables as ring buffer indices while using the ring buffer
> 
>  tools/console/daemon/io.c        |   2 +-
>  xen/arch/arm/Kconfig             |   5 +
>  xen/arch/arm/Makefile            |   1 +
>  xen/arch/arm/vpl011.c            | 418 +++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/domain.h     |   6 +
>  xen/include/asm-arm/pl011-uart.h |   2 +
>  xen/include/asm-arm/vpl011.h     |  74 +++++++
>  xen/include/public/arch-arm.h    |   6 +
>  xen/include/public/io/console.h  |   4 +
>  9 files changed, 517 insertions(+), 1 deletion(-)
>  create mode 100644 xen/arch/arm/vpl011.c
>  create mode 100644 xen/include/asm-arm/vpl011.h
> 
> diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
> index 7e6a886..947f13a 100644
> --- a/tools/console/daemon/io.c
> +++ b/tools/console/daemon/io.c
> @@ -21,6 +21,7 @@
>  
>  #include "utils.h"
>  #include "io.h"
> +#include <string.h>
>  #include <xenevtchn.h>
>  #include <xengnttab.h>
>  #include <xenstore.h>
> @@ -29,7 +30,6 @@
>  
>  #include <stdlib.h>
>  #include <errno.h>
> -#include <string.h>
>  #include <poll.h>
>  #include <fcntl.h>
>  #include <unistd.h>
> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> index d46b98c..c1a0e7f 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -50,6 +50,11 @@ config HAS_ITS
>          prompt "GICv3 ITS MSI controller support" if EXPERT = "y"
>          depends on HAS_GICV3
>  
> +config VPL011_CONSOLE
> +	bool "Emulated pl011 console support"
> +	default y
> +	---help---
> +	  Allows a guest to use pl011 UART as a console

I admit that I am rather late with this comment, but I am not sure we
should advertise PL011 emulation here.
Technically what you emulate is a "SBSA Generic UART", which is indeed a
subset of the PL011, but really only a subset. You confirm this already
in patch 13/14, where you use the respective compatible name instead of
the generic arm,pl011 one.

So while I don't dare to ask for renaming every identifier, I wonder if
we should at least keep the publicly visible part confined to "SBSA
UART". You could mention the subset nature in the help message here, for
instance.
The same reasoning applies to other parts of this series which introduce
user-visible strings (like in libxl).

>  endmenu
>  
>  menu "ARM errata workaround via the alternative framework"
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 49e1fb2..15efc13 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -52,6 +52,7 @@ obj-y += vm_event.o
>  obj-y += vtimer.o
>  obj-y += vpsci.o
>  obj-y += vuart.o
> +obj-$(CONFIG_VPL011_CONSOLE) += vpl011.o
>  
>  #obj-bin-y += ....o
>  
> diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
> new file mode 100644
> index 0000000..9b1f27e
> --- /dev/null
> +++ b/xen/arch/arm/vpl011.c
> @@ -0,0 +1,418 @@
> +/*
> + * arch/arm/vpl011.c
> + *
> + * Virtual PL011 UART
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <xen/errno.h>
> +#include <xen/event.h>
> +#include <xen/guest_access.h>
> +#include <xen/init.h>
> +#include <xen/lib.h>
> +#include <xen/mm.h>
> +#include <xen/sched.h>
> +#include <public/domctl.h>
> +#include <public/io/console.h>
> +#include <asm-arm/pl011-uart.h>
> +#include <asm-arm/vgic-emul.h>
> +#include <asm-arm/vpl011.h>

I think Julien mentioned this already, but I think you should just use
"#include <asm/.. .h>" here.

> +
> +static bool vpl011_reg32_check_access(struct hsr_dabt dabt)
> +{
> +    return (dabt.size != DABT_DOUBLE_WORD);
> +}
> +
> +static void vpl011_update(struct domain *d)

Can you please rename this function to indicate that it updates the
*interrupt status*? That name as it is rather generic at the moment.

> +{
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    /*
> +     * TODO: PL011 interrupts are level triggered which means
> +     * that interrupt needs to be set/clear instead of being
> +     * injected. However, currently vGIC does not handle level 
> +     * triggered interrupts properly. This function needs to be 
> +     * revisited once vGIC starts handling level triggered 
> +     * interrupts.
> +     */
> +    if ( vpl011->uartris & vpl011->uartimsc )
> +        vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI);

So my understanding is that this is using an edge triggered semantic at
the moment. While this is not what an PL011 actually implements and not
what the driver really expects, this is fine on itself for now.
BUT I think we may want to avoid injecting spurious interrupts now:
If for instance the receive interrupt condition is set and we clear the
transmit interrupt bit, then call this function, it would inject a new
interrupt, although in a edge-triggered world we really wouldn't need to
do anything.
So I believe we would need to have some kind of shadowed interrupt
state, which stores the interrupt condition the guest already knows
about. As soon as we *add* a bit to this state, we inject the SPI.
This would act as a kind of temporary bridge between the level triggered
SBSA/PL011 UART and the edge-only VGIC implementation for now.
Later when the VGIC properly handles level triggered interrupts, this
implementation can be adjusted. But this change should then be confined
to this very function.

> +}
> +
> +static uint8_t vpl011_read_data(struct domain *d)
> +{
> +    unsigned long flags;
> +    uint8_t data = 0;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX in_cons = intf->in_cons;
> +    XENCONS_RING_IDX in_prod = intf->in_prod;
> +
> +    VPL011_LOCK(d, flags);
> +
> +    /*
> +     * 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 )
> +    {
> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
> +        in_cons += 1;
> +        intf->in_cons = in_cons;
> +        smp_mb();
> +    }
> +    else
> +    {
> +        gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer empty\n");
> +    }
> +
> +    if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == 0 )
> +    {
> +        vpl011->uartfr |= RXFE;
> +        vpl011->uartris &= ~RXI;

In a level triggered world you would need to possibly change the status
of the interrupt line here, so a call to (a renamed and fixed)
vpl011_update() function would be due here. To make the transition later
as easy as possible, I'd recommend to implement this shadow interrupt
state as described above and then call the interrupt update function
here already.

> +    }
> +    vpl011->uartfr &= ~RXFF;
> +    VPL011_UNLOCK(d, flags);
> +
> +    return data;
> +}
> +
> +static void vpl011_write_data(struct domain *d, uint8_t data)
> +{
> +    unsigned long flags;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX out_cons = intf->out_cons;
> +    XENCONS_RING_IDX out_prod = intf->out_prod;
> +
> +    VPL011_LOCK(d, flags);
> +
> +    /*
> +     * It is expected that the ring is not full when this function is called
> +     * as the guest is expected to write to the data register only when the
> +     * TXFF flag is not set.
> +     * In case the guest does write even when the TXFF flag is set then the
> +     * data will be silently dropped.
> +     */
> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) !=
> +         sizeof (intf->out) )
> +    {
> +        intf->out[xencons_mask(out_prod, sizeof(intf->out))] = data;
> +        smp_wmb();
> +        out_prod += 1;
> +        intf->out_prod = out_prod;
> +    }
> +    else
> +    {
> +        gprintk(XENLOG_ERR, "vpl011: Unexpected OUT ring buffer full\n");
> +    }
> +
> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) ==
> +         sizeof (intf->out) )
> +    {
> +        vpl011->uartfr |= TXFF;
> +        vpl011->uartris &= ~TXI;

Same as above. Basically whenever you change one of the bits that may
affect the status of the interrupt line, I'd call the update function.

> +    }
> +
> +    vpl011->uartfr |= BUSY;
> +
> +    vpl011->uartfr &= ~TXFE;
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    /*
> +     * Send an event to console backend to indicate that there is 
> +     * data in the OUT ring buffer.
> +     */
> +    notify_via_xen_event_channel(d, vpl011->evtchn);
> +}
> +
> +static int vpl011_mmio_read(struct vcpu *v,
> +                            mmio_info_t *info,
> +                            register_t *r,
> +                            void *priv)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
> +
> +    switch ( vpl011_reg )
> +    {
> +    case DR:
> +        /*
> +         * Since pl011 registers are 32-bit registers, all registers
> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
> +         * accesses.
> +         */
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011_read_data(v->domain), info);
> +        return 1;
> +
> +    case RSR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        /* It always returns 0 as there are no physical errors. */
> +        *r = 0;
> +        return 1;
> +
> +    case FR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartfr, info);
> +        return 1;
> +
> +    case RIS:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartris, info);
> +        return 1;
> +
> +    case MIS:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartris & 
> +                                vpl011->uartimsc, info);

That smells like you need a lock here, since another access could change
either RIS and/or IMSC concurrently.
But as Julien already mentioned, these accesses are prone to races
anyway, since vreg_reg32_extract() is not atomic.
So is it worth to take the lock here just before the whole switch statement?

> +        return 1;
> +
> +    case IMSC:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        *r = vreg_reg32_extract(vpl011->uartimsc, info);
> +        return 1;
> +
> +    case ICR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        /* Only write is valid. */
> +        return 0;
> +
> +    default:
> +        gprintk(XENLOG_ERR, "vpl011: unhandled read r%d offset %#08x\n",
> +                dabt.reg, vpl011_reg);
> +        return 0;
> +    }
> +
> +    return 1;
> +
> +bad_width:
> +    gprintk(XENLOG_ERR, "vpl011: bad read width %d r%d offset %#08x\n",
> +            dabt.size, dabt.reg, vpl011_reg);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +}
> +
> +static int vpl011_mmio_write(struct vcpu *v,
> +                             mmio_info_t *info,
> +                             register_t r,
> +                             void *priv)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
> +    struct domain *d = v->domain;
> +    unsigned long flags;
> +
> +    switch ( vpl011_reg )
> +    {
> +    case DR:
> +    {
> +        uint32_t data = 0;
> +
> +        /*
> +         * Since pl011 registers are 32-bit registers, all registers
> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
> +         * accesses.
> +         */
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        vreg_reg32_update(&data, r, info);
> +        data &= 0xFF;

This is not needed as vpl011_write_data()'s second argument is uint8_t,
so the compiler does this masking anyway.
And even if it wouldn't, you could move this statement into the call.

> +        vpl011_write_data(v->domain, data);
> +        return 1;
> +    }
> +    case RSR: /* Nothing to clear. */
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        return 1; 
> +
> +    case FR:
> +    case RIS:
> +    case MIS:
> +        goto write_ignore;
> +
> +    case IMSC:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        VPL011_LOCK(d, flags);
> +        vreg_reg32_update(&vpl011->uartimsc, r, info);
> +        VPL011_UNLOCK(d, flags);
> +        vpl011_update(v->domain);
> +        return 1;
> +
> +    case ICR:
> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
> +
> +        VPL011_LOCK(d, flags);
> +        vreg_reg32_clearbits(&vpl011->uartris, r, info);

Please call the interrupt status update function here.

> +        VPL011_UNLOCK(d, flags);
> +        vpl011_update(d);
> +        return 1;
> +
> +    default:
> +        gprintk(XENLOG_ERR, "vpl011: unhandled write r%d offset %#08x\n",
> +                dabt.reg, vpl011_reg);
> +        return 0;
> +    }
> +
> +write_ignore:
> +    return 1;
> +
> +bad_width:
> +    gprintk(XENLOG_ERR, "vpl011: bad write width %d r%d offset %#08x\n",
> +            dabt.size, dabt.reg, vpl011_reg);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +}
> +
> +static const struct mmio_handler_ops vpl011_mmio_handler = {
> +    .read = vpl011_mmio_read,
> +    .write = vpl011_mmio_write,
> +};
> +
> +static void vpl011_data_avail(struct domain *d)
> +{
> +    unsigned long flags;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +    struct xencons_interface *intf = vpl011->ring_buf;
> +    XENCONS_RING_IDX in_cons = intf->in_cons;
> +    XENCONS_RING_IDX in_prod = intf->in_prod;
> +    XENCONS_RING_IDX out_cons = intf->out_cons;
> +    XENCONS_RING_IDX out_prod = intf->out_prod;
> +    XENCONS_RING_IDX in_ring_qsize, out_ring_qsize;
> +
> +    VPL011_LOCK(d, flags);
> +
> +    in_ring_qsize = xencons_queued(in_prod,
> +                                   in_cons,
> +                                   sizeof(intf->in));
> +
> +    out_ring_qsize = xencons_queued(out_prod,
> +                                    out_cons,
> +                                    sizeof(intf->out));
> +
> +    /* Update the uart rx state if the buffer is not empty. */
> +    if ( in_ring_qsize != 0 )
> +    {
> +        vpl011->uartfr &= ~RXFE;
> +        if ( in_ring_qsize == sizeof(intf->in) )
> +            vpl011->uartfr |= RXFF;
> +        vpl011->uartris |= RXI;

... and here ...

> +    }
> +
> +    /* Update the uart tx state if the buffer is not full. */
> +    if ( out_ring_qsize != sizeof(intf->out) )
> +    {
> +        vpl011->uartfr &= ~TXFF;
> +        vpl011->uartris |= TXI;

... and here.

I didn't look at the locking issue on the Xen console for now, but might
join this discussion later.

Cheers,
Andre.

> +        if ( out_ring_qsize == 0 )
> +        {
> +            vpl011->uartfr &= ~BUSY;
> +            vpl011->uartfr |= TXFE;
> +        }
> +    }
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    vpl011_update(d);
> +}
> +
> +
> +static void vpl011_notification(struct vcpu *v, unsigned int port)
> +{
> +    vpl011_data_avail(v->domain);
> +}
> +
> +int domain_vpl011_init(struct domain *d, struct vpl011_init_info *info)
> +{
> +    int rc;
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    if ( vpl011->ring_buf )
> +        return 0;
> +
> +    /* Map the guest PFN to Xen address space. */
> +    rc =  prepare_ring_for_helper(d,
> +                                  gfn_x(info->gfn),
> +                                  &vpl011->ring_page,
> +                                  &vpl011->ring_buf);
> +    if ( rc < 0 )
> +        goto out;
> +
> +    rc = vgic_reserve_virq(d, GUEST_VPL011_SPI);
> +    if ( !rc )
> +    {
> +        rc = -EINVAL;
> +        goto out1;
> +    }
> +
> +    register_mmio_handler(d, &vpl011_mmio_handler,
> +                          GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);
> +
> +    spin_lock_init(&vpl011->lock);
> +
> +    rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid,
> +                                         vpl011_notification);
> +    if ( rc < 0 )
> +        goto out2;
> +
> +    vpl011->evtchn = info->evtchn = rc;
> +
> +    return 0;
> +
> +out2:
> +    xfree(d->arch.vmmio.handlers);
> +    vgic_free_virq(d, GUEST_VPL011_SPI);
> +
> +out1:
> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
> +
> +out:
> +    return rc;
> +}
> +
> +void domain_vpl011_deinit(struct domain *d)
> +{
> +    struct vpl011 *vpl011 = &d->arch.vpl011;
> +
> +    if ( !vpl011->ring_buf )
> +        return;
> +
> +    free_xen_event_channel(d, vpl011->evtchn);
> +    destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page);
> +    xfree(d->arch.vmmio.handlers);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 6de8082..91d1061 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -11,6 +11,7 @@
>  #include <public/hvm/params.h>
>  #include <xen/serial.h>
>  #include <xen/rbtree.h>
> +#include <asm-arm/vpl011.h>
>  
>  struct hvm_domain
>  {
> @@ -133,6 +134,11 @@ struct arch_domain
>      struct {
>          uint8_t privileged_call_enabled : 1;
>      } monitor;
> +
> +#ifdef CONFIG_VPL011_CONSOLE
> +    struct vpl011 vpl011;
> +#endif
> +
>  }  __cacheline_aligned;
>  
>  struct arch_vcpu
> diff --git a/xen/include/asm-arm/pl011-uart.h b/xen/include/asm-arm/pl011-uart.h
> index 123f477..57e9ec7 100644
> --- a/xen/include/asm-arm/pl011-uart.h
> +++ b/xen/include/asm-arm/pl011-uart.h
> @@ -49,6 +49,8 @@
>  /* FR bits */
>  #define TXFE   (1<<7) /* TX FIFO empty */
>  #define RXFE   (1<<4) /* RX FIFO empty */
> +#define TXFF   (1<<5) /* TX FIFO full */
> +#define RXFF   (1<<6) /* RX FIFO full */
>  #define BUSY   (1<<3) /* Transmit is not complete */
>  
>  /* LCR_H bits */
> diff --git a/xen/include/asm-arm/vpl011.h b/xen/include/asm-arm/vpl011.h
> new file mode 100644
> index 0000000..b3e332d
> --- /dev/null
> +++ b/xen/include/asm-arm/vpl011.h
> @@ -0,0 +1,74 @@
> +/*
> + * include/xen/vpl011.h
> + *
> + * Virtual PL011 UART
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef _VPL011_H_
> +
> +#define _VPL011_H_
> +
> +#include <public/domctl.h>
> +#include <public/io/ring.h>
> +#include <asm-arm/vreg.h>
> +#include <xen/mm.h>
> +
> +/* helper macros */
> +#define VPL011_LOCK(d,flags) spin_lock_irqsave(&(d)->arch.vpl011.lock, flags)
> +#define VPL011_UNLOCK(d,flags) spin_unlock_irqrestore(&(d)->arch.vpl011.lock, flags)
> +
> +struct vpl011 {
> +    void *ring_buf;
> +    struct page_info *ring_page;
> +    uint32_t    uartfr;     /* Flag register */
> +    uint32_t    uartcr;     /* Control register */
> +    uint32_t    uartimsc;   /* Interrupt mask register*/
> +    uint32_t    uarticr;    /* Interrupt clear register */
> +    uint32_t    uartris;    /* Raw interrupt status register */
> +    uint32_t    uartmis;    /* Masked interrupt register */
> +    spinlock_t  lock;
> +    evtchn_port_t evtchn;
> +};
> +
> +struct vpl011_init_info {
> +    uint32_t console_domid;
> +    gfn_t gfn;
> +    evtchn_port_t evtchn;
> +};
> +
> +#ifdef CONFIG_VPL011_CONSOLE
> +int domain_vpl011_init(struct domain *d,
> +                       struct vpl011_init_info *info);
> +void domain_vpl011_deinit(struct domain *d);
> +#else
> +static inline int domain_vpl011_init(struct domain *d,
> +                                     struct vpl011_init_info *info)
> +{
> +    return -ENOSYS;
> +}
> +
> +static inline void domain_vpl011_deinit(struct domain *d) { }
> +#endif
> +
> +#endif
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
> index bd974fb..85ab665 100644
> --- a/xen/include/public/arch-arm.h
> +++ b/xen/include/public/arch-arm.h
> @@ -410,6 +410,10 @@ typedef uint64_t xen_callback_t;
>  #define GUEST_ACPI_BASE 0x20000000ULL
>  #define GUEST_ACPI_SIZE 0x02000000ULL
>  
> +/* PL011 mappings */
> +#define GUEST_PL011_BASE    0x22000000ULL
> +#define GUEST_PL011_SIZE    0x00001000ULL
> +
>  /*
>   * 16MB == 4096 pages reserved for guest to use as a region to map its
>   * grant table in.
> @@ -444,6 +448,8 @@ typedef uint64_t xen_callback_t;
>  #define GUEST_TIMER_PHYS_NS_PPI 30
>  #define GUEST_EVTCHN_PPI        31
>  
> +#define GUEST_VPL011_SPI        32
> +
>  /* PSCI functions */
>  #define PSCI_cpu_suspend 0
>  #define PSCI_cpu_off     1
> diff --git a/xen/include/public/io/console.h b/xen/include/public/io/console.h
> index e2cd97f..5e45e1c 100644
> --- a/xen/include/public/io/console.h
> +++ b/xen/include/public/io/console.h
> @@ -27,6 +27,8 @@
>  #ifndef __XEN_PUBLIC_IO_CONSOLE_H__
>  #define __XEN_PUBLIC_IO_CONSOLE_H__
>  
> +#include "ring.h"
> +
>  typedef uint32_t XENCONS_RING_IDX;
>  
>  #define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
> @@ -38,6 +40,8 @@ struct xencons_interface {
>      XENCONS_RING_IDX out_cons, out_prod;
>  };
>  
> +DEFINE_XEN_FLEX_RING(xencons);
> +
>  #endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
>  
>  /*
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-15  6:33         ` Bhupinder Thakur
@ 2017-06-19 10:59           ` Bhupinder Thakur
  2017-06-19 11:01             ` Julien Grall
  0 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-19 10:59 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu

Hi Julien,

I was mistaken in my earlier mail about vpl011 init working if it is
moved to libxl__arch_domain_create(). It is failing because as you
have mentioned vuart_pfn is allocated later in xc_dom_build_image().

Can we delay mapping of this page in Xen until the ring buffer is
actually required by the emulation code for reading/writing data. By
that time, the page would have been physically mapped.

Regards,
Bhupinder

On 15 June 2017 at 12:03, Bhupinder Thakur <bhupinder.thakur@linaro.org> wrote:
> Hi Julien,
>
>
>>>>> diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
>>>>> index 5e1fc60..d1ca9c6 100644
>>>>> --- a/tools/libxl/libxl_arch.h
>>>>> +++ b/tools/libxl/libxl_arch.h
>>>>> @@ -32,6 +32,13 @@ _hidden
>>>>>   int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config
>>>>> *d_config,
>>>>>                  uint32_t domid);
>>>>>
>>>>> +/* arch specific internal domain creation finish function */
>>>>> +_hidden
>>>>> +int libxl__arch_domain_create_finish(libxl__gc *gc,
>>>>> +                                     libxl_domain_build_info *info,
>>>>> +                                     uint32_t domid,
>>>>> +                                     libxl__domain_build_state *state);
>>>>
>>>>
>>>>
>>>> Can you explain why you need a new arch helper rather than using the
>>>> current
>>>> one?
>>>
>>>
>>> libxl__arch_domain_create() is called from libxl__build_pre(). This
>>> function is called before libxl__build_pv(). By this time the domain
>>> has not be created and I found that if I tried to initialize vpl011
>>> from inside libxl__arch_domain_create() then initialization was
>>> failing due to prepare_ring_for_helper() failing.
>>
>>
>> What do you mean by the domain has not been created? The domain has already
>> been created (you have a domid in hand) when you libxl__build_pre. So the
>> problem is different.
>>
>> Looking at the code, I guess the problem is because the vuart pfn will be
>> allocated by xc_dom_build_image called by libxl_build_pv ->
>> libxl__build_dom.
>>
>>>
>>> So I had to create another function which will be called from
>>> libxl__build_post() after domain has been setup.
>>
>>
>> It looks a bit odd to me to create the vpl011 UART that late in the process
>> because when you read the code you would expect all the hardware to be setup
>> after libxl__arch_domain_finalise_hw_descriptions is called.
>>
>> But I understand it is not possible to do it as the ring has not yet been
>> allocated. So is there a way to allocate the ring before?
>  >
>> Wei, Ian, do you have any opinions on what should the workflow in libxl?
>
> Actually, I had introduced an API xc_get_vuart_gfn() to get the pfn.
> Since it is a fixed pfn, the API can
> return it even before xc_build_dom_image() is called. I tried after
> moving the vpl011_init function to libxl__arch_domain_create() and it
> is working.
>
> Regards,
> Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-19 10:59           ` Bhupinder Thakur
@ 2017-06-19 11:01             ` Julien Grall
  2017-06-19 11:47               ` Wei Liu
  0 siblings, 1 reply; 65+ messages in thread
From: Julien Grall @ 2017-06-19 11:01 UTC (permalink / raw)
  To: Bhupinder Thakur; +Cc: xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu



On 19/06/17 11:59, Bhupinder Thakur wrote:
> Hi Julien,
>
> I was mistaken in my earlier mail about vpl011 init working if it is
> moved to libxl__arch_domain_create(). It is failing because as you
> have mentioned vuart_pfn is allocated later in xc_dom_build_image().
>
> Can we delay mapping of this page in Xen until the ring buffer is
> actually required by the emulation code for reading/writing data. By
> that time, the page would have been physically mapped.

You would not be able to report an error if you fail to map it. But this 
looks like to me a workaround for a tool problem.

Anyway, as I said, I'd like feedback from the tools maintainers to see 
how we can proceed.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-19 11:01             ` Julien Grall
@ 2017-06-19 11:47               ` Wei Liu
  2017-06-19 13:11                 ` Bhupinder Thakur
  0 siblings, 1 reply; 65+ messages in thread
From: Wei Liu @ 2017-06-19 11:47 UTC (permalink / raw)
  To: Julien Grall
  Cc: Bhupinder Thakur, xen-devel, Stefano Stabellini, Ian Jackson, Wei Liu

On Mon, Jun 19, 2017 at 12:01:32PM +0100, Julien Grall wrote:
> 
> 
> On 19/06/17 11:59, Bhupinder Thakur wrote:
> > Hi Julien,
> > 
> > I was mistaken in my earlier mail about vpl011 init working if it is
> > moved to libxl__arch_domain_create(). It is failing because as you
> > have mentioned vuart_pfn is allocated later in xc_dom_build_image().
> > 
> > Can we delay mapping of this page in Xen until the ring buffer is
> > actually required by the emulation code for reading/writing data. By
> > that time, the page would have been physically mapped.
> 
> You would not be able to report an error if you fail to map it. But this
> looks like to me a workaround for a tool problem.
> 
> Anyway, as I said, I'd like feedback from the tools maintainers to see how
> we can proceed.
> 

Is there a summary of the problem, is there a particular email in this
thread I should look at? Sorry I'm swamped by emails and patches at the
moment.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-19 11:47               ` Wei Liu
@ 2017-06-19 13:11                 ` Bhupinder Thakur
  2017-06-20 11:16                   ` Julien Grall
  0 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-19 13:11 UTC (permalink / raw)
  To: Wei Liu; +Cc: xen-devel, Julien Grall, Stefano Stabellini, Ian Jackson

Hi Wei,

On 19 June 2017 at 17:17, Wei Liu <wei.liu2@citrix.com> wrote:
> On Mon, Jun 19, 2017 at 12:01:32PM +0100, Julien Grall wrote:
>>
>>
>> On 19/06/17 11:59, Bhupinder Thakur wrote:
>> > Hi Julien,
>> >
>> > I was mistaken in my earlier mail about vpl011 init working if it is
>> > moved to libxl__arch_domain_create(). It is failing because as you
>> > have mentioned vuart_pfn is allocated later in xc_dom_build_image().
>> >
>> > Can we delay mapping of this page in Xen until the ring buffer is
>> > actually required by the emulation code for reading/writing data. By
>> > that time, the page would have been physically mapped.
>>
>> You would not be able to report an error if you fail to map it. But this
>> looks like to me a workaround for a tool problem.
>>
>> Anyway, as I said, I'd like feedback from the tools maintainers to see how
>> we can proceed.
>>
>
> Is there a summary of the problem, is there a particular email in this
> thread I should look at? Sorry I'm swamped by emails and patches at the
> moment.

I will summarize the problem.

It was decided to call domain_vpl011_init() from inside
libxl__arch_domain_create() to initialize vpl011. However,
domain_vpl011_init() fails to map the the vuart GFN because it has not
been physically mapped yet by the toolstack.

The following call flows highlights the issue.

libxl__domain_build() ---> libxl__build_pv ---> libxl__build_dom()
----> xc_dom_build_image() ---> alloc_magic_pages() ----> vuart GFN
allocated/mapped here

libxl__domain_build() ----> libxl__build_pre()  ---->
libxl__arch_domain_create() ----> domain_vpl011_init() ---> this call
fails as the vuart GFN has not been physically mapped yet as shown in
the first call flow.

However, libxl__build_pv() is called after libxl__build_pre(). It
means that the domain_vpl011_init() is called before
alloc_magic_pages() is called and hence the initialization fails.

For that reason, I had introduced a new function
libxl__arch_domain_create_finish() which will be called from
libxl__build_post(). I moved the domain_vpl011_init() there. However,
Julien pointed out that vuart should be initialized early in
libxl__arch_domain_create() function.

So the issue is what is the right place to call domain_vpl011_init()?

I hope it clarifies the issue.

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h
  2017-06-19  9:33   ` Andre Przywara
@ 2017-06-19 16:53     ` Bhupinder Thakur
  2017-06-19 16:59       ` Andre Przywara
  0 siblings, 1 reply; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-19 16:53 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

Hi Andre,

On 19 June 2017 at 15:03, Andre Przywara <andre.przywara@arm.com> wrote:
> Hi Bhupinder,
>
> I think the commit message is a bit misleading.
> Actually you *rename* functions and their call sites, and also this
> touches the VGIC code, so shouldn't it mention both in the first line of
> the commit message? After all this patch really has not much to do with
> vpl011.
>
I will modify the commit message to indicate this commit renames
vgic_reg* to vreg_reg*
and modifies all the places where this call is made.

> On 06/06/17 18:25, Bhupinder Thakur wrote:
>> This patch redefines the vgic_reg* access functions to vreg_reg* functions.
>> These are generic functions, which will be used by the vgic emulation code
>> to access the vgic registers.
>>
>> PL011 emulation code will also use vreg_reg* access functions.
>
> Also I am sorry to be the bearer of bad news (and also for being the
> origin of this), but I am afraid you have to rework this when you rebase
> it against origin/staging, since the ITS emulation has been merged.
> So while actual conflicts seem to be trivial, there are now many new
> users of vgic_reg??_* which you have to change as well.
> Should be rather mechanical, though.
>
I will rebase it on origin/staging and merge the changes. How do I
enable ITS code compilation to verify that it is compiling fine with
new
vreg_reg* functions? Is ITS code not compiled in by default?

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h
  2017-06-19 16:53     ` Bhupinder Thakur
@ 2017-06-19 16:59       ` Andre Przywara
  0 siblings, 0 replies; 65+ messages in thread
From: Andre Przywara @ 2017-06-19 16:59 UTC (permalink / raw)
  To: Bhupinder Thakur; +Cc: xen-devel, Julien Grall, Stefano Stabellini

Hi,

On 19/06/17 17:53, Bhupinder Thakur wrote:
> Hi Andre,
> 
> On 19 June 2017 at 15:03, Andre Przywara <andre.przywara@arm.com> wrote:
>> Hi Bhupinder,
>>
>> I think the commit message is a bit misleading.
>> Actually you *rename* functions and their call sites, and also this
>> touches the VGIC code, so shouldn't it mention both in the first line of
>> the commit message? After all this patch really has not much to do with
>> vpl011.
>>
> I will modify the commit message to indicate this commit renames
> vgic_reg* to vreg_reg*
> and modifies all the places where this call is made.

Thanks!

>> On 06/06/17 18:25, Bhupinder Thakur wrote:
>>> This patch redefines the vgic_reg* access functions to vreg_reg* functions.
>>> These are generic functions, which will be used by the vgic emulation code
>>> to access the vgic registers.
>>>
>>> PL011 emulation code will also use vreg_reg* access functions.
>>
>> Also I am sorry to be the bearer of bad news (and also for being the
>> origin of this), but I am afraid you have to rework this when you rebase
>> it against origin/staging, since the ITS emulation has been merged.
>> So while actual conflicts seem to be trivial, there are now many new
>> users of vgic_reg??_* which you have to change as well.
>> Should be rather mechanical, though.
>>
> I will rebase it on origin/staging and merge the changes.

Thanks - and sorry for the mess ;-)

> How do I
> enable ITS code compilation to verify that it is compiling fine with
> new vreg_reg* functions? Is ITS code not compiled in by default?

You need to add "XEN_CONFIG_EXPERT=y" to every make invocation, so both
for any configuration and for the actual build.
If it doesn't prompt you for the ITS, please type:
$ make -C xen menuconfig XEN_CONFIG_EXPERT=y
then select "GICv3 ITS MSI controller support" under "Architecture
Features" (should only be needed once).
You should check xen/.config for having a line with "CONFIG_HAS_ITS=y".

Cheers,
Andre.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-19 13:11                 ` Bhupinder Thakur
@ 2017-06-20 11:16                   ` Julien Grall
  2017-06-20 11:42                     ` Wei Liu
  2017-06-21 10:18                     ` Bhupinder Thakur
  0 siblings, 2 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-20 11:16 UTC (permalink / raw)
  To: Bhupinder Thakur, Wei Liu; +Cc: xen-devel, Stefano Stabellini, Ian Jackson

On 06/19/2017 02:11 PM, Bhupinder Thakur wrote:
> Hi Wei,

Hi Bhupinder,

> On 19 June 2017 at 17:17, Wei Liu <wei.liu2@citrix.com> wrote:
>> On Mon, Jun 19, 2017 at 12:01:32PM +0100, Julien Grall wrote:
>>>
>>>
>>> On 19/06/17 11:59, Bhupinder Thakur wrote:
>>>> Hi Julien,
>>>>
>>>> I was mistaken in my earlier mail about vpl011 init working if it is
>>>> moved to libxl__arch_domain_create(). It is failing because as you
>>>> have mentioned vuart_pfn is allocated later in xc_dom_build_image().
>>>>
>>>> Can we delay mapping of this page in Xen until the ring buffer is
>>>> actually required by the emulation code for reading/writing data. By
>>>> that time, the page would have been physically mapped.
>>>
>>> You would not be able to report an error if you fail to map it. But this
>>> looks like to me a workaround for a tool problem.
>>>
>>> Anyway, as I said, I'd like feedback from the tools maintainers to see how
>>> we can proceed.
>>>
>>
>> Is there a summary of the problem, is there a particular email in this
>> thread I should look at? Sorry I'm swamped by emails and patches at the
>> moment.
> 
> I will summarize the problem.
> 
> It was decided to call domain_vpl011_init() from inside
> libxl__arch_domain_create() to initialize vpl011. However,
> domain_vpl011_init() fails to map the the vuart GFN because it has not
> been physically mapped yet by the toolstack.
> 
> The following call flows highlights the issue.
> 
> libxl__domain_build() ---> libxl__build_pv ---> libxl__build_dom()
> ----> xc_dom_build_image() ---> alloc_magic_pages() ----> vuart GFN
> allocated/mapped here
> 
> libxl__domain_build() ----> libxl__build_pre()  ---->
> libxl__arch_domain_create() ----> domain_vpl011_init() ---> this call
> fails as the vuart GFN has not been physically mapped yet as shown in
> the first call flow.
> 
> However, libxl__build_pv() is called after libxl__build_pre(). It
> means that the domain_vpl011_init() is called before
> alloc_magic_pages() is called and hence the initialization fails.
> 
> For that reason, I had introduced a new function
> libxl__arch_domain_create_finish() which will be called from
> libxl__build_post(). I moved the domain_vpl011_init() there. However,
> Julien pointed out that vuart should be initialized early in
> libxl__arch_domain_create() function. 

libxl__arch_domain_create could be a place or even 
libxl__arch_domain_finalise_hw_descriptions.

My point is it looks a bit odd to create the vpl011 UART very late in 
the process as from the code you would expect all the hardware to be 
setup after libxl__arch_domain_finialise_hw_descriptions is called.

> 
> So the issue is what is the right place to call domain_vpl011_init()?
> 
> I hope it clarifies the issue.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-20 11:16                   ` Julien Grall
@ 2017-06-20 11:42                     ` Wei Liu
  2017-06-21 10:18                     ` Bhupinder Thakur
  1 sibling, 0 replies; 65+ messages in thread
From: Wei Liu @ 2017-06-20 11:42 UTC (permalink / raw)
  To: Julien Grall
  Cc: Bhupinder Thakur, xen-devel, Stefano Stabellini, Wei Liu, Ian Jackson

On Tue, Jun 20, 2017 at 12:16:52PM +0100, Julien Grall wrote:
> On 06/19/2017 02:11 PM, Bhupinder Thakur wrote:
> > Hi Wei,
> 
> Hi Bhupinder,
> 
> > On 19 June 2017 at 17:17, Wei Liu <wei.liu2@citrix.com> wrote:
> > > On Mon, Jun 19, 2017 at 12:01:32PM +0100, Julien Grall wrote:
> > > > 
> > > > 
> > > > On 19/06/17 11:59, Bhupinder Thakur wrote:
> > > > > Hi Julien,
> > > > > 
> > > > > I was mistaken in my earlier mail about vpl011 init working if it is
> > > > > moved to libxl__arch_domain_create(). It is failing because as you
> > > > > have mentioned vuart_pfn is allocated later in xc_dom_build_image().
> > > > > 
> > > > > Can we delay mapping of this page in Xen until the ring buffer is
> > > > > actually required by the emulation code for reading/writing data. By
> > > > > that time, the page would have been physically mapped.
> > > > 
> > > > You would not be able to report an error if you fail to map it. But this
> > > > looks like to me a workaround for a tool problem.
> > > > 
> > > > Anyway, as I said, I'd like feedback from the tools maintainers to see how
> > > > we can proceed.
> > > > 
> > > 
> > > Is there a summary of the problem, is there a particular email in this
> > > thread I should look at? Sorry I'm swamped by emails and patches at the
> > > moment.
> > 
> > I will summarize the problem.
> > 
> > It was decided to call domain_vpl011_init() from inside
> > libxl__arch_domain_create() to initialize vpl011. However,
> > domain_vpl011_init() fails to map the the vuart GFN because it has not
> > been physically mapped yet by the toolstack.
> > 
> > The following call flows highlights the issue.
> > 
> > libxl__domain_build() ---> libxl__build_pv ---> libxl__build_dom()
> > ----> xc_dom_build_image() ---> alloc_magic_pages() ----> vuart GFN
> > allocated/mapped here
> > 
> > libxl__domain_build() ----> libxl__build_pre()  ---->
> > libxl__arch_domain_create() ----> domain_vpl011_init() ---> this call
> > fails as the vuart GFN has not been physically mapped yet as shown in
> > the first call flow.
> > 
> > However, libxl__build_pv() is called after libxl__build_pre(). It
> > means that the domain_vpl011_init() is called before
> > alloc_magic_pages() is called and hence the initialization fails.
> > 
> > For that reason, I had introduced a new function
> > libxl__arch_domain_create_finish() which will be called from
> > libxl__build_post(). I moved the domain_vpl011_init() there. However,
> > Julien pointed out that vuart should be initialized early in
> > libxl__arch_domain_create() function.
> 
> libxl__arch_domain_create could be a place or even
> libxl__arch_domain_finalise_hw_descriptions.
> 

libxl__arch_domain_finialise_hw_descriptions sounds like a good place to
me.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011
  2017-06-20 11:16                   ` Julien Grall
  2017-06-20 11:42                     ` Wei Liu
@ 2017-06-21 10:18                     ` Bhupinder Thakur
  1 sibling, 0 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-21 10:18 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Wei Liu, Ian Jackson

Hi Julien,

On 20 June 2017 at 16:46, Julien Grall <julien.grall@arm.com> wrote:
> On 06/19/2017 02:11 PM, Bhupinder Thakur wrote:
>>
>> Hi Wei,
>
>
> Hi Bhupinder,
>
>
>> On 19 June 2017 at 17:17, Wei Liu <wei.liu2@citrix.com> wrote:
>>>
>>> On Mon, Jun 19, 2017 at 12:01:32PM +0100, Julien Grall wrote:
>>>>
>>>>
>>>>
>>>> On 19/06/17 11:59, Bhupinder Thakur wrote:
>>>>>
>>>>> Hi Julien,
>>>>>
>>>>> I was mistaken in my earlier mail about vpl011 init working if it is
>>>>> moved to libxl__arch_domain_create(). It is failing because as you
>>>>> have mentioned vuart_pfn is allocated later in xc_dom_build_image().
>>>>>
>>>>> Can we delay mapping of this page in Xen until the ring buffer is
>>>>> actually required by the emulation code for reading/writing data. By
>>>>> that time, the page would have been physically mapped.
>>>>
>>>>
>>>> You would not be able to report an error if you fail to map it. But this
>>>> looks like to me a workaround for a tool problem.
>>>>
>>>> Anyway, as I said, I'd like feedback from the tools maintainers to see
>>>> how
>>>> we can proceed.
>>>>
>>>
>>> Is there a summary of the problem, is there a particular email in this
>>> thread I should look at? Sorry I'm swamped by emails and patches at the
>>> moment.
>>
>>
>> I will summarize the problem.
>>
>> It was decided to call domain_vpl011_init() from inside
>> libxl__arch_domain_create() to initialize vpl011. However,
>> domain_vpl011_init() fails to map the the vuart GFN because it has not
>> been physically mapped yet by the toolstack.
>>
>> The following call flows highlights the issue.
>>
>> libxl__domain_build() ---> libxl__build_pv ---> libxl__build_dom()
>> ----> xc_dom_build_image() ---> alloc_magic_pages() ----> vuart GFN
>> allocated/mapped here
>>
>> libxl__domain_build() ----> libxl__build_pre()  ---->
>> libxl__arch_domain_create() ----> domain_vpl011_init() ---> this call
>> fails as the vuart GFN has not been physically mapped yet as shown in
>> the first call flow.
>>
>> However, libxl__build_pv() is called after libxl__build_pre(). It
>> means that the domain_vpl011_init() is called before
>> alloc_magic_pages() is called and hence the initialization fails.
>>
>> For that reason, I had introduced a new function
>> libxl__arch_domain_create_finish() which will be called from
>> libxl__build_post(). I moved the domain_vpl011_init() there. However,
>> Julien pointed out that vuart should be initialized early in
>> libxl__arch_domain_create() function.
>
>
> libxl__arch_domain_create could be a place or even
> libxl__arch_domain_finalise_hw_descriptions.
>
> My point is it looks a bit odd to create the vpl011 UART very late in the
> process as from the code you would expect all the hardware to be setup after
> libxl__arch_domain_finialise_hw_descriptions is called.
>

libxl__arch_domain_finalise_hw_descriptions() is called just before
xc_dom_build_image() and therefore the vuart gfn is still not
allocated. Maybe I can introduce a new arch specific
libxl__arch_domain_init_vpl011() function and call it from inside
libxl__build_dom() after call to xc_dom_build_image() so that the
vuart gfn is allocated.

Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-19 10:14   ` Andre Przywara
@ 2017-06-22  5:16     ` Bhupinder Thakur
  2017-06-23 12:45     ` Julien Grall
  1 sibling, 0 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-22  5:16 UTC (permalink / raw)
  To: Andre Przywara
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Wei Liu, Ian Jackson

Hi Andre,

Thanks for your comments.

>> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
>> index d46b98c..c1a0e7f 100644
>> --- a/xen/arch/arm/Kconfig
>> +++ b/xen/arch/arm/Kconfig
>> @@ -50,6 +50,11 @@ config HAS_ITS
>>          prompt "GICv3 ITS MSI controller support" if EXPERT = "y"
>>          depends on HAS_GICV3
>>
>> +config VPL011_CONSOLE
>> +     bool "Emulated pl011 console support"
>> +     default y
>> +     ---help---
>> +       Allows a guest to use pl011 UART as a console
>
> I admit that I am rather late with this comment, but I am not sure we
> should advertise PL011 emulation here.
> Technically what you emulate is a "SBSA Generic UART", which is indeed a
> subset of the PL011, but really only a subset. You confirm this already
> in patch 13/14, where you use the respective compatible name instead of
> the generic arm,pl011 one.
>
> So while I don't dare to ask for renaming every identifier, I wonder if
> we should at least keep the publicly visible part confined to "SBSA
> UART". You could mention the subset nature in the help message here, for
> instance.
> The same reasoning applies to other parts of this series which introduce
> user-visible strings (like in libxl).
>
>>  endmenu
>>
I will rename the user visible part to "sbsa_uart".

>> +#include <xen/errno.h>
>> +#include <xen/event.h>
>> +#include <xen/guest_access.h>
>> +#include <xen/init.h>
>> +#include <xen/lib.h>
>> +#include <xen/mm.h>
>> +#include <xen/sched.h>
>> +#include <public/domctl.h>
>> +#include <public/io/console.h>
>> +#include <asm-arm/pl011-uart.h>
>> +#include <asm-arm/vgic-emul.h>
>> +#include <asm-arm/vpl011.h>
>
> I think Julien mentioned this already, but I think you should just use
> "#include <asm/.. .h>" here.
>
ok.
>> +
>> +static bool vpl011_reg32_check_access(struct hsr_dabt dabt)
>> +{
>> +    return (dabt.size != DABT_DOUBLE_WORD);
>> +}
>> +
>> +static void vpl011_update(struct domain *d)
>
> Can you please rename this function to indicate that it updates the
> *interrupt status*? That name as it is rather generic at the moment.
>
I will rename it to vpl011_update_interrupt_status.

>> +{
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +
>> +    /*
>> +     * TODO: PL011 interrupts are level triggered which means
>> +     * that interrupt needs to be set/clear instead of being
>> +     * injected. However, currently vGIC does not handle level
>> +     * triggered interrupts properly. This function needs to be
>> +     * revisited once vGIC starts handling level triggered
>> +     * interrupts.
>> +     */
>> +    if ( vpl011->uartris & vpl011->uartimsc )
>> +        vgic_vcpu_inject_spi(d, GUEST_VPL011_SPI);
>
> So my understanding is that this is using an edge triggered semantic at
> the moment. While this is not what an PL011 actually implements and not
> what the driver really expects, this is fine on itself for now.
> BUT I think we may want to avoid injecting spurious interrupts now:
> If for instance the receive interrupt condition is set and we clear the
> transmit interrupt bit, then call this function, it would inject a new
> interrupt, although in a edge-triggered world we really wouldn't need to
> do anything.
> So I believe we would need to have some kind of shadowed interrupt
> state, which stores the interrupt condition the guest already knows
> about. As soon as we *add* a bit to this state, we inject the SPI.
> This would act as a kind of temporary bridge between the level triggered
> SBSA/PL011 UART and the edge-only VGIC implementation for now.
> Later when the VGIC properly handles level triggered interrupts, this
> implementation can be adjusted. But this change should then be confined
> to this very function.
>
ok. I will update the logic accordingly.

>> +}
>> +
>> +static uint8_t vpl011_read_data(struct domain *d)
>> +{
>> +    unsigned long flags;
>> +    uint8_t data = 0;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>> +
>> +    VPL011_LOCK(d, flags);
>> +
>> +    /*
>> +     * 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 )
>> +    {
>> +        data = intf->in[xencons_mask(in_cons, sizeof(intf->in))];
>> +        in_cons += 1;
>> +        intf->in_cons = in_cons;
>> +        smp_mb();
>> +    }
>> +    else
>> +    {
>> +        gprintk(XENLOG_ERR, "vpl011: Unexpected IN ring buffer empty\n");
>> +    }
>> +
>> +    if ( xencons_queued(in_prod, in_cons, sizeof(intf->in)) == 0 )
>> +    {
>> +        vpl011->uartfr |= RXFE;
>> +        vpl011->uartris &= ~RXI;
>
> In a level triggered world you would need to possibly change the status
> of the interrupt line here, so a call to (a renamed and fixed)
> vpl011_update() function would be due here. To make the transition later
> as easy as possible, I'd recommend to implement this shadow interrupt
> state as described above and then call the interrupt update function
> here already.
ok.
>
>> +    }
>> +    vpl011->uartfr &= ~RXFF;
>> +    VPL011_UNLOCK(d, flags);
>> +
>> +    return data;
>> +}
>> +
>> +static void vpl011_write_data(struct domain *d, uint8_t data)
>> +{
>> +    unsigned long flags;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX out_cons = intf->out_cons;
>> +    XENCONS_RING_IDX out_prod = intf->out_prod;
>> +
>> +    VPL011_LOCK(d, flags);
>> +
>> +    /*
>> +     * It is expected that the ring is not full when this function is called
>> +     * as the guest is expected to write to the data register only when the
>> +     * TXFF flag is not set.
>> +     * In case the guest does write even when the TXFF flag is set then the
>> +     * data will be silently dropped.
>> +     */
>> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) !=
>> +         sizeof (intf->out) )
>> +    {
>> +        intf->out[xencons_mask(out_prod, sizeof(intf->out))] = data;
>> +        smp_wmb();
>> +        out_prod += 1;
>> +        intf->out_prod = out_prod;
>> +    }
>> +    else
>> +    {
>> +        gprintk(XENLOG_ERR, "vpl011: Unexpected OUT ring buffer full\n");
>> +    }
>> +
>> +    if ( xencons_queued(out_prod, out_cons, sizeof(intf->out)) ==
>> +         sizeof (intf->out) )
>> +    {
>> +        vpl011->uartfr |= TXFF;
>> +        vpl011->uartris &= ~TXI;
>
> Same as above. Basically whenever you change one of the bits that may
> affect the status of the interrupt line, I'd call the update function.
ok.
>
>> +    }
>> +
>> +    vpl011->uartfr |= BUSY;
>> +
>> +    vpl011->uartfr &= ~TXFE;
>> +
>> +    VPL011_UNLOCK(d, flags);
>> +
>> +    /*
>> +     * Send an event to console backend to indicate that there is
>> +     * data in the OUT ring buffer.
>> +     */
>> +    notify_via_xen_event_channel(d, vpl011->evtchn);
>> +}
>> +
>> +static int vpl011_mmio_read(struct vcpu *v,
>> +                            mmio_info_t *info,
>> +                            register_t *r,
>> +                            void *priv)
>> +{
>> +    struct hsr_dabt dabt = info->dabt;
>> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
>> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
>> +
>> +    switch ( vpl011_reg )
>> +    {
>> +    case DR:
>> +        /*
>> +         * Since pl011 registers are 32-bit registers, all registers
>> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
>> +         * accesses.
>> +         */
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011_read_data(v->domain), info);
>> +        return 1;
>> +
>> +    case RSR:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        /* It always returns 0 as there are no physical errors. */
>> +        *r = 0;
>> +        return 1;
>> +
>> +    case FR:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011->uartfr, info);
>> +        return 1;
>> +
>> +    case RIS:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011->uartris, info);
>> +        return 1;
>> +
>> +    case MIS:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011->uartris &
>> +                                vpl011->uartimsc, info);
>
> That smells like you need a lock here, since another access could change
> either RIS and/or IMSC concurrently.
> But as Julien already mentioned, these accesses are prone to races
> anyway, since vreg_reg32_extract() is not atomic.
> So is it worth to take the lock here just before the whole switch statement?
>
Yes, I have taken the lock while reading.

>> +        return 1;
>> +
>> +    case IMSC:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        *r = vreg_reg32_extract(vpl011->uartimsc, info);
>> +        return 1;
>> +
>> +    case ICR:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        /* Only write is valid. */
>> +        return 0;
>> +
>> +    default:
>> +        gprintk(XENLOG_ERR, "vpl011: unhandled read r%d offset %#08x\n",
>> +                dabt.reg, vpl011_reg);
>> +        return 0;
>> +    }
>> +
>> +    return 1;
>> +
>> +bad_width:
>> +    gprintk(XENLOG_ERR, "vpl011: bad read width %d r%d offset %#08x\n",
>> +            dabt.size, dabt.reg, vpl011_reg);
>> +    domain_crash_synchronous();
>> +    return 0;
>> +
>> +}
>> +
>> +static int vpl011_mmio_write(struct vcpu *v,
>> +                             mmio_info_t *info,
>> +                             register_t r,
>> +                             void *priv)
>> +{
>> +    struct hsr_dabt dabt = info->dabt;
>> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
>> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
>> +    struct domain *d = v->domain;
>> +    unsigned long flags;
>> +
>> +    switch ( vpl011_reg )
>> +    {
>> +    case DR:
>> +    {
>> +        uint32_t data = 0;
>> +
>> +        /*
>> +         * Since pl011 registers are 32-bit registers, all registers
>> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
>> +         * accesses.
>> +         */
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        vreg_reg32_update(&data, r, info);
>> +        data &= 0xFF;
>
> This is not needed as vpl011_write_data()'s second argument is uint8_t,
> so the compiler does this masking anyway.
> And even if it wouldn't, you could move this statement into the call.
>
Yes. I will remove the masking.

>> +        vpl011_write_data(v->domain, data);
>> +        return 1;
>> +    }
>> +    case RSR: /* Nothing to clear. */
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        return 1;
>> +
>> +    case FR:
>> +    case RIS:
>> +    case MIS:
>> +        goto write_ignore;
>> +
>> +    case IMSC:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        VPL011_LOCK(d, flags);
>> +        vreg_reg32_update(&vpl011->uartimsc, r, info);
>> +        VPL011_UNLOCK(d, flags);
>> +        vpl011_update(v->domain);
>> +        return 1;
>> +
>> +    case ICR:
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        VPL011_LOCK(d, flags);
>> +        vreg_reg32_clearbits(&vpl011->uartris, r, info);
>
> Please call the interrupt status update function here.
>
ok.
>> +        VPL011_UNLOCK(d, flags);
>> +        vpl011_update(d);
>> +        return 1;
>> +
>> +    default:
>> +        gprintk(XENLOG_ERR, "vpl011: unhandled write r%d offset %#08x\n",
>> +                dabt.reg, vpl011_reg);
>> +        return 0;
>> +    }
>> +
>> +write_ignore:
>> +    return 1;
>> +
>> +bad_width:
>> +    gprintk(XENLOG_ERR, "vpl011: bad write width %d r%d offset %#08x\n",
>> +            dabt.size, dabt.reg, vpl011_reg);
>> +    domain_crash_synchronous();
>> +    return 0;
>> +
>> +}
>> +
>> +static const struct mmio_handler_ops vpl011_mmio_handler = {
>> +    .read = vpl011_mmio_read,
>> +    .write = vpl011_mmio_write,
>> +};
>> +
>> +static void vpl011_data_avail(struct domain *d)
>> +{
>> +    unsigned long flags;
>> +    struct vpl011 *vpl011 = &d->arch.vpl011;
>> +    struct xencons_interface *intf = vpl011->ring_buf;
>> +    XENCONS_RING_IDX in_cons = intf->in_cons;
>> +    XENCONS_RING_IDX in_prod = intf->in_prod;
>> +    XENCONS_RING_IDX out_cons = intf->out_cons;
>> +    XENCONS_RING_IDX out_prod = intf->out_prod;
>> +    XENCONS_RING_IDX in_ring_qsize, out_ring_qsize;
>> +
>> +    VPL011_LOCK(d, flags);
>> +
>> +    in_ring_qsize = xencons_queued(in_prod,
>> +                                   in_cons,
>> +                                   sizeof(intf->in));
>> +
>> +    out_ring_qsize = xencons_queued(out_prod,
>> +                                    out_cons,
>> +                                    sizeof(intf->out));
>> +
>> +    /* Update the uart rx state if the buffer is not empty. */
>> +    if ( in_ring_qsize != 0 )
>> +    {
>> +        vpl011->uartfr &= ~RXFE;
>> +        if ( in_ring_qsize == sizeof(intf->in) )
>> +            vpl011->uartfr |= RXFF;
>> +        vpl011->uartris |= RXI;
>
> ... and here ...
>
>> +    }
>> +
>> +    /* Update the uart tx state if the buffer is not full. */
>> +    if ( out_ring_qsize != sizeof(intf->out) )
>> +    {
>> +        vpl011->uartfr &= ~TXFF;
>> +        vpl011->uartris |= TXI;
>
> ... and here.
>
ok


Regards,
Bhupinder

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* Re: [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen
  2017-06-19 10:14   ` Andre Przywara
  2017-06-22  5:16     ` Bhupinder Thakur
@ 2017-06-23 12:45     ` Julien Grall
  1 sibling, 0 replies; 65+ messages in thread
From: Julien Grall @ 2017-06-23 12:45 UTC (permalink / raw)
  To: Andre Przywara, Bhupinder Thakur, xen-devel
  Cc: Ian Jackson, Stefano Stabellini, Wei Liu

Hi,

On 19/06/17 11:14, Andre Przywara wrote:
>> +
>> +static bool vpl011_reg32_check_access(struct hsr_dabt dabt)
>> +{
>> +    return (dabt.size != DABT_DOUBLE_WORD);
>> +}
>> +
>> +static void vpl011_update(struct domain *d)
>
> Can you please rename this function to indicate that it updates the
> *interrupt status*? That name as it is rather generic at the moment.

Well, it updates the pl011 state even though today it is only handling 
interrupt...

>> +static int vpl011_mmio_write(struct vcpu *v,
>> +                             mmio_info_t *info,
>> +                             register_t r,
>> +                             void *priv)
>> +{
>> +    struct hsr_dabt dabt = info->dabt;
>> +    uint32_t vpl011_reg = (uint32_t)(info->gpa - GUEST_PL011_BASE);
>> +    struct vpl011 *vpl011 = &v->domain->arch.vpl011;
>> +    struct domain *d = v->domain;
>> +    unsigned long flags;
>> +
>> +    switch ( vpl011_reg )
>> +    {
>> +    case DR:
>> +    {
>> +        uint32_t data = 0;
>> +
>> +        /*
>> +         * Since pl011 registers are 32-bit registers, all registers
>> +         * are handled similarly allowing 8-bit, 16-bit and 32-bit
>> +         * accesses.
>> +         */
>> +        if ( !vpl011_reg32_check_access(dabt) ) goto bad_width;
>> +
>> +        vreg_reg32_update(&data, r, info);
>> +        data &= 0xFF;
>
> This is not needed as vpl011_write_data()'s second argument is uint8_t,
> so the compiler does this masking anyway.
> And even if it wouldn't, you could move this statement into the call.

Sorry, I have only spotted this comment now. We should really avoid 
implicit cast when calling function. This is a call to make error if we 
ever decide to change the type of the parameter. More than the local 
variable data is 32-bit.

Better to play safe than handling security issue after afterwards.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 65+ messages in thread

* [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole
@ 2017-06-06 10:04 Bhupinder Thakur
  0 siblings, 0 replies; 65+ messages in thread
From: Bhupinder Thakur @ 2017-06-06 10:04 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Julien Grall, Stefano Stabellini, Ian Jackson

This patch finally adds the support for vuart console.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---

Changes since v3:
- The changes in xenconsole have been split into four patches. This is the fourth patch.
- The vuart console support is added under CONFIG_VUART_CONSOLE option.

 tools/console/Makefile    |  3 ++-
 tools/console/daemon/io.c | 26 +++++++++++++++++++++++++-
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/tools/console/Makefile b/tools/console/Makefile
index c8b0300..fcee313 100644
--- a/tools/console/Makefile
+++ b/tools/console/Makefile
@@ -11,6 +11,7 @@ LDLIBS += $(SOCKET_LIBS)
 
 LDLIBS_xenconsoled += $(UTIL_LIBS)
 LDLIBS_xenconsoled += -lrt
+VUART_CFLAGS-$(CONFIG_VUART_CONSOLE) = -DCONFIG_VUART_CONSOLE
 
 BIN      = xenconsoled xenconsole
 
@@ -28,7 +29,7 @@ clean:
 distclean: clean
 
 daemon/main.o: daemon/_paths.h
-daemon/io.o: CFLAGS += $(CFLAGS_libxenevtchn) $(CFLAGS_libxengnttab)
+daemon/io.o: CFLAGS += $(CFLAGS_libxenevtchn) $(CFLAGS_libxengnttab) $(VUART_CFLAGS-y)
 xenconsoled: $(patsubst %.c,%.o,$(wildcard daemon/*.c))
 	$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LDLIBS_libxenevtchn) $(LDLIBS_libxengnttab) $(LDLIBS_xenconsoled) $(APPEND_LDFLAGS)
 
diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index db73e10..cae2efe 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -104,12 +104,16 @@ struct console {
 	xenevtchn_port_or_error_t remote_port;
 	struct xencons_interface *interface;
 	struct domain *d;
+	bool optional;
+	bool prefer_gnttab;
 };
 
 struct console_data {
 	char *xsname;
 	char *ttyname;
 	char *log_suffix;
+	bool optional;
+	bool prefer_gnttab;
 };
 
 static struct console_data console_data[] = {
@@ -118,7 +122,18 @@ static struct console_data console_data[] = {
 		.xsname = "/console",
 		.ttyname = "tty",
 		.log_suffix = "",
+		.optional = false,
+		.prefer_gnttab = true,
 	},
+#if defined(CONFIG_VUART_CONSOLE)
+	{
+		.xsname = "/vuart/0",
+		.ttyname = "tty",
+		.log_suffix = "-vuart0",
+		.optional = true,
+		.prefer_gnttab = false,
+	},
+#endif
 };
 
 #define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data))
@@ -665,7 +680,12 @@ static int console_create_ring(struct console *con)
 			"port", "%i", &remote_port,
 			NULL);
 	if (err)
+	{
+		/* If the console is optional then do not return an error. */
+		if (con->optional)
+			err = 0;
 		goto out;
+	}
 
 	snprintf(path, sizeof(path), "%s/type", con->xspath);
 	type = xs_read(xs, XBT_NULL, path, NULL);
@@ -679,7 +699,9 @@ static int console_create_ring(struct console *con)
 	if (ring_ref != con->ring_ref && con->ring_ref != -1)
 		console_unmap_interface(con);
 
-	if (!con->interface && xgt_handle) {
+	if (!con->interface && 
+		xgt_handle &&
+		con->prefer_gnttab) {
 		/* Prefer using grant table */
 		con->interface = xengnttab_map_grant_ref(xgt_handle,
 			dom->domid, GNTTAB_RESERVED_CONSOLE,
@@ -789,6 +811,8 @@ static int console_init(struct console *con, struct domain *dom, void **data)
 	con->d = dom;
 	con->ttyname = (*con_data)->ttyname;
 	con->log_suffix = (*con_data)->log_suffix;
+	con->optional = (*con_data)->optional;
+	con->prefer_gnttab = (*con_data)->prefer_gnttab;
 	con->xsname = (*con_data)->xsname;
 	con->xspath = xs_get_domain_path(xs, dom->domid);
 	s = realloc(con->xspath, strlen(con->xspath) +
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 65+ messages in thread

end of thread, other threads:[~2017-06-23 12:45 UTC | newest]

Thread overview: 65+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-06 17:25 [PATCH 00/14 v4] PL011 emulation support in Xen Bhupinder Thakur
2017-06-06 17:25 ` [PATCH 01/14 v4] xen/arm: vpl011: Move vgic register access functions to vreg.h Bhupinder Thakur
2017-06-09 12:49   ` Julien Grall
2017-06-06 17:25 ` [PATCH 02/14 v4] xen/arm: vpl011: Define generic vreg_reg* access functions in vreg.h Bhupinder Thakur
2017-06-09 12:54   ` Julien Grall
2017-06-19  9:33   ` Andre Przywara
2017-06-19 16:53     ` Bhupinder Thakur
2017-06-19 16:59       ` Andre Przywara
2017-06-06 17:25 ` [PATCH 03/14 v4] xen/arm: vpl011: Add pl011 uart emulation in Xen Bhupinder Thakur
2017-06-06 23:02   ` Stefano Stabellini
2017-06-09 13:15     ` Julien Grall
2017-06-09 18:02       ` Stefano Stabellini
2017-06-13  8:58       ` Bhupinder Thakur
2017-06-13  9:25         ` Julien Grall
2017-06-09 13:54   ` Julien Grall
2017-06-13 10:57     ` Bhupinder Thakur
2017-06-13 12:44       ` Julien Grall
2017-06-13 17:50         ` Stefano Stabellini
2017-06-14  5:47         ` Bhupinder Thakur
2017-06-14  9:33           ` Julien Grall
2017-06-19 10:14   ` Andre Przywara
2017-06-22  5:16     ` Bhupinder Thakur
2017-06-23 12:45     ` Julien Grall
2017-06-06 17:25 ` [PATCH 04/14 v4] xen/arm: vpl011: Add support for vuart in libxl Bhupinder Thakur
2017-06-06 23:07   ` Stefano Stabellini
2017-06-06 17:25 ` [PATCH 05/14 v4] xen/arm: vpl011: Allocate a new GFN in the toolstack for vuart Bhupinder Thakur
2017-06-06 23:17   ` Stefano Stabellini
2017-06-07 16:43   ` Wei Liu
2017-06-06 17:25 ` [PATCH 06/14 v4] xen/arm: vpl011: Add a new domctl API to initialize vpl011 Bhupinder Thakur
2017-06-06 23:26   ` Stefano Stabellini
2017-06-09 14:06     ` Julien Grall
2017-06-09 18:32       ` Stefano Stabellini
2017-06-14  7:35     ` Bhupinder Thakur
2017-06-14  8:34       ` Bhupinder Thakur
2017-06-09 14:13   ` Julien Grall
2017-06-14  9:16     ` Bhupinder Thakur
2017-06-14 10:15       ` Julien Grall
2017-06-15  6:33         ` Bhupinder Thakur
2017-06-19 10:59           ` Bhupinder Thakur
2017-06-19 11:01             ` Julien Grall
2017-06-19 11:47               ` Wei Liu
2017-06-19 13:11                 ` Bhupinder Thakur
2017-06-20 11:16                   ` Julien Grall
2017-06-20 11:42                     ` Wei Liu
2017-06-21 10:18                     ` Bhupinder Thakur
2017-06-06 17:25 ` [PATCH 07/14 v4] xen/arm: vpl011: Add a new vuart node in the xenstore Bhupinder Thakur
2017-06-06 23:38   ` Stefano Stabellini
2017-06-06 17:25 ` [PATCH 08/14 v4] xen/arm: vpl011: Modify xenconsole to define and use a new console structure Bhupinder Thakur
2017-06-07  1:13   ` Stefano Stabellini
2017-06-06 17:25 ` [PATCH 09/14 v4] xen/arm: vpl011: Modify xenconsole functions to take console structure as input Bhupinder Thakur
2017-06-07  0:43   ` Stefano Stabellini
2017-06-06 17:25 ` [PATCH 10/14 v4] xen/arm: vpl011: Modify xenconsole to support multiple consoles Bhupinder Thakur
2017-06-07  1:03   ` Stefano Stabellini
2017-06-07  3:51     ` Bhupinder Thakur
2017-06-07 16:46       ` Wei Liu
2017-06-07 17:54       ` Stefano Stabellini
2017-06-06 17:25 ` [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole Bhupinder Thakur
2017-06-07  1:08   ` Stefano Stabellini
2017-06-07 16:44   ` Wei Liu
2017-06-06 17:25 ` [PATCH 12/14 v4] xen/arm: vpl011: Add a new vuart console type to xenconsole client Bhupinder Thakur
2017-06-06 23:41   ` Stefano Stabellini
2017-06-06 17:25 ` [PATCH 13/14 v4] xen/arm: vpl011: Add a pl011 uart DT node in the guest device tree Bhupinder Thakur
2017-06-06 17:25 ` [PATCH 14/14 v4] xen/arm: vpl011: Update documentation for vuart console support Bhupinder Thakur
2017-06-09 13:58 ` [PATCH 00/14 v4] PL011 emulation support in Xen Julien Grall
  -- strict thread matches above, loose matches on Subject: below --
2017-06-06 10:04 [PATCH 11/14 v4] xen/arm: vpl011: Add support for vuart console in xenconsole Bhupinder Thakur

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).