[PATCH 2/11] drivers/watchdog: Eliminate a NULL pointer dereference
[safe/jmp/linux-2.6] / drivers / char / hvc_xen.c
index 2413af3..60446f8 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/types.h>
 
 #include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
 #include <xen/page.h>
 #include <xen/events.h>
 #include <xen/interface/io/console.h>
@@ -39,9 +41,14 @@ static int xencons_irq;
 
 /* ------------------------------------------------------------------ */
 
+static unsigned long console_pfn = ~0ul;
+
 static inline struct xencons_interface *xencons_interface(void)
 {
-       return mfn_to_virt(xen_start_info->console.domU.mfn);
+       if (console_pfn == ~0ul)
+               return mfn_to_virt(xen_start_info->console.domU.mfn);
+       else
+               return __va(console_pfn << PAGE_SHIFT);
 }
 
 static inline void notify_daemon(void)
@@ -50,7 +57,7 @@ static inline void notify_daemon(void)
        notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
 }
 
-static int write_console(uint32_t vtermno, const char *data, int len)
+static int __write_console(const char *data, int len)
 {
        struct xencons_interface *intf = xencons_interface();
        XENCONS_RING_IDX cons, prod;
@@ -71,6 +78,29 @@ static int write_console(uint32_t vtermno, const char *data, int len)
        return sent;
 }
 
+static int write_console(uint32_t vtermno, const char *data, int len)
+{
+       int ret = len;
+
+       /*
+        * Make sure the whole buffer is emitted, polling if
+        * necessary.  We don't ever want to rely on the hvc daemon
+        * because the most interesting console output is when the
+        * kernel is crippled.
+        */
+       while (len) {
+               int sent = __write_console(data, len);
+               
+               data += sent;
+               len -= sent;
+
+               if (unlikely(len))
+                       HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
+       }
+
+       return ret;
+}
+
 static int read_console(uint32_t vtermno, char *buf, int len)
 {
        struct xencons_interface *intf = xencons_interface();
@@ -92,29 +122,44 @@ static int read_console(uint32_t vtermno, char *buf, int len)
        return recv;
 }
 
-static struct hv_ops hvc_ops = {
+static const struct hv_ops hvc_ops = {
        .get_chars = read_console,
        .put_chars = write_console,
+       .notifier_add = notifier_add_irq,
+       .notifier_del = notifier_del_irq,
+       .notifier_hangup = notifier_hangup_irq,
 };
 
 static int __init xen_init(void)
 {
        struct hvc_struct *hp;
 
-       if (!is_running_on_xen())
-               return 0;
+       if (!xen_pv_domain() ||
+           xen_initial_domain() ||
+           !xen_start_info->console.domU.evtchn)
+               return -ENODEV;
 
        xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
        if (xencons_irq < 0)
-               xencons_irq = 0 /* NO_IRQ */;
+               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;
+
+       console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn);
+
        return 0;
 }
 
+void xen_console_resume(void)
+{
+       if (xencons_irq)
+               rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq);
+}
+
 static void __exit xen_fini(void)
 {
        if (hvc)
@@ -123,7 +168,7 @@ static void __exit xen_fini(void)
 
 static int xen_cons_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_pv_domain())
                return 0;
 
        hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
@@ -155,6 +200,7 @@ static void xenboot_write_console(struct console *console, const char *string,
 
        raw_console_write(string, len);
 
+       write_console(0, "(early) ", 8);
        while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
                linelen = pos-string+off;
                if (off + linelen > len)