#include <xtf/hypercall.h>
#include <arch/x86/config.h>
+#include <arch/x86/mm.h>
#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);
void arch_setup(void)
{
register_console_callback(xen_console_write);
+
+ setup_pv_console();
}
/*
#include <xtf/types.h>
+#include <xtf/atomic.h>
#include <xtf/console.h>
+#include <xtf/hypercall.h>
#include <xtf/lib.h>
#include <xtf/libc.h>
* 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;
--- /dev/null
+#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:
+ */
#include <xtf/compiler.h>
+#include <xen/event_channel.h>
+#include <xen/io/console.h>
+
/* Console output callback. */
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 */