/* * xencons.c * Access to xen consoles. */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "../pc/io.h" struct { struct xencons_interface *intf; int evtchn; Lock txlock; } xencons; static void xenconsintr(Ureg*, void*); /* * Debug print to xen "emergency console". * Output only appears if xen is built with verbose=y */ void dprint(char *fmt, ...) { int n; va_list arg; char buf[PRINTSIZE]; va_start(arg, fmt); n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); HYPERVISOR_console_io(0, n, buf); } /* * Polled input for the debugger */ int uartgetc(void) { struct xencons_interface *con = xencons.intf; char c; while (con->in_cons == con->in_prod) HYPERVISOR_yield(); coherence(); c = con->in[MASK_XENCONS_IDX(con->in_cons++, con->in)]; if (con->in_cons == con->in_prod) xenchannotify(xencons.evtchn); return c; } /* * Emit a string to the guest OS console, bypassing the queue * - before serialoq is initialised * - when rdb is activated * - from iprint() for messages from interrupt routines * If ring is full, just throw extra output away. */ void uartputs(char *s, int n) { struct xencons_interface *con = xencons.intf; unsigned long prod; int c; ilock(&xencons.txlock); prod = con->out_prod; while (n-- > 0 && (prod - con->out_cons) < sizeof(con->out)) { c = *s++; if (c == '\n') con->out[MASK_XENCONS_IDX(prod++, con->out)] = '\r'; con->out[MASK_XENCONS_IDX(prod++, con->out)] = c; } coherence(); con->out_prod = prod; xenchannotify(xencons.evtchn); iunlock(&xencons.txlock); } /* * Send queued output to guest OS console */ static void txkick(void*) { struct xencons_interface *con = xencons.intf; unsigned long prod; long avail, idx, n, m; ilock(&xencons.txlock); prod = con->out_prod; avail = sizeof(con->out) - (prod - con->out_cons); while (avail > 0) { idx = MASK_XENCONS_IDX(prod, con->out); m = sizeof(con->out) - idx; if (m > avail) m = avail; n = qconsume(serialoq, con->out+idx, m); if (n < 0) break; prod += n; avail -= n; } coherence(); con->out_prod = prod; xenchannotify(xencons.evtchn); iunlock(&xencons.txlock); } /* * Handle channel event from console */ static void xenconsintr(Ureg*, void*) { struct xencons_interface *con = xencons.intf; unsigned long cons; char c; cons = con->in_cons; coherence(); while (cons != con->in_prod) { c = con->in[MASK_XENCONS_IDX(cons++, con->in)]; kbdcr2nl(kbdq, c); } coherence(); con->in_cons = cons; txkick(0); } void xenconsinit(void) { xencons.intf = (struct xencons_interface*)mmumapframe(XENCONSOLE, xenstart->console_mfn); xencons.evtchn = xenstart->console_evtchn; } void kbdenable(void) { serialoq = qopen(4 * 1024, 0, txkick, 0); qget(serialoq); kbdq = qopen(4 * 1024, 0, 0, 0); if(kbdq == nil) panic("kbdinit"); qnoblock(kbdq, 1); intrenable(xencons.evtchn, xenconsintr, 0, BUSUNKNOWN, "Xen console"); }