[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] console: generalize the ability for domU access



This patch reworks the console rotation logic to provide a general mechanism to
incorporate domU in to the rotation. It does so by walking the domain list
using the XSM console privlege check to determine if the domain is given access.

In reworking the rotation logic, the assumption that the hardware domain is the
first domain created is removed and is changed to explicitly locate the
hardware domain at boot. As part of this removal, the reliance on the
`max_init_domid` global is eliminated, allowing the removal of a compatibility
`#define` for the x86 arch.

Suggested-by: Stefano Stabellini <stefano.stabellini@xxxxxxx>
Signed-off-by: Daniel P. Smith <dpsmith@xxxxxxxxxxxxxxxxxxxx>
---

This patch was developed as part of enabling PVH domain construction for
hyperlaunch. There will be a corresponding Linux patch to enable the kernel to
make use of console_io when running as a DomU. For x86, this will only be
usable by leveraging FLASK to assign the privilege to a label that is applied
to domains desired to be able to use the Xen console. When hyperlaunch is
merged, it will become possible to assign the privilege without FLASK. This
should work for Arm environments with or without vp1011 backend.

 xen/arch/x86/include/asm/setup.h |   2 -
 xen/drivers/char/console.c       | 134 +++++++++++++++++++++++--------
 2 files changed, 99 insertions(+), 37 deletions(-)

diff --git a/xen/arch/x86/include/asm/setup.h b/xen/arch/x86/include/asm/setup.h
index 51fce66607..5242dfcf93 100644
--- a/xen/arch/x86/include/asm/setup.h
+++ b/xen/arch/x86/include/asm/setup.h
@@ -64,6 +64,4 @@ extern bool opt_dom0_verbose;
 extern bool opt_dom0_cpuid_faulting;
 extern bool opt_dom0_msr_relaxed;
 
-#define max_init_domid (0)
-
 #endif
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 0e410fa086..f5b759898e 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -473,45 +473,102 @@ static void cf_check dump_console_ring_key(unsigned char 
key)
  */
 static unsigned int __read_mostly console_rx = 0;
 
