From 48d50de8e086e6669979889fb58dbf1092d10347 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Tue, 10 Sep 2013 16:39:46 +0200 Subject: console: buffer and show origin of guest PV writes Guests other than domain 0 using the console output have previously been controlled by the VERBOSE #define, but with no designation of which guest's output was on the console. This patch converts the HVM output buffering to be used by all domains except the hardware domain (dom0): stripping non-printable characters, line buffering the output, and prefixing it with the domain ID. This is especially useful for debugging stub domains during early boot. Signed-off-by: Daniel De Graaf Acked-by: Keir Fraser --- xen/drivers/char/console.c | 93 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 17 deletions(-) (limited to 'xen/drivers') diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index e47ddf21cc..508f84592e 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include /* for do_console_io */ @@ -375,6 +376,7 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count) { char kbuf[128]; int kcount; + struct domain *cd = current->domain; while ( count > 0 ) { @@ -388,18 +390,58 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer, int count) return -EFAULT; kbuf[kcount] = '\0'; - spin_lock_irq(&console_lock); + if ( is_hardware_domain(cd) ) + { + /* Use direct console output as it could be interactive */ + spin_lock_irq(&console_lock); - sercon_puts(kbuf); - video_puts(kbuf); + sercon_puts(kbuf); + video_puts(kbuf); - if ( opt_console_to_ring ) - { - conring_puts(kbuf); - tasklet_schedule(¬ify_dom0_con_ring_tasklet); + if ( opt_console_to_ring ) + { + conring_puts(kbuf); + tasklet_schedule(¬ify_dom0_con_ring_tasklet); + } + + spin_unlock_irq(&console_lock); } + else + { + char *kin = kbuf, *kout = kbuf, c; - spin_unlock_irq(&console_lock); + /* Strip non-printable characters */ + for ( ; ; ) + { + c = *kin++; + if ( c == '\0' || c == '\n' ) + break; + if ( isprint(c) || c == '\t' ) + *kout++ = c; + } + *kout = '\0'; + spin_lock(&cd->pbuf_lock); + if ( c == '\n' ) + { + kcount = kin - kbuf; + cd->pbuf[cd->pbuf_idx] = '\0'; + guest_printk(cd, XENLOG_G_DEBUG "%s%s\n", cd->pbuf, kbuf); + cd->pbuf_idx = 0; + } + else if ( cd->pbuf_idx + kcount < (DOMAIN_PBUF_SIZE - 1) ) + { + /* buffer the output until a newline */ + memcpy(cd->pbuf + cd->pbuf_idx, kbuf, kcount); + cd->pbuf_idx += kcount; + } + else + { + cd->pbuf[cd->pbuf_idx] = '\0'; + guest_printk(cd, XENLOG_G_DEBUG "%s%s\n", cd->pbuf, kbuf); + cd->pbuf_idx = 0; + } + spin_unlock(&cd->pbuf_lock); + } guest_handle_add_offset(buffer, kcount); count -= kcount; @@ -504,12 +546,12 @@ static int printk_prefix_check(char *p, char **pp) ((loglvl < upper_thresh) && printk_ratelimit())); } -static void printk_start_of_line(void) +static void printk_start_of_line(const char *prefix) { struct tm tm; char tstr[32]; - __putstr("(XEN) "); + __putstr(prefix); if ( !opt_console_timestamps ) return; @@ -524,12 +566,11 @@ static void printk_start_of_line(void) __putstr(tstr); } -void printk(const char *fmt, ...) +static void vprintk_common(const char *prefix, const char *fmt, va_list args) { static char buf[1024]; static int start_of_line = 1, do_print; - va_list args; char *p, *q; unsigned long flags; @@ -537,9 +578,7 @@ void printk(const char *fmt, ...) local_irq_save(flags); spin_lock_recursive(&console_lock); - va_start(args, fmt); (void)vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); p = buf; @@ -551,7 +590,7 @@ void printk(const char *fmt, ...) if ( do_print ) { if ( start_of_line ) - printk_start_of_line(); + printk_start_of_line(prefix); __putstr(p); __putstr("\n"); } @@ -566,7 +605,7 @@ void printk(const char *fmt, ...) if ( do_print ) { if ( start_of_line ) - printk_start_of_line(); + printk_start_of_line(prefix); __putstr(p); } start_of_line = 0; @@ -576,6 +615,26 @@ void printk(const char *fmt, ...) local_irq_restore(flags); } +void printk(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintk_common("(XEN) ", fmt, args); + va_end(args); +} + +void guest_printk(const struct domain *d, const char *fmt, ...) +{ + va_list args; + char prefix[16]; + + snprintf(prefix, sizeof(prefix), "(d%d) ", d->domain_id); + + va_start(args, fmt); + vprintk_common(prefix, fmt, args); + va_end(args); +} + void __init console_init_preirq(void) { char *p; @@ -792,7 +851,7 @@ int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst) snprintf(lost_str, sizeof(lost_str), "%d", lost); /* console_lock may already be acquired by printk(). */ spin_lock_recursive(&console_lock); - printk_start_of_line(); + printk_start_of_line("(XEN) "); __putstr("printk: "); __putstr(lost_str); __putstr(" messages suppressed.\n"); -- cgit v1.2.3