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