323 lines
5 KiB
C
323 lines
5 KiB
C
/*
|
|
* 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);
|
|
}
|
|
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;
|
|
|
|
ilock(&xencons.txlock);
|
|
prod = con->out_prod;
|
|
if((prod - con->out_cons) < sizeof(con->out)){
|
|
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);
|
|
}
|
|
|
|
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;
|
|
consuart->console = 1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|