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