xref: /openbmc/linux/drivers/tty/hvc/hvc_xen.c (revision cabce92d)
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 
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 
76 static inline int xenbus_devid_to_vtermno(int devid)
77 {
78 	return devid + HVC_COOKIE;
79 }
80 
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 
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 
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 
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 
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  */
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 
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 
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 
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 
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 
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 
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
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 
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 
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 
420 static void xencons_remove(struct xenbus_device *dev)
421 {
422 	xen_console_remove(dev_get_drvdata(&dev->dev));
423 }
424 
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 
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 
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 
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 
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 
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
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
665 static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len) { }
666 #endif
667 
668 #ifdef CONFIG_EARLY_PRINTK
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 
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 
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 
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 
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 
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