Implement a Xen back-end for hvc console. * * * Add early printk support via hvc console, enable using "earlyprintk=xen" on the kernel command line. From: Gerd Hoffmann Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Chris Wright Acked-by: Ingo Molnar Acked-by: Olof Johansson --- arch/i386/xen/events.c | 3 arch/x86_64/kernel/early_printk.c | 5 + drivers/char/Kconfig | 8 + drivers/char/Makefile | 1 drivers/char/hvc_xen.c | 159 +++++++++++++++++++++++++++++++++++++ include/xen/events.h | 1 include/xen/hvc-console.h | 6 + 7 files changed, 182 insertions(+), 1 deletion(-) =================================================================== --- a/arch/i386/xen/events.c +++ b/arch/i386/xen/events.c @@ -244,7 +244,7 @@ static int find_unbound_irq(void) return irq; } -static int bind_evtchn_to_irq(unsigned int evtchn) +int bind_evtchn_to_irq(unsigned int evtchn) { int irq; @@ -269,6 +269,7 @@ static int bind_evtchn_to_irq(unsigned i return irq; } +EXPORT_SYMBOL_GPL(bind_evtchn_to_irq); static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) { =================================================================== --- a/arch/x86_64/kernel/early_printk.c +++ b/arch/x86_64/kernel/early_printk.c @@ -6,6 +6,7 @@ #include #include #include +#include /* Simple VGA output */ @@ -242,6 +243,10 @@ static int __init setup_early_printk(cha simnow_init(buf + 6); early_console = &simnow_console; keep_early = 1; +#ifdef CONFIG_HVC_XEN + } else if (!strncmp(buf, "xen", 3)) { + early_console = &xenboot_console; +#endif } if (keep_early) =================================================================== --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -663,6 +663,14 @@ config HVC_BEAT help Toshiba's Cell Reference Set Beat Console device driver +config HVC_XEN + bool "Xen Hypervisor Console support" + depends on XEN + select HVC_DRIVER + default y + help + Xen virtual console device driver + config HVCS tristate "IBM Hypervisor Virtual Console Server support" depends on PPC_PSERIES =================================================================== --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o +obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MSPEC) += mspec.o =================================================================== --- /dev/null +++ b/drivers/char/hvc_xen.c @@ -0,0 +1,159 @@ +/* + * xen console driver interface to hvc_console.c + * + * (c) 2007 Gerd Hoffmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "hvc_console.h" + +#define HVC_COOKIE 0x58656e /* "Xen" in hex */ + +static struct hvc_struct *hvc; +static int xencons_irq; + +/* ------------------------------------------------------------------ */ + +static inline struct xencons_interface *xencons_interface(void) +{ + return mfn_to_virt(xen_start_info->console.domU.mfn); +} + +static inline void notify_daemon(void) +{ + /* Use evtchn: this is called early, before irq is set up. */ + notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); +} + +static int write_console(uint32_t vtermno, const char *data, int len) +{ + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; + int sent = 0; + + cons = intf->out_cons; + prod = intf->out_prod; + mb(); + BUG_ON((prod - cons) > sizeof(intf->out)); + + while ((sent < len) && ((prod - cons) < sizeof(intf->out))) + intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; + + wmb(); + intf->out_prod = prod; + + notify_daemon(); + return sent; +} + +static int read_console(uint32_t vtermno, char *buf, int len) +{ + struct xencons_interface *intf = xencons_interface(); + XENCONS_RING_IDX cons, prod; + int recv = 0; + + cons = intf->in_cons; + prod = intf->in_prod; + mb(); + BUG_ON((prod - cons) > sizeof(intf->in)); + + while (cons != prod && recv < len) + buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++,intf->in)]; + + mb(); + intf->in_cons = cons; + + notify_daemon(); + return recv; +} + +static struct hv_ops hvc_ops = { + .get_chars = read_console, + .put_chars = write_console, +}; + +static int __init xen_init(void) +{ + struct hvc_struct *hp; + + if (!is_running_on_xen()) + return 0; + + xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); + if (xencons_irq < 0) + xencons_irq = 0 /* NO_IRQ */; + hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256); + if (IS_ERR(hp)) + return PTR_ERR(hp); + + hvc = hp; + return 0; +} + +static void __exit xen_fini(void) +{ + if (hvc) + hvc_remove(hvc); +} + +static int xen_cons_init(void) +{ + if (!is_running_on_xen()) + return 0; + + hvc_instantiate(HVC_COOKIE, 0, &hvc_ops); + return 0; +} + +module_init(xen_init); +module_exit(xen_fini); +console_initcall(xen_cons_init); + +static void xenboot_write_console(struct console *console, const char *string, + unsigned len) +{ + unsigned int linelen, off = 0; + const char *pos; + + while (off < len && NULL != (pos = strchr(string+off, '\n'))) { + linelen = pos-string+off; + if (off + linelen > len) + break; + write_console(0, string+off, linelen); + write_console(0, "\r\n", 2); + off += linelen + 1; + } + if (off < len) + write_console(0, string+off, len-off); +} + +struct console xenboot_console = { + .name = "xenboot", + .write = xenboot_write_console, + .flags = CON_PRINTBUFFER | CON_BOOT, +}; =================================================================== --- a/include/xen/events.h +++ b/include/xen/events.h @@ -13,6 +13,7 @@ enum ipi_vector { XEN_NR_IPIS, }; +int bind_evtchn_to_irq(unsigned int evtchn); int bind_evtchn_to_irqhandler(unsigned int evtchn, irq_handler_t handler, unsigned long irqflags, const char *devname, =================================================================== --- /dev/null +++ b/include/xen/hvc-console.h @@ -0,0 +1,6 @@ +#ifndef XEN_HVC_CONSOLE_H +#define XEN_HVC_CONSOLE_H + +extern struct console xenboot_console; + +#endif /* XEN_HVC_CONSOLE_H */ -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/