• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
vtermno_to_xencons(int vtermno)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 
xenbus_devid_to_vtermno(int devid)75 static inline int xenbus_devid_to_vtermno(int devid)
76 {
77 	return devid + HVC_COOKIE;
78 }
79 
notify_daemon(struct xencons_info * cons)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 
__write_console(struct xencons_info * xencons,const char * data,int len)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 
domU_write_console(uint32_t vtermno,const char * data,int len)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 
domU_read_console(uint32_t vtermno,char * buf,int len)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 
dom0_read_console(uint32_t vtermno,char * buf,int len)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  */
dom0_write_console(uint32_t vtermno,const char * str,int len)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 
xen_hvm_console_init(void)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 = xen_remap(gfn << XEN_PAGE_SHIFT, XEN_PAGE_SIZE);
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 
xencons_info_pv_init(struct xencons_info * info,int vtermno)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 
xen_pv_console_init(void)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 
xen_initial_domain_console_init(void)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 
xen_console_update_evtchn(struct xencons_info * info)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 
xen_console_resume(void)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
xencons_disconnect_backend(struct xencons_info * info)364 static void xencons_disconnect_backend(struct xencons_info *info)
365 {
366 	if (info->hvc != NULL)
367 		hvc_remove(info->hvc);
368 	info->hvc = NULL;
369 	if (info->irq > 0) {
370 		evtchn_put(info->evtchn);
371 		info->irq = 0;
372 		info->evtchn = 0;
373 	}
374 	/* evtchn_put() will also close it so this is only an error path */
375 	if (info->evtchn > 0)
376 		xenbus_free_evtchn(info->xbdev, info->evtchn);
377 	info->evtchn = 0;
378 	if (info->gntref > 0)
379 		gnttab_free_grant_references(info->gntref);
380 	info->gntref = 0;
381 }
382 
xencons_free(struct xencons_info * info)383 static void xencons_free(struct xencons_info *info)
384 {
385 	free_page((unsigned long)info->intf);
386 	info->intf = NULL;
387 	info->vtermno = 0;
388 	kfree(info);
389 }
390 
xen_console_remove(struct xencons_info * info)391 static int xen_console_remove(struct xencons_info *info)
392 {
393 	unsigned long flags;
394 
395 	xencons_disconnect_backend(info);
396 	spin_lock_irqsave(&xencons_lock, flags);
397 	list_del(&info->list);
398 	spin_unlock_irqrestore(&xencons_lock, flags);
399 	if (info->xbdev != NULL)
400 		xencons_free(info);
401 	else {
402 		if (xen_hvm_domain())
403 			iounmap(info->intf);
404 		kfree(info);
405 	}
406 	return 0;
407 }
408 
xencons_remove(struct xenbus_device * dev)409 static int xencons_remove(struct xenbus_device *dev)
410 {
411 	return xen_console_remove(dev_get_drvdata(&dev->dev));
412 }
413 
xencons_connect_backend(struct xenbus_device * dev,struct xencons_info * info)414 static int xencons_connect_backend(struct xenbus_device *dev,
415 				  struct xencons_info *info)
416 {
417 	int ret, evtchn, devid, ref, irq;
418 	struct xenbus_transaction xbt;
419 	grant_ref_t gref_head;
420 
421 	ret = xenbus_alloc_evtchn(dev, &evtchn);
422 	if (ret)
423 		return ret;
424 	info->evtchn = evtchn;
425 	irq = bind_interdomain_evtchn_to_irq_lateeoi(dev->otherend_id, evtchn);
426 	if (irq < 0)
427 		return irq;
428 	info->irq = irq;
429 	devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
430 	info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid),
431 			irq, &domU_hvc_ops, 256);
432 	if (IS_ERR(info->hvc))
433 		return PTR_ERR(info->hvc);
434 	ret = gnttab_alloc_grant_references(1, &gref_head);
435 	if (ret < 0)
436 		return ret;
437 	info->gntref = gref_head;
438 	ref = gnttab_claim_grant_reference(&gref_head);
439 	if (ref < 0)
440 		return ref;
441 	gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,
442 					virt_to_gfn(info->intf), 0);
443 
444  again:
445 	ret = xenbus_transaction_start(&xbt);
446 	if (ret) {
447 		xenbus_dev_fatal(dev, ret, "starting transaction");
448 		return ret;
449 	}
450 	ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref);
451 	if (ret)
452 		goto error_xenbus;
453 	ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
454 			    evtchn);
455 	if (ret)
456 		goto error_xenbus;
457 	ret = xenbus_transaction_end(xbt, 0);
458 	if (ret) {
459 		if (ret == -EAGAIN)
460 			goto again;
461 		xenbus_dev_fatal(dev, ret, "completing transaction");
462 		return ret;
463 	}
464 
465 	xenbus_switch_state(dev, XenbusStateInitialised);
466 	return 0;
467 
468  error_xenbus:
469 	xenbus_transaction_end(xbt, 1);
470 	xenbus_dev_fatal(dev, ret, "writing xenstore");
471 	return ret;
472 }
473 
xencons_probe(struct xenbus_device * dev,const struct xenbus_device_id * id)474 static int xencons_probe(struct xenbus_device *dev,
475 				  const struct xenbus_device_id *id)
476 {
477 	int ret, devid;
478 	struct xencons_info *info;
479 	unsigned long flags;
480 
481 	devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
482 	if (devid == 0)
483 		return -ENODEV;
484 
485 	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
486 	if (!info)
487 		return -ENOMEM;
488 	dev_set_drvdata(&dev->dev, info);
489 	info->xbdev = dev;
490 	info->vtermno = xenbus_devid_to_vtermno(devid);
491 	info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
492 	if (!info->intf)
493 		goto error_nomem;
494 
495 	ret = xencons_connect_backend(dev, info);
496 	if (ret < 0)
497 		goto error;
498 	spin_lock_irqsave(&xencons_lock, flags);
499 	list_add_tail(&info->list, &xenconsoles);
500 	spin_unlock_irqrestore(&xencons_lock, flags);
501 
502 	return 0;
503 
504  error_nomem:
505 	ret = -ENOMEM;
506 	xenbus_dev_fatal(dev, ret, "allocating device memory");
507  error:
508 	xencons_disconnect_backend(info);
509 	xencons_free(info);
510 	return ret;
511 }
512 
xencons_resume(struct xenbus_device * dev)513 static int xencons_resume(struct xenbus_device *dev)
514 {
515 	struct xencons_info *info = dev_get_drvdata(&dev->dev);
516 
517 	xencons_disconnect_backend(info);
518 	memset(info->intf, 0, XEN_PAGE_SIZE);
519 	return xencons_connect_backend(dev, info);
520 }
521 
xencons_backend_changed(struct xenbus_device * dev,enum xenbus_state backend_state)522 static void xencons_backend_changed(struct xenbus_device *dev,
523 				   enum xenbus_state backend_state)
524 {
525 	switch (backend_state) {
526 	case XenbusStateReconfiguring:
527 	case XenbusStateReconfigured:
528 	case XenbusStateInitialising:
529 	case XenbusStateInitialised:
530 	case XenbusStateUnknown:
531 		break;
532 
533 	case XenbusStateInitWait:
534 		break;
535 
536 	case XenbusStateConnected:
537 		xenbus_switch_state(dev, XenbusStateConnected);
538 		break;
539 
540 	case XenbusStateClosed:
541 		if (dev->state == XenbusStateClosed)
542 			break;
543 		fallthrough;	/* Missed the backend's CLOSING state */
544 	case XenbusStateClosing: {
545 		struct xencons_info *info = dev_get_drvdata(&dev->dev);;
546 
547 		/*
548 		 * Don't tear down the evtchn and grant ref before the other
549 		 * end has disconnected, but do stop userspace from trying
550 		 * to use the device before we allow the backend to close.
551 		 */
552 		if (info->hvc) {
553 			hvc_remove(info->hvc);
554 			info->hvc = NULL;
555 		}
556 
557 		xenbus_frontend_closed(dev);
558 		break;
559 	}
560 	}
561 }
562 
563 static const struct xenbus_device_id xencons_ids[] = {
564 	{ "console" },
565 	{ "" }
566 };
567 
568 static struct xenbus_driver xencons_driver = {
569 	.name = "xenconsole",
570 	.ids = xencons_ids,
571 	.probe = xencons_probe,
572 	.remove = xencons_remove,
573 	.resume = xencons_resume,
574 	.otherend_changed = xencons_backend_changed,
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 			goto register_fe;
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 			goto register_fe;
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 			evtchn_put(info->evtchn);
620 		kfree(info);
621 		return r;
622 	}
623 
624 	r = 0;
625  register_fe:
626 #ifdef CONFIG_HVC_XEN_FRONTEND
627 	r = xenbus_register_frontend(&xencons_driver);
628 #endif
629 	return r;
630 }
631 device_initcall(xen_hvc_init);
632 
xen_cons_init(void)633 static int xen_cons_init(void)
634 {
635 	const struct hv_ops *ops;
636 
637 	if (!xen_domain())
638 		return 0;
639 
640 	if (xen_initial_domain())
641 		ops = &dom0_hvc_ops;
642 	else {
643 		int r;
644 		ops = &domU_hvc_ops;
645 
646 		if (xen_hvm_domain())
647 			r = xen_hvm_console_init();
648 		else
649 			r = xen_pv_console_init();
650 		if (r < 0)
651 			return r;
652 	}
653 
654 	hvc_instantiate(HVC_COOKIE, 0, ops);
655 	return 0;
656 }
657 console_initcall(xen_cons_init);
658 
659 #ifdef CONFIG_X86
xen_hvm_early_write(uint32_t vtermno,const char * str,int len)660 static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len)
661 {
662 	if (xen_cpuid_base())
663 		outsb(0xe9, str, len);
664 }
665 #else
xen_hvm_early_write(uint32_t vtermno,const char * str,int len)666 static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len) { }
667 #endif
668 
669 #ifdef CONFIG_EARLY_PRINTK
xenboot_console_setup(struct console * console,char * string)670 static int __init xenboot_console_setup(struct console *console, char *string)
671 {
672 	static struct xencons_info xenboot;
673 
674 	if (xen_initial_domain())
675 		return 0;
676 	if (!xen_pv_domain())
677 		return -ENODEV;
678 
679 	return xencons_info_pv_init(&xenboot, 0);
680 }
681 
xenboot_write_console(struct console * console,const char * string,unsigned len)682 static void xenboot_write_console(struct console *console, const char *string,
683 				  unsigned len)
684 {
685 	unsigned int linelen, off = 0;
686 	const char *pos;
687 
688 	if (!xen_pv_domain()) {
689 		xen_hvm_early_write(0, string, len);
690 		return;
691 	}
692 
693 	dom0_write_console(0, string, len);
694 
695 	if (xen_initial_domain())
696 		return;
697 
698 	domU_write_console(0, "(early) ", 8);
699 	while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
700 		linelen = pos-string+off;
701 		if (off + linelen > len)
702 			break;
703 		domU_write_console(0, string+off, linelen);
704 		domU_write_console(0, "\r\n", 2);
705 		off += linelen + 1;
706 	}
707 	if (off < len)
708 		domU_write_console(0, string+off, len-off);
709 }
710 
711 struct console xenboot_console = {
712 	.name		= "xenboot",
713 	.write		= xenboot_write_console,
714 	.setup		= xenboot_console_setup,
715 	.flags		= CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
716 	.index		= -1,
717 };
718 #endif	/* CONFIG_EARLY_PRINTK */
719 
xen_raw_console_write(const char * str)720 void xen_raw_console_write(const char *str)
721 {
722 	ssize_t len = strlen(str);
723 	int rc = 0;
724 
725 	if (xen_domain()) {
726 		rc = dom0_write_console(0, str, len);
727 		if (rc != -ENOSYS || !xen_hvm_domain())
728 			return;
729 	}
730 	xen_hvm_early_write(0, str, len);
731 }
732 
xen_raw_printk(const char * fmt,...)733 void xen_raw_printk(const char *fmt, ...)
734 {
735 	static char buf[512];
736 	va_list ap;
737 
738 	va_start(ap, fmt);
739 	vsnprintf(buf, sizeof(buf), fmt, ap);
740 	va_end(ap);
741 
742 	xen_raw_console_write(buf);
743 }
744 
xenboot_earlycon_write(struct console * console,const char * string,unsigned len)745 static void xenboot_earlycon_write(struct console *console,
746 				  const char *string,
747 				  unsigned len)
748 {
749 	dom0_write_console(0, string, len);
750 }
751 
xenboot_earlycon_setup(struct earlycon_device * device,const char * opt)752 static int __init xenboot_earlycon_setup(struct earlycon_device *device,
753 					    const char *opt)
754 {
755 	device->con->write = xenboot_earlycon_write;
756 	return 0;
757 }
758 EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);
759