extern char *log_dir;
static int log_hv_fd = -1;
+static evtchn_port_or_error_t log_hv_evtchn = -1;
static int xc_handle = -1;
+static int xce_handle = -1;
struct buffer
{
char *serialpath;
int use_consolepath;
int ring_ref;
- evtchn_port_t local_port;
- evtchn_port_t remote_port;
+ evtchn_port_or_error_t local_port;
+ evtchn_port_or_error_t remote_port;
int xce_handle;
struct xencons_interface *interface;
};
static void handle_ring_read(struct domain *dom)
{
- evtchn_port_t port;
+ evtchn_port_or_error_t port;
if ((port = xc_evtchn_pending(dom->xce_handle)) == -1)
return;
char buffer[1024*16];
char *bufptr = buffer;
unsigned int size = sizeof(buffer);
- if (xc_readconsolering(xc_handle, &bufptr, &size, 1) == 0) {
+ static uint32_t index = 0;
+ evtchn_port_or_error_t port;
+
+ if ((port = xc_evtchn_pending(xce_handle)) == -1)
+ return;
+
+ if (xc_readconsolering(xc_handle, &bufptr, &size, 0, 1, &index) == 0) {
int len = write(log_hv_fd, buffer, size);
if (len < 0)
dolog(LOG_ERR, "Failed to write hypervisor log: %d (%s)",
errno, strerror(errno));
}
+
+ (void)xc_evtchn_unmask(xce_handle, port);
}
static void handle_log_reload(void)
if (log_hv) {
xc_handle = xc_interface_open();
- if (xc_handle == -1)
+ if (xc_handle == -1) {
dolog(LOG_ERR, "Failed to open xc handle: %d (%s)",
errno, strerror(errno));
- else
- log_hv_fd = create_hv_log();
+ goto out;
+ }
+ xce_handle = xc_evtchn_open();
+ if (xce_handle == -1) {
+ dolog(LOG_ERR, "Failed to open xce handle: %d (%s)",
+ errno, strerror(errno));
+ goto out;
+ }
+ log_hv_fd = create_hv_log();
+ if (log_hv_fd == -1)
+ goto out;
+ log_hv_evtchn = xc_evtchn_bind_virq(xce_handle, VIRQ_CON_RING);
+ if (log_hv_evtchn == -1) {
+ dolog(LOG_ERR, "Failed to bind to VIRQ_CON_RING: "
+ "%d (%s)", errno, strerror(errno));
+ goto out;
+ }
}
for (;;) {
struct domain *d, *n;
- struct timeval timeout = { 1, 0 }; /* Read HV logs every 1 second */
int max_fd = -1;
FD_ZERO(&readfds);
FD_SET(xs_fileno(xs), &readfds);
max_fd = MAX(xs_fileno(xs), max_fd);
+ if (log_hv) {
+ FD_SET(xc_evtchn_fd(xce_handle), &readfds);
+ max_fd = MAX(xc_evtchn_fd(xce_handle), max_fd);
+ }
+
for (d = dom_head; d; d = d->next) {
if (d->xce_handle != -1) {
int evtchn_fd = xc_evtchn_fd(d->xce_handle);
}
}
- /* XXX I wish we didn't have to busy wait for hypervisor logs
- * but there's no obvious way to get event channel notifications
- * for new HV log data as we can with guest */
- ret = select(max_fd + 1, &readfds, &writefds, 0,
- log_hv_fd != -1 ? &timeout : NULL);
+ ret = select(max_fd + 1, &readfds, &writefds, 0, NULL);
if (log_reload) {
handle_log_reload();
break;
}
- /* Always process HV logs even if not a timeout */
- if (log_hv_fd != -1)
+ if (log_hv && FD_ISSET(xc_evtchn_fd(xce_handle), &readfds))
handle_hv_logs();
- /* Must not check returned FDSET if it was a timeout */
- if (ret == 0)
+ if (ret <= 0)
continue;
if (FD_ISSET(xs_fileno(xs), &readfds))
}
}
+ out:
if (log_hv_fd != -1) {
close(log_hv_fd);
log_hv_fd = -1;
xc_interface_close(xc_handle);
xc_handle = -1;
}
+ if (xce_handle != -1) {
+ xc_evtchn_close(xce_handle);
+ xce_handle = -1;
+ }
+ log_hv_evtchn = -1;
}
/*
int xc_readconsolering(int xc_handle,
char **pbuffer,
unsigned int *pnr_chars,
- int clear)
+ int clear, int incremental, uint32_t *pindex)
{
int ret;
DECLARE_SYSCTL;
sysctl.cmd = XEN_SYSCTL_readconsole;
set_xen_guest_handle(sysctl.u.readconsole.buffer, buffer);
- sysctl.u.readconsole.count = nr_chars;
- sysctl.u.readconsole.clear = clear;
+ sysctl.u.readconsole.count = nr_chars;
+ sysctl.u.readconsole.clear = clear;
+ sysctl.u.readconsole.incremental = 0;
+ if ( pindex )
+ {
+ sysctl.u.readconsole.index = *pindex;
+ sysctl.u.readconsole.incremental = incremental;
+ }
if ( (ret = lock_pages(buffer, nr_chars)) != 0 )
return ret;
if ( (ret = do_sysctl(xc_handle, &sysctl)) == 0 )
+ {
*pnr_chars = sysctl.u.readconsole.count;
+ if ( pindex )
+ *pindex = sysctl.u.readconsole.index;
+ }
unlock_pages(buffer, nr_chars);
int xc_readconsolering(int xc_handle,
char **pbuffer,
unsigned int *pnr_chars,
- int clear);
+ int clear, int incremental, uint32_t *pindex);
int xc_send_debug_keys(int xc_handle, char *keys);
PyObject *args,
PyObject *kwds)
{
- unsigned int clear = 0;
+ unsigned int clear = 0, index = 0, incremental = 0;
char _str[32768], *str = _str;
unsigned int count = 32768;
int ret;
- static char *kwd_list[] = { "clear", NULL };
+ static char *kwd_list[] = { "clear", "index", "incremental", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) )
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iii", kwd_list,
+ &clear, &index, &incremental) )
return NULL;
- ret = xc_readconsolering(self->xc_handle, &str, &count, clear);
+ ret = xc_readconsolering(self->xc_handle, &str, &count, clear,
+ incremental, &index);
if ( ret < 0 )
return pyxc_error_to_exception();
if ( ret )
break;
- ret = read_console_ring(
- guest_handle_cast(op->u.readconsole.buffer, char),
- &op->u.readconsole.count,
- op->u.readconsole.clear);
+ ret = read_console_ring(&op->u.readconsole);
if ( copy_to_guest(u_sysctl, op, 1) )
ret = -EFAULT;
}
#include <asm/io.h>
#include <asm/div64.h>
#include <xsm/xsm.h>
+#include <public/sysctl.h>
/* console: comma-separated list of console outputs. */
static char opt_console[30] = OPT_CONSOLE_STR;
#define CONRING_SIZE 16384
#define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))
static char conring[CONRING_SIZE];
-static unsigned int conringc, conringp;
+static uint32_t conringc, conringp;
static int sercon_handle = -1;
static void putchar_console_ring(int c)
{
+ ASSERT(spin_is_locked(&console_lock));
conring[CONRING_IDX_MASK(conringp++)] = c;
- if ( (conringp - conringc) > CONRING_SIZE )
+ if ( (uint32_t)(conringp - conringc) > CONRING_SIZE )
conringc = conringp - CONRING_SIZE;
}
-long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear)
+long read_console_ring(struct xen_sysctl_readconsole *op)
{
- unsigned int idx, len, max, sofar, c;
- unsigned long flags;
+ XEN_GUEST_HANDLE(char) str;
+ uint32_t idx, len, max, sofar, c;
- max = *pcount;
+ str = guest_handle_cast(op->buffer, char),
+ max = op->count;
sofar = 0;
c = conringc;
+ if ( op->incremental && ((int32_t)(op->index - c) < 0) )
+ c = op->index;
+
while ( (c != conringp) && (sofar < max) )
{
idx = CONRING_IDX_MASK(c);
c += len;
}
- if ( clear )
+ if ( op->clear )
{
- spin_lock_irqsave(&console_lock, flags);
- if ( (conringp - c) > CONRING_SIZE )
+ spin_lock_irq(&console_lock);
+ if ( (uint32_t)(conringp - c) > CONRING_SIZE )
conringc = conringp - CONRING_SIZE;
else
conringc = c;
- spin_unlock_irqrestore(&console_lock, flags);
+ spin_unlock_irq(&console_lock);
}
- *pcount = sofar;
+ op->count = sofar;
+ op->index = c;
+
return 0;
}
return -EFAULT;
kbuf[kcount] = '\0';
+ spin_lock_irq(&console_lock);
+
sercon_puts(kbuf);
vga_puts(kbuf);
if ( opt_console_to_ring )
+ {
for ( kptr = kbuf; *kptr != '\0'; kptr++ )
putchar_console_ring(*kptr);
-
- if ( opt_console_to_ring )
send_guest_global_virq(dom0, VIRQ_CON_RING);
+ }
+
+ spin_unlock_irq(&console_lock);
guest_handle_add_offset(buffer, kcount);
count -= kcount;
{
int c;
+ ASSERT(spin_is_locked(&console_lock));
+
sercon_puts(str);
vga_puts(str);
serial_set_rx_handler(sercon_handle, serial_rx);
/* HELLO WORLD --- start-of-day banner text. */
+ spin_lock(&console_lock);
__putstr(xen_banner());
+ spin_unlock(&console_lock);
printk("Xen version %d.%d%s (%s@%s) (%s) %s\n",
xen_major_version(), xen_minor_version(), xen_extra_version(),
xen_compile_by(), xen_compile_domain(),
#include "xen.h"
#include "domctl.h"
-#define XEN_SYSCTL_INTERFACE_VERSION 0x00000005
+#define XEN_SYSCTL_INTERFACE_VERSION 0x00000006
/*
* Read console content from Xen buffer ring.
*/
#define XEN_SYSCTL_readconsole 1
struct xen_sysctl_readconsole {
- /* IN variables. */
- uint32_t clear; /* Non-zero -> clear after reading. */
- XEN_GUEST_HANDLE_64(char) buffer; /* Buffer start */
- /* IN/OUT variables. */
- uint32_t count; /* In: Buffer size; Out: Used buffer size */
+ /* IN: Non-zero -> clear after reading. */
+ uint8_t clear;
+ /* IN: Non-zero -> start index specified by @index field. */
+ uint8_t incremental;
+ uint8_t pad0, pad1;
+ /*
+ * IN: Start index for consuming from ring buffer (if @incremental);
+ * OUT: End index after consuming from ring buffer.
+ */
+ uint32_t index;
+ /* IN: Virtual address to write console data. */
+ XEN_GUEST_HANDLE_64(char) buffer;
+ /* IN: Size of buffer; OUT: Bytes written to buffer. */
+ uint32_t count;
};
typedef struct xen_sysctl_readconsole xen_sysctl_readconsole_t;
DEFINE_XEN_GUEST_HANDLE(xen_sysctl_readconsole_t);
#include <xen/guest_access.h>
#include <public/xen.h>
-long read_console_ring(XEN_GUEST_HANDLE(char), u32 *, int);
+struct xen_sysctl_readconsole;
+long read_console_ring(struct xen_sysctl_readconsole *op);
void init_console(void);
void console_endboot(void);