GNU Linux-libre 4.14.328-gnu1
[releases.git] / drivers / tty / hvc / 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/irq.h>
25 #include <linux/init.h>
26 #include <linux/types.h>
27 #include <linux/list.h>
28 #include <linux/serial_core.h>
29
30 #include <asm/io.h>
31 #include <asm/xen/hypervisor.h>
32
33 #include <xen/xen.h>
34 #include <xen/interface/xen.h>
35 #include <xen/hvm.h>
36 #include <xen/grant_table.h>
37 #include <xen/page.h>
38 #include <xen/events.h>
39 #include <xen/interface/io/console.h>
40 #include <xen/interface/sched.h>
41 #include <xen/hvc-console.h>
42 #include <xen/xenbus.h>
43
44 #include "hvc_console.h"
45
46 #define HVC_COOKIE   0x58656e /* "Xen" in hex */
47
48 struct xencons_info {
49         struct list_head list;
50         struct xenbus_device *xbdev;
51         struct xencons_interface *intf;
52         unsigned int evtchn;
53         XENCONS_RING_IDX out_cons;
54         unsigned int out_cons_same;
55         struct hvc_struct *hvc;
56         int irq;
57         int vtermno;
58         grant_ref_t gntref;
59         spinlock_t ring_lock;
60 };
61
62 static LIST_HEAD(xenconsoles);
63 static DEFINE_SPINLOCK(xencons_lock);
64
65 /* ------------------------------------------------------------------ */
66
67 static struct xencons_info *vtermno_to_xencons(int vtermno)
68 {
69         struct xencons_info *entry, *ret = NULL;
70         unsigned long flags;
71
72         spin_lock_irqsave(&xencons_lock, flags);
73         if (list_empty(&xenconsoles)) {
74                 spin_unlock_irqrestore(&xencons_lock, flags);
75                 return NULL;
76         }
77
78         list_for_each_entry(entry, &xenconsoles, list) {
79                 if (entry->vtermno == vtermno) {
80                         ret  = entry;
81                         break;
82                 }
83         }
84         spin_unlock_irqrestore(&xencons_lock, flags);
85
86         return ret;
87 }
88
89 static inline int xenbus_devid_to_vtermno(int devid)
90 {
91         return devid + HVC_COOKIE;
92 }
93
94 static inline void notify_daemon(struct xencons_info *cons)
95 {
96         /* Use evtchn: this is called early, before irq is set up. */
97         notify_remote_via_evtchn(cons->evtchn);
98 }
99
100 static int __write_console(struct xencons_info *xencons,
101                 const char *data, int len)
102 {
103         XENCONS_RING_IDX cons, prod;
104         struct xencons_interface *intf = xencons->intf;
105         int sent = 0;
106         unsigned long flags;
107
108         spin_lock_irqsave(&xencons->ring_lock, flags);
109         cons = intf->out_cons;
110         prod = intf->out_prod;
111         mb();                   /* update queue values before going on */
112
113         if ((prod - cons) > sizeof(intf->out)) {
114                 spin_unlock_irqrestore(&xencons->ring_lock, flags);
115                 pr_err_once("xencons: Illegal ring page indices");
116                 return -EINVAL;
117         }
118
119         while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
120                 intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
121
122         wmb();                  /* write ring before updating pointer */
123         intf->out_prod = prod;
124         spin_unlock_irqrestore(&xencons->ring_lock, flags);
125
126         if (sent)
127                 notify_daemon(xencons);
128         return sent;
129 }
130
131 static int domU_write_console(uint32_t vtermno, const char *data, int len)
132 {
133         int ret = len;
134         struct xencons_info *cons = vtermno_to_xencons(vtermno);
135         if (cons == NULL)
136                 return -EINVAL;
137
138         /*
139          * Make sure the whole buffer is emitted, polling if
140          * necessary.  We don't ever want to rely on the hvc daemon
141          * because the most interesting console output is when the
142          * kernel is crippled.
143          */
144         while (len) {
145                 int sent = __write_console(cons, data, len);
146
147                 if (sent < 0)
148                         return sent;
149
150                 data += sent;
151                 len -= sent;
152
153                 if (unlikely(len))
154                         HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
155         }
156
157         return ret;
158 }
159
160 static int domU_read_console(uint32_t vtermno, char *buf, int len)
161 {
162         struct xencons_interface *intf;
163         XENCONS_RING_IDX cons, prod;
164         int recv = 0;
165         struct xencons_info *xencons = vtermno_to_xencons(vtermno);
166         unsigned int eoiflag = 0;
167         unsigned long flags;
168
169         if (xencons == NULL)
170                 return -EINVAL;
171         intf = xencons->intf;
172
173         spin_lock_irqsave(&xencons->ring_lock, flags);
174         cons = intf->in_cons;
175         prod = intf->in_prod;
176         mb();                   /* get pointers before reading ring */
177
178         if ((prod - cons) > sizeof(intf->in)) {
179                 spin_unlock_irqrestore(&xencons->ring_lock, flags);
180                 pr_err_once("xencons: Illegal ring page indices");
181                 return -EINVAL;
182         }
183
184         while (cons != prod && recv < len)
185                 buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
186
187         mb();                   /* read ring before consuming */
188         intf->in_cons = cons;
189
190         /*
191          * When to mark interrupt having been spurious:
192          * - there was no new data to be read, and
193          * - the backend did not consume some output bytes, and
194          * - the previous round with no read data didn't see consumed bytes
195          *   (we might have a race with an interrupt being in flight while
196          *   updating xencons->out_cons, so account for that by allowing one
197          *   round without any visible reason)
198          */
199         if (intf->out_cons != xencons->out_cons) {
200                 xencons->out_cons = intf->out_cons;
201                 xencons->out_cons_same = 0;
202         }
203         if (!recv && xencons->out_cons_same++ > 1) {
204                 eoiflag = XEN_EOI_FLAG_SPURIOUS;
205         }
206         spin_unlock_irqrestore(&xencons->ring_lock, flags);
207
208         if (recv) {
209                 notify_daemon(xencons);
210         }
211
212         xen_irq_lateeoi(xencons->irq, eoiflag);
213
214         return recv;
215 }
216
217 static const struct hv_ops domU_hvc_ops = {
218         .get_chars = domU_read_console,
219         .put_chars = domU_write_console,
220         .notifier_add = notifier_add_irq,
221         .notifier_del = notifier_del_irq,
222         .notifier_hangup = notifier_hangup_irq,
223 };
224
225 static int dom0_read_console(uint32_t vtermno, char *buf, int len)
226 {
227         return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);
228 }
229
230 /*
231  * Either for a dom0 to write to the system console, or a domU with a
232  * debug version of Xen
233  */
234 static int dom0_write_console(uint32_t vtermno, const char *str, int len)
235 {
236         int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
237         if (rc < 0)
238                 return rc;
239
240         return len;
241 }
242
243 static const struct hv_ops dom0_hvc_ops = {
244         .get_chars = dom0_read_console,
245         .put_chars = dom0_write_console,
246         .notifier_add = notifier_add_irq,
247         .notifier_del = notifier_del_irq,
248         .notifier_hangup = notifier_hangup_irq,
249 };
250
251 static int xen_hvm_console_init(void)
252 {
253         int r;
254         uint64_t v = 0;
255         unsigned long gfn, flags;
256         struct xencons_info *info;
257
258         if (!xen_hvm_domain())
259                 return -ENODEV;
260
261         info = vtermno_to_xencons(HVC_COOKIE);
262         if (!info) {
263                 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
264                 if (!info)
265                         return -ENOMEM;
266                 spin_lock_init(&info->ring_lock);
267         } else if (info->intf != NULL) {
268                 /* already configured */
269                 return 0;
270         }
271         /*
272          * If the toolstack (or the hypervisor) hasn't set these values, the
273          * default value is 0. Even though gfn = 0 and evtchn = 0 are
274          * theoretically correct values, in practice they never are and they
275          * mean that a legacy toolstack hasn't initialized the pv console correctly.
276          */
277         r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
278         if (r < 0 || v == 0)
279                 goto err;
280         info->evtchn = v;
281         v = 0;
282         r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
283         if (r < 0 || v == 0)
284                 goto err;
285         gfn = v;
286         info->intf = xen_remap(gfn << XEN_PAGE_SHIFT, XEN_PAGE_SIZE);
287         if (info->intf == NULL)
288                 goto err;
289         info->vtermno = HVC_COOKIE;
290
291         spin_lock_irqsave(&xencons_lock, flags);
292         list_add_tail(&info->list, &xenconsoles);
293         spin_unlock_irqrestore(&xencons_lock, flags);
294
295         return 0;
296 err:
297         kfree(info);
298         return -ENODEV;
299 }
300
301 static int xencons_info_pv_init(struct xencons_info *info, int vtermno)
302 {
303         spin_lock_init(&info->ring_lock);
304         info->evtchn = xen_start_info->console.domU.evtchn;
305         /* GFN == MFN for PV guest */
306         info->intf = gfn_to_virt(xen_start_info->console.domU.mfn);
307         info->vtermno = vtermno;
308
309         list_add_tail(&info->list, &xenconsoles);
310
311         return 0;
312 }
313
314 static int xen_pv_console_init(void)
315 {
316         struct xencons_info *info;
317         unsigned long flags;
318
319         if (!xen_pv_domain())
320                 return -ENODEV;
321
322         if (!xen_start_info->console.domU.evtchn)
323                 return -ENODEV;
324
325         info = vtermno_to_xencons(HVC_COOKIE);
326         if (!info) {
327                 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
328                 if (!info)
329                         return -ENOMEM;
330         } else if (info->intf != NULL) {
331                 /* already configured */
332                 return 0;
333         }
334         spin_lock_irqsave(&xencons_lock, flags);
335         xencons_info_pv_init(info, HVC_COOKIE);
336         spin_unlock_irqrestore(&xencons_lock, flags);
337
338         return 0;
339 }
340
341 static int xen_initial_domain_console_init(void)
342 {
343         struct xencons_info *info;
344         unsigned long flags;
345
346         if (!xen_initial_domain())
347                 return -ENODEV;
348
349         info = vtermno_to_xencons(HVC_COOKIE);
350         if (!info) {
351                 info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
352                 if (!info)
353                         return -ENOMEM;
354                 spin_lock_init(&info->ring_lock);
355         }
356
357         info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);
358         info->vtermno = HVC_COOKIE;
359
360         spin_lock_irqsave(&xencons_lock, flags);
361         list_add_tail(&info->list, &xenconsoles);
362         spin_unlock_irqrestore(&xencons_lock, flags);
363
364         return 0;
365 }
366
367 static void xen_console_update_evtchn(struct xencons_info *info)
368 {
369         if (xen_hvm_domain()) {
370                 uint64_t v = 0;
371                 int err;
372
373                 err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
374                 if (!err && v)
375                         info->evtchn = v;
376         } else
377                 info->evtchn = xen_start_info->console.domU.evtchn;
378 }
379
380 void xen_console_resume(void)
381 {
382         struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);
383         if (info != NULL && info->irq) {
384                 if (!xen_initial_domain())
385                         xen_console_update_evtchn(info);
386                 rebind_evtchn_irq(info->evtchn, info->irq);
387         }
388 }
389
390 #ifdef CONFIG_HVC_XEN_FRONTEND
391 static void xencons_disconnect_backend(struct xencons_info *info)
392 {
393         if (info->irq > 0)
394                 unbind_from_irqhandler(info->irq, NULL);
395         info->irq = 0;
396         if (info->evtchn > 0)
397                 xenbus_free_evtchn(info->xbdev, info->evtchn);
398         info->evtchn = 0;
399         if (info->gntref > 0)
400                 gnttab_free_grant_references(info->gntref);
401         info->gntref = 0;
402         if (info->hvc != NULL)
403                 hvc_remove(info->hvc);
404         info->hvc = NULL;
405 }
406
407 static void xencons_free(struct xencons_info *info)
408 {
409         free_page((unsigned long)info->intf);
410         info->intf = NULL;
411         info->vtermno = 0;
412         kfree(info);
413 }
414
415 static int xen_console_remove(struct xencons_info *info)
416 {
417         unsigned long flags;
418
419         xencons_disconnect_backend(info);
420         spin_lock_irqsave(&xencons_lock, flags);
421         list_del(&info->list);
422         spin_unlock_irqrestore(&xencons_lock, flags);
423         if (info->xbdev != NULL)
424                 xencons_free(info);
425         else {
426                 if (xen_hvm_domain())
427                         iounmap(info->intf);
428                 kfree(info);
429         }
430         return 0;
431 }
432
433 static int xencons_remove(struct xenbus_device *dev)
434 {
435         return xen_console_remove(dev_get_drvdata(&dev->dev));
436 }
437
438 static int xencons_connect_backend(struct xenbus_device *dev,
439                                   struct xencons_info *info)
440 {
441         int ret, evtchn, devid, ref, irq;
442         struct xenbus_transaction xbt;
443         grant_ref_t gref_head;
444
445         ret = xenbus_alloc_evtchn(dev, &evtchn);
446         if (ret)
447                 return ret;
448         info->evtchn = evtchn;
449         irq = bind_interdomain_evtchn_to_irq_lateeoi(dev->otherend_id, evtchn);
450         if (irq < 0)
451                 return irq;
452         info->irq = irq;
453         devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
454         info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid),
455                         irq, &domU_hvc_ops, 256);
456         if (IS_ERR(info->hvc))
457                 return PTR_ERR(info->hvc);
458         ret = gnttab_alloc_grant_references(1, &gref_head);
459         if (ret < 0)
460                 return ret;
461         info->gntref = gref_head;
462         ref = gnttab_claim_grant_reference(&gref_head);
463         if (ref < 0)
464                 return ref;
465         gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,
466                                         virt_to_gfn(info->intf), 0);
467
468  again:
469         ret = xenbus_transaction_start(&xbt);
470         if (ret) {
471                 xenbus_dev_fatal(dev, ret, "starting transaction");
472                 return ret;
473         }
474         ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref);
475         if (ret)
476                 goto error_xenbus;
477         ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
478                             evtchn);
479         if (ret)
480                 goto error_xenbus;
481         ret = xenbus_transaction_end(xbt, 0);
482         if (ret) {
483                 if (ret == -EAGAIN)
484                         goto again;
485                 xenbus_dev_fatal(dev, ret, "completing transaction");
486                 return ret;
487         }
488
489         xenbus_switch_state(dev, XenbusStateInitialised);
490         return 0;
491
492  error_xenbus:
493         xenbus_transaction_end(xbt, 1);
494         xenbus_dev_fatal(dev, ret, "writing xenstore");
495         return ret;
496 }
497
498 static int xencons_probe(struct xenbus_device *dev,
499                                   const struct xenbus_device_id *id)
500 {
501         int ret, devid;
502         struct xencons_info *info;
503         unsigned long flags;
504
505         devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
506         if (devid == 0)
507                 return -ENODEV;
508
509         info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
510         if (!info)
511                 return -ENOMEM;
512         spin_lock_init(&info->ring_lock);
513         dev_set_drvdata(&dev->dev, info);
514         info->xbdev = dev;
515         info->vtermno = xenbus_devid_to_vtermno(devid);
516         info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
517         if (!info->intf)
518                 goto error_nomem;
519
520         ret = xencons_connect_backend(dev, info);
521         if (ret < 0)
522                 goto error;
523         spin_lock_irqsave(&xencons_lock, flags);
524         list_add_tail(&info->list, &xenconsoles);
525         spin_unlock_irqrestore(&xencons_lock, flags);
526
527         return 0;
528
529  error_nomem:
530         ret = -ENOMEM;
531         xenbus_dev_fatal(dev, ret, "allocating device memory");
532  error:
533         xencons_disconnect_backend(info);
534         xencons_free(info);
535         return ret;
536 }
537
538 static int xencons_resume(struct xenbus_device *dev)
539 {
540         struct xencons_info *info = dev_get_drvdata(&dev->dev);
541
542         xencons_disconnect_backend(info);
543         memset(info->intf, 0, XEN_PAGE_SIZE);
544         return xencons_connect_backend(dev, info);
545 }
546
547 static void xencons_backend_changed(struct xenbus_device *dev,
548                                    enum xenbus_state backend_state)
549 {
550         switch (backend_state) {
551         case XenbusStateReconfiguring:
552         case XenbusStateReconfigured:
553         case XenbusStateInitialising:
554         case XenbusStateInitialised:
555         case XenbusStateUnknown:
556                 break;
557
558         case XenbusStateInitWait:
559                 break;
560
561         case XenbusStateConnected:
562                 xenbus_switch_state(dev, XenbusStateConnected);
563                 break;
564
565         case XenbusStateClosed:
566                 if (dev->state == XenbusStateClosed)
567                         break;
568                 /* Missed the backend's CLOSING state -- fallthrough */
569         case XenbusStateClosing:
570                 xenbus_frontend_closed(dev);
571                 break;
572         }
573 }
574
575 static const struct xenbus_device_id xencons_ids[] = {
576         { "console" },
577         { "" }
578 };
579
580 static struct xenbus_driver xencons_driver = {
581         .name = "xenconsole",
582         .ids = xencons_ids,
583         .probe = xencons_probe,
584         .remove = xencons_remove,
585         .resume = xencons_resume,
586         .otherend_changed = xencons_backend_changed,
587 };
588 #endif /* CONFIG_HVC_XEN_FRONTEND */
589
590 static int __init xen_hvc_init(void)
591 {
592         int r;
593         struct xencons_info *info;
594         const struct hv_ops *ops;
595
596         if (!xen_domain())
597                 return -ENODEV;
598
599         if (xen_initial_domain()) {
600                 ops = &dom0_hvc_ops;
601                 r = xen_initial_domain_console_init();
602                 if (r < 0)
603                         return r;
604                 info = vtermno_to_xencons(HVC_COOKIE);
605         } else {
606                 ops = &domU_hvc_ops;
607                 if (xen_hvm_domain())
608                         r = xen_hvm_console_init();
609                 else
610                         r = xen_pv_console_init();
611                 if (r < 0)
612                         return r;
613
614                 info = vtermno_to_xencons(HVC_COOKIE);
615                 info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn);
616         }
617         if (info->irq < 0)
618                 info->irq = 0; /* NO_IRQ */
619         else
620                 irq_set_noprobe(info->irq);
621
622         info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);
623         if (IS_ERR(info->hvc)) {
624                 unsigned long flags;
625
626                 r = PTR_ERR(info->hvc);
627                 spin_lock_irqsave(&xencons_lock, flags);
628                 list_del(&info->list);
629                 spin_unlock_irqrestore(&xencons_lock, flags);
630                 if (info->irq)
631                         unbind_from_irqhandler(info->irq, NULL);
632                 kfree(info);
633                 return r;
634         }
635
636         r = 0;
637 #ifdef CONFIG_HVC_XEN_FRONTEND
638         r = xenbus_register_frontend(&xencons_driver);
639 #endif
640         return r;
641 }
642 device_initcall(xen_hvc_init);
643
644 static int xen_cons_init(void)
645 {
646         const struct hv_ops *ops;
647
648         if (!xen_domain())
649                 return 0;
650
651         if (xen_initial_domain())
652                 ops = &dom0_hvc_ops;
653         else {
654                 int r;
655                 ops = &domU_hvc_ops;
656
657                 if (xen_hvm_domain())
658                         r = xen_hvm_console_init();
659                 else
660                         r = xen_pv_console_init();
661                 if (r < 0)
662                         return r;
663         }
664
665         hvc_instantiate(HVC_COOKIE, 0, ops);
666         return 0;
667 }
668 console_initcall(xen_cons_init);
669
670 #ifdef CONFIG_X86
671 static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len)
672 {
673         if (xen_cpuid_base())
674                 outsb(0xe9, str, len);
675 }
676 #else
677 static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len) { }
678 #endif
679
680 #ifdef CONFIG_EARLY_PRINTK
681 static int __init xenboot_setup_console(struct console *console, char *string)
682 {
683         static struct xencons_info xenboot;
684
685         if (xen_initial_domain())
686                 return 0;
687         if (!xen_pv_domain())
688                 return -ENODEV;
689
690         return xencons_info_pv_init(&xenboot, 0);
691 }
692
693 static void xenboot_write_console(struct console *console, const char *string,
694                                   unsigned len)
695 {
696         unsigned int linelen, off = 0;
697         const char *pos;
698
699         if (!xen_pv_domain()) {
700                 xen_hvm_early_write(0, string, len);
701                 return;
702         }
703
704         dom0_write_console(0, string, len);
705
706         if (xen_initial_domain())
707                 return;
708
709         domU_write_console(0, "(early) ", 8);
710         while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
711                 linelen = pos-string+off;
712                 if (off + linelen > len)
713                         break;
714                 domU_write_console(0, string+off, linelen);
715                 domU_write_console(0, "\r\n", 2);
716                 off += linelen + 1;
717         }
718         if (off < len)
719                 domU_write_console(0, string+off, len-off);
720 }
721
722 struct console xenboot_console = {
723         .name           = "xenboot",
724         .write          = xenboot_write_console,
725         .setup          = xenboot_setup_console,
726         .flags          = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
727         .index          = -1,
728 };
729 #endif  /* CONFIG_EARLY_PRINTK */
730
731 void xen_raw_console_write(const char *str)
732 {
733         ssize_t len = strlen(str);
734         int rc = 0;
735
736         if (xen_domain()) {
737                 rc = dom0_write_console(0, str, len);
738                 if (rc != -ENOSYS || !xen_hvm_domain())
739                         return;
740         }
741         xen_hvm_early_write(0, str, len);
742 }
743
744 void xen_raw_printk(const char *fmt, ...)
745 {
746         static char buf[512];
747         va_list ap;
748
749         va_start(ap, fmt);
750         vsnprintf(buf, sizeof(buf), fmt, ap);
751         va_end(ap);
752
753         xen_raw_console_write(buf);
754 }
755
756 static void xenboot_earlycon_write(struct console *console,
757                                   const char *string,
758                                   unsigned len)
759 {
760         dom0_write_console(0, string, len);
761 }
762
763 static int __init xenboot_earlycon_setup(struct earlycon_device *device,
764                                             const char *opt)
765 {
766         device->con->write = xenboot_earlycon_write;
767         return 0;
768 }
769 EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);