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