From: Andrew Cooper Date: Fri, 20 Mar 2015 23:30:35 +0000 (+0100) Subject: PV Console driver. Synchronous output only X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=0f15786a68e03791c9e225d287b3d406bc6e39a1;p=people%2Froyger%2Fxen-test-framework.git PV Console driver. Synchronous output only Signed-off-by: Andrew Cooper --- diff --git a/README b/README index 91c9ca8..c4f4192 100644 --- a/README +++ b/README @@ -13,11 +13,11 @@ machine. * PV 32 and 64 bit entry points * Hypercall interface +* PV console driver (output) ## TODO List: * More introductory text * Entry points for 32 and 64bit HVM guests -* PV console driver * Common reporting framework * Tests diff --git a/arch/x86/setup.c b/arch/x86/setup.c index 09669b7..a8f9138 100644 --- a/arch/x86/setup.c +++ b/arch/x86/setup.c @@ -3,12 +3,26 @@ #include #include +#include #ifdef CONFIG_ENV_pv /* Filled in by head_pv.S */ start_info_t *start_info = NULL; #endif +static void setup_pv_console(void) +{ + xencons_interface_t *cons_ring; + evtchn_port_t cons_evtchn; + +#if defined(CONFIG_ENV_pv) + cons_ring = mfn_to_virt(start_info->console.domU.mfn); + cons_evtchn = start_info->console.domU.evtchn; +#endif + + init_pv_console(cons_ring, cons_evtchn); +} + static void xen_console_write(const char *buf, size_t len) { hypercall_console_write(buf, len); @@ -17,6 +31,8 @@ static void xen_console_write(const char *buf, size_t len) void arch_setup(void) { register_console_callback(xen_console_write); + + setup_pv_console(); } /* diff --git a/common/console.c b/common/console.c index da68dba..fe2551b 100644 --- a/common/console.c +++ b/common/console.c @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include @@ -7,16 +9,78 @@ * Output functions, registered if/when available. * Possibilities: * - Xen hypervisor console + * - PV console */ -static cons_output_cb output_fns[1]; +static cons_output_cb output_fns[2]; static unsigned int nr_cons_cb; +/* Guest PV console details. */ +static xencons_interface_t *pv_ring; +static evtchn_port_t pv_evtchn; + void register_console_callback(cons_output_cb fn) { if ( nr_cons_cb < ARRAY_SIZE(output_fns) ) output_fns[nr_cons_cb++] = fn; } +/* + * Write some data into the pv ring, taking care not to overflow the ring. + */ +static size_t pv_console_write_some(const char *buf, size_t len) +{ + size_t s = 0; + uint32_t cons = LOAD_ACQUIRE(&pv_ring->out_cons), prod = pv_ring->out_prod; + + while ( (s < len) && ((prod - cons) < sizeof(pv_ring->out)) ) + pv_ring->out[prod++ & (sizeof(pv_ring->out) - 1)] = buf[s++]; + + STORE_RELEASE(&pv_ring->out_prod, prod); + + return s; +} + +/* + * Write some data into the pv ring, synchronously waiting for all data to be + * consumed. + */ +static void pv_console_write(const char *buf, size_t len) +{ + size_t written = 0; + uint32_t cons = LOAD_ACQUIRE(&pv_ring->out_cons); + + do + { + /* Try and put some data into the ring. */ + written = pv_console_write_some(&buf[written], len - written); + + /* Kick xenconsoled into action. */ + hypercall_evtchn_send(pv_evtchn); + + /* + * If we have more to write, the ring must have filled up. Wait for + * more space. + */ + if ( written < len ) + { + while ( ACCESS_ONCE(pv_ring->out_cons) == cons ) + hypercall_yield(); + } + + } while ( written < len ); + + /* Wait for xenconsoled to consume all the data we gave. */ + while ( ACCESS_ONCE(pv_ring->out_cons) != pv_ring->out_prod ) + hypercall_yield(); +} + +void init_pv_console(xencons_interface_t *ring, evtchn_port_t port) +{ + pv_ring = ring; + pv_evtchn = port; + register_console_callback(pv_console_write); +} + void printk(const char *fmt, ...) { unsigned int i; diff --git a/include/xen/io/console.h b/include/xen/io/console.h new file mode 100644 index 0000000..5914833 --- /dev/null +++ b/include/xen/io/console.h @@ -0,0 +1,23 @@ +#ifndef XEN_PUBLIC_IO_CONSOLE_H +#define XEN_PUBLIC_IO_CONSOLE_H + +struct xencons_interface +{ + char in[1024]; + char out[2048]; + uint32_t in_cons, in_prod; + uint32_t out_cons, out_prod; +}; +typedef struct xencons_interface xencons_interface_t; + +#endif /* XEN_PUBLIC_IO_CONSOLE_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/xtf/atomic.h b/include/xtf/atomic.h index 3034165..b28612a 100644 --- a/include/xtf/atomic.h +++ b/include/xtf/atomic.h @@ -1,6 +1,7 @@ #ifndef XTF_ATOMIC_H #define XTF_ATOMIC_H +#include #include #define LOAD_ACQUIRE(p) \ diff --git a/include/xtf/console.h b/include/xtf/console.h index f6b2f94..e85236b 100644 --- a/include/xtf/console.h +++ b/include/xtf/console.h @@ -3,6 +3,9 @@ #include +#include +#include + /* Console output callback. */ typedef void (*cons_output_cb)(const char *buf, size_t len); @@ -12,6 +15,12 @@ typedef void (*cons_output_cb)(const char *buf, size_t len); */ void register_console_callback(cons_output_cb cb); +/* + * Initialise the PV console. Will register a callback. + */ +void init_pv_console(xencons_interface_t *ring, + evtchn_port_t port); + void printk(const char *fmt, ...) __printf(1, 2); #endif /* XTF_CONSOLE_H */