diff options
author | mischief <mischief@offblast.org> | 2014-06-24 18:02:25 -0700 |
---|---|---|
committer | mischief <mischief@offblast.org> | 2014-06-24 18:02:25 -0700 |
commit | 5ba95fdb07ddc2c32111a1b2f57f17aa27fcbbf5 (patch) | |
tree | c1ec54cb9ecff85b0b820a26d26a10a32a118d0c /sys/src/9/xen/uartxen.c | |
parent | fa03455b5057675b18d1c87aef2d1071b2088de0 (diff) |
import xen 32 bit paravirtual kernel from /n/sources/xen.
Diffstat (limited to 'sys/src/9/xen/uartxen.c')
-rw-r--r-- | sys/src/9/xen/uartxen.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/sys/src/9/xen/uartxen.c b/sys/src/9/xen/uartxen.c new file mode 100644 index 000000000..31e9b8ef3 --- /dev/null +++ b/sys/src/9/xen/uartxen.c @@ -0,0 +1,334 @@ +/* + * 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" + +extern PhysUart xenphysuart; + +static Uart xenuart = { + .name = "xencons", + .freq = 1843200, + .phys = &xenphysuart, +}; + +struct { + struct xencons_interface *intf; + int evtchn; + Lock txlock; +} xencons; + +/* + * 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(CONSOLEIO_write, n, buf); +} + +static void kick(Uart*); +/* + * 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 +xenuartputs(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); +} + +/* + * Handle channel event from console + */ +static void +interrupt(Ureg*, void *arg) +{ + char c; + unsigned long cons; + Uart *uart; + struct xencons_interface *con = xencons.intf; + + uart = &xenuart; + + cons = con->in_cons; + coherence(); + while (cons != con->in_prod) { + c = con->in[MASK_XENCONS_IDX(cons++, con->in)]; + uartrecv(uart, c & 0xFF); + } + coherence(); + con->in_cons = cons; + kick(nil); +} + +static Uart* +pnp(void) +{ + return &xenuart; +} + +static void +enable(Uart*, int ie) +{ + if(ie) + intrenable(xencons.evtchn, interrupt, 0, BUSUNKNOWN, "Xen console"); +} + +static void +disable(Uart*) +{ +} + +/* + * Send queued output to guest OS console + */ +static void +kick(Uart*) +{ + 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); +} + +static void +donothing(Uart*, int) +{ +} + +static int +donothingint(Uart*, int) +{ + return 0; +} + +static int +baud(Uart *uart, int n) +{ + if(n <= 0) + return -1; + + uart->baud = n; + return 0; +} + +static int +bits(Uart *uart, int n) +{ + switch(n){ + case 7: + case 8: + break; + default: + return -1; + } + + uart->bits = n; + return 0; +} + +static int +stop(Uart *uart, int n) +{ + if(n != 1) + return -1; + uart->stop = n; + return 0; +} + +static int +parity(Uart *uart, int n) +{ + if(n != 'n') + return -1; + uart->parity = n; + return 0; +} + +static long +status(Uart *uart, void *buf, long n, long offset) +{ + char *p; + + p = malloc(READSTR); + if(p == nil) + error(Enomem); + snprint(p, READSTR, + "b%d\n" + "dev(%d) type(%d) framing(%d) overruns(%d) " + "berr(%d) serr(%d)\n", + + uart->baud, + uart->dev, + uart->type, + uart->ferr, + uart->oerr, + uart->berr, + uart->serr + ); + n = readstr(offset, buf, n, p); + free(p); + + return n; +} + +void +xenputc(Uart*, int c) +{ + struct xencons_interface *con = xencons.intf; + unsigned long prod; + + c &= 0xFF; + + ilock(&xencons.txlock); + /* + while(con->out_cons == con->out_prod) + HYPERVISOR_yield(); + */ + if(con->out_cons == con->out_prod){ + iunlock(&xencons.txlock); + return; + } + + prod = con->out_prod; + + if((con->out[MASK_XENCONS_IDX(prod++, con->out)] = c) == '\n') + con->out[MASK_XENCONS_IDX(prod++, con->out)] = '\r'; + + coherence(); + con->out_prod = prod; + xenchannotify(xencons.evtchn); + iunlock(&xencons.txlock); +} + +int +xengetc(Uart*) +{ + struct xencons_interface *con = xencons.intf; + char c; + + c = 0; + + if(con->in_cons != con->in_prod){ + coherence(); + c = con->in[MASK_XENCONS_IDX(con->in_cons++, con->in)]; + if (con->in_cons == con->in_prod) + xenchannotify(xencons.evtchn); + } + + return c; +} + +PhysUart xenphysuart = { + .name = "xenuart", + + .pnp = pnp, + .enable = enable, + .disable = disable, + .kick = kick, + .dobreak = donothing, + .baud = baud, + .bits = bits, + .stop = stop, + .parity = parity, + .modemctl = donothing, + .rts = donothing, + .dtr = donothing, + .status = status, + .fifo = donothing, + + .getc = xengetc, + .putc = xenputc, +}; + +/* console=0 to enable */ +void +xenconsinit(void) +{ + xencons.intf = (struct xencons_interface*)mmumapframe(XENCONSOLE, xenstart->console_mfn); + xencons.evtchn = xenstart->console_evtchn; + + consuart = &xenuart; +} + +void +kbdenable(void) +{ + Uart *uart; + int n; + char *p, *cmd; + + if((p = getconf("console")) == nil) + return; + n = strtoul(p, &cmd, 0); + if(p == cmd || n != 0) + return; + uart = &xenuart; + + (*uart->phys->enable)(uart, 0); + uartctl(uart, "b9600 l8 pn s1"); + if(*cmd != '\0') + uartctl(uart, cmd); + + consuart = uart; + uart->console = 1; + + uartputs("CONSOLE1\n", 9); + + //*(char*)0 = 0; +} + |