Commit b536b4b9623084d86f2b1f19cb44a2d6d74f00bf

Authored by Jeremy Fitzhardinge
Committed by Jeremy Fitzhardinge
1 parent 8b84ad942b

xen: use the hvc console infrastructure for Xen console

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 <kraxel@suse.de>
Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Acked-by: Ingo Molnar <mingo@elte.hu>
Acked-by: Olof Johansson <olof@lixom.net>

Showing 7 changed files with 182 additions and 1 deletions Side-by-side Diff

arch/i386/xen/events.c
... ... @@ -244,7 +244,7 @@
244 244 return irq;
245 245 }
246 246  
247   -static int bind_evtchn_to_irq(unsigned int evtchn)
  247 +int bind_evtchn_to_irq(unsigned int evtchn)
248 248 {
249 249 int irq;
250 250  
... ... @@ -269,6 +269,7 @@
269 269  
270 270 return irq;
271 271 }
  272 +EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
272 273  
273 274 static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
274 275 {
arch/x86_64/kernel/early_printk.c
... ... @@ -6,6 +6,7 @@
6 6 #include <asm/io.h>
7 7 #include <asm/processor.h>
8 8 #include <asm/fcntl.h>
  9 +#include <xen/hvc-console.h>
9 10  
10 11 /* Simple VGA output */
11 12  
... ... @@ -242,6 +243,10 @@
242 243 simnow_init(buf + 6);
243 244 early_console = &simnow_console;
244 245 keep_early = 1;
  246 +#ifdef CONFIG_HVC_XEN
  247 + } else if (!strncmp(buf, "xen", 3)) {
  248 + early_console = &xenboot_console;
  249 +#endif
245 250 }
246 251  
247 252 if (keep_early)
drivers/char/Kconfig
... ... @@ -604,6 +604,14 @@
604 604 help
605 605 Toshiba's Cell Reference Set Beat Console device driver
606 606  
  607 +config HVC_XEN
  608 + bool "Xen Hypervisor Console support"
  609 + depends on XEN
  610 + select HVC_DRIVER
  611 + default y
  612 + help
  613 + Xen virtual console device driver
  614 +
607 615 config HVCS
608 616 tristate "IBM Hypervisor Virtual Console Server support"
609 617 depends on PPC_PSERIES
drivers/char/Makefile
... ... @@ -48,6 +48,7 @@
48 48 obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
49 49 obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
50 50 obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
  51 +obj-$(CONFIG_HVC_XEN) += hvc_xen.o