-#define max_console_rx (max_init_domid + 1)
+#define CON_RX_DOMID (console_rx - 1)
 
 /* Make sure to rcu_unlock_domain after use */
 struct domain *console_input_domain(void)
 {
     if ( console_rx == 0 )
             return NULL;
-    return rcu_lock_domain_by_id(console_rx - 1);
+    return rcu_lock_domain_by_id(CON_RX_DOMID);
 }
 
 static void switch_serial_input(void)
 {
-    unsigned int next_rx = console_rx;
+    struct domain *next, *d = console_input_domain();
 
-    /*
-     * Rotate among Xen, dom0 and boot-time created domUs while skipping
-     * switching serial input to non existing domains.
-     */
-    for ( ; ; )
+    if ( d == NULL )
     {
-        struct domain *d;
+        if ( hardware_domain )
+        {
+            console_rx = hardware_domain->domain_id + 1;
+            printk("*** Serial input to DOM%d", CON_RX_DOMID);
+            goto out; //print switch_code statement & newline
+        }
+        else
+        {
+            for_each_domain(next)
+            {
+                if ( xsm_console_io(XSM_OTHER, next, CONSOLEIO_read) == 0 )
+                {
+                    console_rx = next->domain_id + 1;
+                    printk("*** Serial input to DOM%d", CON_RX_DOMID);
+                    goto out; //print switch_code statement & newline
+                }
+            }
 
-        if ( next_rx++ >= max_console_rx )
+            console_rx = 0;
+            printk("*** Serial input to Xen");
+            goto out;
+        }
+    }
+
+    for ( next = rcu_dereference(d->next_in_list); next != NULL;
+          next = rcu_dereference(next->next_in_list) )
+    {
+        if ( hardware_domain && next == hardware_domain )
         {
             console_rx = 0;
             printk("*** Serial input to Xen");
-            break;
+            goto out;
         }
 
-        d = rcu_lock_domain_by_id(next_rx - 1);
-        if ( d )
+        if ( xsm_console_io(XSM_OTHER, next, CONSOLEIO_read) == 0 )
         {
-            rcu_unlock_domain(d);
-            console_rx = next_rx;
-            printk("*** Serial input to DOM%u", next_rx - 1);
-            break;
+            console_rx = next->domain_id + 1;
+            printk("*** Serial input to DOM%d", CON_RX_DOMID);
+            goto out;
+        }
+    }
+
+    /*
+     * Hit the end of the domain list and instead of assuming that the
+     * hardware domain is the first in the list, get the first domain
+     * in the domain list and then if it is not the hardware domain or
+     * does not have console privilege, iterate the list until we find
+     * the hardware domain or a domain with console privilege.
+     */
+    if ( next == NULL )
+    {
+        for_each_domain(next)
+        {
+            if ( hardware_domain && next == hardware_domain )
+            {
+                console_rx = 0;
+                printk("*** Serial input to Xen");
+                goto out;
+            }
+
+            if ( xsm_console_io(XSM_OTHER, next, CONSOLEIO_read) == 0 )
+            {
+                console_rx = next->domain_id + 1;
+                printk("*** Serial input to DOM%d", CON_RX_DOMID);
+                goto out;
+            }
         }
     }
 
+    /*
+     * If we got here, could not find a domain with console io privilege.
+     * Default to Xen.
+     */
+    console_rx = 0;
+    printk("*** Serial input to Xen");
+
+out:
+    if ( d != NULL)
+        rcu_unlock_domain(d);
+
     if ( switch_code )
         printk(" (type 'CTRL-%c' three times to switch input)",
                opt_conswitch[0]);
@@ -520,12 +577,11 @@ static void switch_serial_input(void)
 
 static void __serial_rx(char c, struct cpu_user_regs *regs)
 {
-    switch ( console_rx )
-    {
-    case 0:
+    if ( console_rx == 0 )
         return handle_keypress(c, regs);
 
-    case 1:
+    if ( hardware_domain->domain_id == CON_RX_DOMID )
+    {
         /*
          * Deliver input to the hardware domain buffer, unless it is
          * already full.
@@ -538,31 +594,37 @@ static void __serial_rx(char c, struct cpu_user_regs 
*regs)
          * getting stuck.
          */
         send_global_virq(VIRQ_CONSOLE);
-        break;
-
-#ifdef CONFIG_SBSA_VUART_CONSOLE
-    default:
+    }
+    else
     {
-        struct domain *d = rcu_lock_domain_by_id(console_rx - 1);
+        struct domain *d = rcu_lock_domain_by_any_id(CON_RX_DOMID);
 
+        if ( d == NULL )
+            goto unlock_out;
+
+#ifdef CONFIG_SBSA_VUART_CONSOLE
         /*
          * If we have a properly initialized vpl011 console for the
          * domain, without a full PV ring to Dom0 (in that case input
          * comes from the PV ring), then send the character to it.
          */
-        if ( d != NULL &&
-             !d->arch.vpl011.backend_in_domain &&
+        if ( !d->arch.vpl011.backend_in_domain &&
              d->arch.vpl011.backend.xen != NULL )
+        {
             vpl011_rx_char_xen(d, c);
-        else
-            printk("Cannot send chars to Dom%d: no UART available\n",
-                   console_rx - 1);
+            goto unlock_out;
+        }
+#endif
+
+        if ( (serial_rx_prod - serial_rx_cons) != SERIAL_RX_SIZE )
+            serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
 
+        send_guest_global_virq(d, VIRQ_CONSOLE);
+
+unlock_out:
         if ( d != NULL )
             rcu_unlock_domain(d);
     }
-#endif
-    }
 
 #ifdef CONFIG_X86
     if ( pv_shim && pv_console )
@@ -627,7 +689,7 @@ static long 
guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer,
         if ( copy_from_guest(kbuf, buffer, kcount) )
             return -EFAULT;
 
-        if ( is_hardware_domain(cd) )
+        if ( cd->domain_id == CON_RX_DOMID )
         {
             /* Use direct console output as it could be interactive */
             spin_lock_irq(&console_lock);
@@ -717,6 +779,8 @@ long do_console_io(
         rc = -E2BIG;
         if ( count > INT_MAX )
             break;
+        if ( CON_RX_DOMID != current->domain->domain_id )
+            return 0;
 
         rc = 0;
         while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )
@@ -1107,7 +1171,7 @@ void __init console_endboot(void)
      * a useful 'how to switch' message.
      */
     if ( opt_conswitch[1] == 'x' )
-        console_rx = max_console_rx;
+        console_rx = 0;
 
     register_keyhandler('w', dump_console_ring_key,
                         "synchronously dump console ring buffer (dmesg)", 0);
-- 
2.20.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.