cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hvc_xen.c (16439B)


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