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