51 52 obj-$(CONFIG_RAW_DRIVER) += raw.o
52 53 obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
53 54 obj-$(CONFIG_MSPEC) += mspec.o
drivers/char/hvc_xen.c
  1 +/*
  2 + * xen console driver interface to hvc_console.c
  3 + *
  4 + * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License as published by
  8 + * the Free Software Foundation; either version 2 of the License, or
  9 + * (at your option) any later version.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + *
  16 + * You should have received a copy of the GNU General Public License
  17 + * along with this program; if not, write to the Free Software
  18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 + */
  20 +
  21 +#include <linux/console.h>
  22 +#include <linux/delay.h>
  23 +#include <linux/err.h>
  24 +#include <linux/init.h>
  25 +#include <linux/types.h>
  26 +
  27 +#include <asm/xen/hypervisor.h>
  28 +#include <xen/page.h>
  29 +#include <xen/events.h>
  30 +#include <xen/interface/io/console.h>
  31 +#include <xen/hvc-console.h>
  32 +
  33 +#include "hvc_console.h"
  34 +
  35 +#define HVC_COOKIE 0x58656e /* "Xen" in hex */
  36 +
  37 +static struct hvc_struct *hvc;
  38 +static int xencons_irq;
  39 +
  40 +/* ------------------------------------------------------------------ */
  41 +
  42 +static inline struct xencons_interface *xencons_interface(void)
  43 +{
  44 + return mfn_to_virt(xen_start_info->console.domU.mfn);
  45 +}
  46 +
  47 +static inline void notify_daemon(void)
  48 +{
  49 + /* Use evtchn: this is called early, before irq is set up. */
  50 + notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
  51 +}
  52 +
  53 +static int write_console(uint32_t vtermno, const char *data, int len)
  54 +{
  55 + struct xencons_interface *intf = xencons_interface();
  56 + XENCONS_RING_IDX cons, prod;
  57 + int sent = 0;
  58 +
  59 + cons = intf->out_cons;
  60 + prod = intf->out_prod;
  61 + mb(); /* update queue values before going on */
  62 + BUG_ON((prod - cons) > sizeof(intf->out));
  63 +
  64 + while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
  65 + intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
  66 +
  67 + wmb(); /* write ring before updating pointer */
  68 + intf->out_prod = prod;
  69 +
  70 + notify_daemon();
  71 + return sent;
  72 +}
  73 +
  74 +static int read_console(uint32_t vtermno, char *buf, int len)
  75 +{
  76 + struct xencons_interface *intf = xencons_interface();
  77 + XENCONS_RING_IDX cons, prod;
  78 + int recv = 0;
  79 +
  80 + cons = intf->in_cons;
  81 + prod = intf->in_prod;
  82 + mb(); /* get pointers before reading ring */
  83 + BUG_ON((prod - cons) > sizeof(intf->in));
  84 +
  85 + while (cons != prod && recv < len)
  86 + buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
  87 +
  88 + mb(); /* read ring before consuming */
  89 + intf->in_cons = cons;
  90 +
  91 + notify_daemon();
  92 + return recv;
  93 +}
  94 +
  95 +static struct hv_ops hvc_ops = {
  96 + .get_chars = read_console,
  97 + .put_chars = write_console,
  98 +};
  99 +
  100 +static int __init xen_init(void)
  101 +{
  102 + struct hvc_struct *hp;
  103 +
  104 + if (!is_running_on_xen())
  105 + return 0;
  106 +
  107 + xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
  108 + if (xencons_irq < 0)
  109 + xencons_irq = 0 /* NO_IRQ */;
  110 + hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
  111 + if (IS_ERR(hp))
  112 + return PTR_ERR(hp);
  113 +
  114 + hvc = hp;
  115 + return 0;
  116 +}
  117 +
  118 +static void __exit xen_fini(void)
  119 +{
  120 + if (hvc)
  121 + hvc_remove(hvc);
  122 +}
  123 +
  124 +static int xen_cons_init(void)
  125 +{
  126 + if (!is_running_on_xen())
  127 + return 0;
  128 +
  129 + hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
  130 + return 0;
  131 +}
  132 +
  133 +module_init(xen_init);
  134 +module_exit(xen_fini);
  135 +console_initcall(xen_cons_init);
  136 +
  137 +static void xenboot_write_console(struct console *console, const char *string,
  138 + unsigned len)
  139 +{
  140 + unsigned int linelen, off = 0;
  141 + const char *pos;
  142 +
  143 + while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
  144 + linelen = pos-string+off;
  145 + if (off + linelen > len)
  146 + break;
  147 + write_console(0, string+off, linelen);
  148 + write_console(0, "\r\n", 2);
  149 + off += linelen + 1;
  150 + }
  151 + if (off < len)
  152 + write_console(0, string+off, len-off);
  153 +}
  154 +
  155 +struct console xenboot_console = {
  156 + .name = "xenboot",
  157 + .write = xenboot_write_console,
  158 + .flags = CON_PRINTBUFFER | CON_BOOT,
  159 +};
include/xen/events.h
... ... @@ -13,6 +13,7 @@
13 13 XEN_NR_IPIS,
14 14 };
15 15  
  16 +int bind_evtchn_to_irq(unsigned int evtchn);
16 17 int bind_evtchn_to_irqhandler(unsigned int evtchn,
17 18 irq_handler_t handler,
18 19 unsigned long irqflags, const char *devname,
include/xen/hvc-console.h
  1 +#ifndef XEN_HVC_CONSOLE_H
  2 +#define XEN_HVC_CONSOLE_H
  3 +
  4 +extern struct console xenboot_console;
  5 +
  6 +#endif /* XEN_HVC_CONSOLE_H */