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

connection.c (14648B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *
      4 * Copyright (c) 2009, Microsoft Corporation.
      5 *
      6 * Authors:
      7 *   Haiyang Zhang <haiyangz@microsoft.com>
      8 *   Hank Janssen  <hjanssen@microsoft.com>
      9 */
     10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     11
     12#include <linux/kernel.h>
     13#include <linux/sched.h>
     14#include <linux/wait.h>
     15#include <linux/delay.h>
     16#include <linux/mm.h>
     17#include <linux/module.h>
     18#include <linux/slab.h>
     19#include <linux/vmalloc.h>
     20#include <linux/hyperv.h>
     21#include <linux/export.h>
     22#include <linux/io.h>
     23#include <linux/set_memory.h>
     24#include <asm/mshyperv.h>
     25
     26#include "hyperv_vmbus.h"
     27
     28
     29struct vmbus_connection vmbus_connection = {
     30	.conn_state		= DISCONNECTED,
     31	.unload_event		= COMPLETION_INITIALIZER(
     32				  vmbus_connection.unload_event),
     33	.next_gpadl_handle	= ATOMIC_INIT(0xE1E10),
     34
     35	.ready_for_suspend_event = COMPLETION_INITIALIZER(
     36				  vmbus_connection.ready_for_suspend_event),
     37	.ready_for_resume_event	= COMPLETION_INITIALIZER(
     38				  vmbus_connection.ready_for_resume_event),
     39};
     40EXPORT_SYMBOL_GPL(vmbus_connection);
     41
     42/*
     43 * Negotiated protocol version with the host.
     44 */
     45__u32 vmbus_proto_version;
     46EXPORT_SYMBOL_GPL(vmbus_proto_version);
     47
     48/*
     49 * Table of VMBus versions listed from newest to oldest.
     50 * VERSION_WIN7 and VERSION_WS2008 are no longer supported in
     51 * Linux guests and are not listed.
     52 */
     53static __u32 vmbus_versions[] = {
     54	VERSION_WIN10_V5_3,
     55	VERSION_WIN10_V5_2,
     56	VERSION_WIN10_V5_1,
     57	VERSION_WIN10_V5,
     58	VERSION_WIN10_V4_1,
     59	VERSION_WIN10,
     60	VERSION_WIN8_1,
     61	VERSION_WIN8
     62};
     63
     64/*
     65 * Maximal VMBus protocol version guests can negotiate.  Useful to cap the
     66 * VMBus version for testing and debugging purpose.
     67 */
     68static uint max_version = VERSION_WIN10_V5_3;
     69
     70module_param(max_version, uint, S_IRUGO);
     71MODULE_PARM_DESC(max_version,
     72		 "Maximal VMBus protocol version which can be negotiated");
     73
     74int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
     75{
     76	int ret = 0;
     77	struct vmbus_channel_initiate_contact *msg;
     78	unsigned long flags;
     79
     80	init_completion(&msginfo->waitevent);
     81
     82	msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;
     83
     84	memset(msg, 0, sizeof(*msg));
     85	msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
     86	msg->vmbus_version_requested = version;
     87
     88	/*
     89	 * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
     90	 * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
     91	 * and for subsequent messages, we must use the Message Connection ID
     92	 * field in the host-returned Version Response Message. And, with
     93	 * VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
     94	 * tell the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
     95	 * compatibility.
     96	 *
     97	 * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
     98	 */
     99	if (version >= VERSION_WIN10_V5) {
    100		msg->msg_sint = VMBUS_MESSAGE_SINT;
    101		vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
    102	} else {
    103		msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
    104		vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
    105	}
    106
    107	msg->monitor_page1 = vmbus_connection.monitor_pages_pa[0];
    108	msg->monitor_page2 = vmbus_connection.monitor_pages_pa[1];
    109
    110	msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU);
    111
    112	/*
    113	 * Add to list before we send the request since we may
    114	 * receive the response before returning from this routine
    115	 */
    116	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
    117	list_add_tail(&msginfo->msglistentry,
    118		      &vmbus_connection.chn_msg_list);
    119
    120	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
    121
    122	ret = vmbus_post_msg(msg,
    123			     sizeof(struct vmbus_channel_initiate_contact),
    124			     true);
    125
    126	trace_vmbus_negotiate_version(msg, ret);
    127
    128	if (ret != 0) {
    129		spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
    130		list_del(&msginfo->msglistentry);
    131		spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
    132					flags);
    133		return ret;
    134	}
    135
    136	/* Wait for the connection response */
    137	wait_for_completion(&msginfo->waitevent);
    138
    139	spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
    140	list_del(&msginfo->msglistentry);
    141	spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
    142
    143	/* Check if successful */
    144	if (msginfo->response.version_response.version_supported) {
    145		vmbus_connection.conn_state = CONNECTED;
    146
    147		if (version >= VERSION_WIN10_V5)
    148			vmbus_connection.msg_conn_id =
    149				msginfo->response.version_response.msg_conn_id;
    150	} else {
    151		return -ECONNREFUSED;
    152	}
    153
    154	return ret;
    155}
    156
    157/*
    158 * vmbus_connect - Sends a connect request on the partition service connection
    159 */
    160int vmbus_connect(void)
    161{
    162	struct vmbus_channel_msginfo *msginfo = NULL;
    163	int i, ret = 0;
    164	__u32 version;
    165
    166	/* Initialize the vmbus connection */
    167	vmbus_connection.conn_state = CONNECTING;
    168	vmbus_connection.work_queue = create_workqueue("hv_vmbus_con");
    169	if (!vmbus_connection.work_queue) {
    170		ret = -ENOMEM;
    171		goto cleanup;
    172	}
    173
    174	vmbus_connection.handle_primary_chan_wq =
    175		create_workqueue("hv_pri_chan");
    176	if (!vmbus_connection.handle_primary_chan_wq) {
    177		ret = -ENOMEM;
    178		goto cleanup;
    179	}
    180
    181	vmbus_connection.handle_sub_chan_wq =
    182		create_workqueue("hv_sub_chan");
    183	if (!vmbus_connection.handle_sub_chan_wq) {
    184		ret = -ENOMEM;
    185		goto cleanup;
    186	}
    187
    188	INIT_LIST_HEAD(&vmbus_connection.chn_msg_list);
    189	spin_lock_init(&vmbus_connection.channelmsg_lock);
    190
    191	INIT_LIST_HEAD(&vmbus_connection.chn_list);
    192	mutex_init(&vmbus_connection.channel_mutex);
    193
    194	/*
    195	 * Setup the vmbus event connection for channel interrupt
    196	 * abstraction stuff
    197	 */
    198	vmbus_connection.int_page =
    199	(void *)hv_alloc_hyperv_zeroed_page();
    200	if (vmbus_connection.int_page == NULL) {
    201		ret = -ENOMEM;
    202		goto cleanup;
    203	}
    204
    205	vmbus_connection.recv_int_page = vmbus_connection.int_page;
    206	vmbus_connection.send_int_page =
    207		(void *)((unsigned long)vmbus_connection.int_page +
    208			(HV_HYP_PAGE_SIZE >> 1));
    209
    210	/*
    211	 * Setup the monitor notification facility. The 1st page for
    212	 * parent->child and the 2nd page for child->parent
    213	 */
    214	vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_zeroed_page();
    215	vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_zeroed_page();
    216	if ((vmbus_connection.monitor_pages[0] == NULL) ||
    217	    (vmbus_connection.monitor_pages[1] == NULL)) {
    218		ret = -ENOMEM;
    219		goto cleanup;
    220	}
    221
    222	vmbus_connection.monitor_pages_original[0]
    223		= vmbus_connection.monitor_pages[0];
    224	vmbus_connection.monitor_pages_original[1]
    225		= vmbus_connection.monitor_pages[1];
    226	vmbus_connection.monitor_pages_pa[0]
    227		= virt_to_phys(vmbus_connection.monitor_pages[0]);
    228	vmbus_connection.monitor_pages_pa[1]
    229		= virt_to_phys(vmbus_connection.monitor_pages[1]);
    230
    231	if (hv_is_isolation_supported()) {
    232		ret = set_memory_decrypted((unsigned long)
    233					   vmbus_connection.monitor_pages[0],
    234					   1);
    235		ret |= set_memory_decrypted((unsigned long)
    236					    vmbus_connection.monitor_pages[1],
    237					    1);
    238		if (ret)
    239			goto cleanup;
    240
    241		/*
    242		 * Isolation VM with AMD SNP needs to access monitor page via
    243		 * address space above shared gpa boundary.
    244		 */
    245		if (hv_isolation_type_snp()) {
    246			vmbus_connection.monitor_pages_pa[0] +=
    247				ms_hyperv.shared_gpa_boundary;
    248			vmbus_connection.monitor_pages_pa[1] +=
    249				ms_hyperv.shared_gpa_boundary;
    250
    251			vmbus_connection.monitor_pages[0]
    252				= memremap(vmbus_connection.monitor_pages_pa[0],
    253					   HV_HYP_PAGE_SIZE,
    254					   MEMREMAP_WB);
    255			if (!vmbus_connection.monitor_pages[0]) {
    256				ret = -ENOMEM;
    257				goto cleanup;
    258			}
    259
    260			vmbus_connection.monitor_pages[1]
    261				= memremap(vmbus_connection.monitor_pages_pa[1],
    262					   HV_HYP_PAGE_SIZE,
    263					   MEMREMAP_WB);
    264			if (!vmbus_connection.monitor_pages[1]) {
    265				ret = -ENOMEM;
    266				goto cleanup;
    267			}
    268		}
    269
    270		/*
    271		 * Set memory host visibility hvcall smears memory
    272		 * and so zero monitor pages here.
    273		 */
    274		memset(vmbus_connection.monitor_pages[0], 0x00,
    275		       HV_HYP_PAGE_SIZE);
    276		memset(vmbus_connection.monitor_pages[1], 0x00,
    277		       HV_HYP_PAGE_SIZE);
    278
    279	}
    280
    281	msginfo = kzalloc(sizeof(*msginfo) +
    282			  sizeof(struct vmbus_channel_initiate_contact),
    283			  GFP_KERNEL);
    284	if (msginfo == NULL) {
    285		ret = -ENOMEM;
    286		goto cleanup;
    287	}
    288
    289	/*
    290	 * Negotiate a compatible VMBUS version number with the
    291	 * host. We start with the highest number we can support
    292	 * and work our way down until we negotiate a compatible
    293	 * version.
    294	 */
    295
    296	for (i = 0; ; i++) {
    297		if (i == ARRAY_SIZE(vmbus_versions)) {
    298			ret = -EDOM;
    299			goto cleanup;
    300		}
    301
    302		version = vmbus_versions[i];
    303		if (version > max_version)
    304			continue;
    305
    306		ret = vmbus_negotiate_version(msginfo, version);
    307		if (ret == -ETIMEDOUT)
    308			goto cleanup;
    309
    310		if (vmbus_connection.conn_state == CONNECTED)
    311			break;
    312	}
    313
    314	if (hv_is_isolation_supported() && version < VERSION_WIN10_V5_2) {
    315		pr_err("Invalid VMBus version %d.%d (expected >= %d.%d) from the host supporting isolation\n",
    316		       version >> 16, version & 0xFFFF, VERSION_WIN10_V5_2 >> 16, VERSION_WIN10_V5_2 & 0xFFFF);
    317		ret = -EINVAL;
    318		goto cleanup;
    319	}
    320
    321	vmbus_proto_version = version;
    322	pr_info("Vmbus version:%d.%d\n",
    323		version >> 16, version & 0xFFFF);
    324
    325	vmbus_connection.channels = kcalloc(MAX_CHANNEL_RELIDS,
    326					    sizeof(struct vmbus_channel *),
    327					    GFP_KERNEL);
    328	if (vmbus_connection.channels == NULL) {
    329		ret = -ENOMEM;
    330		goto cleanup;
    331	}
    332
    333	kfree(msginfo);
    334	return 0;
    335
    336cleanup:
    337	pr_err("Unable to connect to host\n");
    338
    339	vmbus_connection.conn_state = DISCONNECTED;
    340	vmbus_disconnect();
    341
    342	kfree(msginfo);
    343
    344	return ret;
    345}
    346
    347void vmbus_disconnect(void)
    348{
    349	/*
    350	 * First send the unload request to the host.
    351	 */
    352	vmbus_initiate_unload(false);
    353
    354	if (vmbus_connection.handle_sub_chan_wq)
    355		destroy_workqueue(vmbus_connection.handle_sub_chan_wq);
    356
    357	if (vmbus_connection.handle_primary_chan_wq)
    358		destroy_workqueue(vmbus_connection.handle_primary_chan_wq);
    359
    360	if (vmbus_connection.work_queue)
    361		destroy_workqueue(vmbus_connection.work_queue);
    362
    363	if (vmbus_connection.int_page) {
    364		hv_free_hyperv_page((unsigned long)vmbus_connection.int_page);
    365		vmbus_connection.int_page = NULL;
    366	}
    367
    368	if (hv_is_isolation_supported()) {
    369		/*
    370		 * memunmap() checks input address is ioremap address or not
    371		 * inside. It doesn't unmap any thing in the non-SNP CVM and
    372		 * so not check CVM type here.
    373		 */
    374		memunmap(vmbus_connection.monitor_pages[0]);
    375		memunmap(vmbus_connection.monitor_pages[1]);
    376
    377		set_memory_encrypted((unsigned long)
    378			vmbus_connection.monitor_pages_original[0],
    379			1);
    380		set_memory_encrypted((unsigned long)
    381			vmbus_connection.monitor_pages_original[1],
    382			1);
    383	}
    384
    385	hv_free_hyperv_page((unsigned long)
    386		vmbus_connection.monitor_pages_original[0]);
    387	hv_free_hyperv_page((unsigned long)
    388		vmbus_connection.monitor_pages_original[1]);
    389	vmbus_connection.monitor_pages_original[0] =
    390		vmbus_connection.monitor_pages[0] = NULL;
    391	vmbus_connection.monitor_pages_original[1] =
    392		vmbus_connection.monitor_pages[1] = NULL;
    393}
    394
    395/*
    396 * relid2channel - Get the channel object given its
    397 * child relative id (ie channel id)
    398 */
    399struct vmbus_channel *relid2channel(u32 relid)
    400{
    401	if (WARN_ON(relid >= MAX_CHANNEL_RELIDS))
    402		return NULL;
    403	return READ_ONCE(vmbus_connection.channels[relid]);
    404}
    405
    406/*
    407 * vmbus_on_event - Process a channel event notification
    408 *
    409 * For batched channels (default) optimize host to guest signaling
    410 * by ensuring:
    411 * 1. While reading the channel, we disable interrupts from host.
    412 * 2. Ensure that we process all posted messages from the host
    413 *    before returning from this callback.
    414 * 3. Once we return, enable signaling from the host. Once this
    415 *    state is set we check to see if additional packets are
    416 *    available to read. In this case we repeat the process.
    417 *    If this tasklet has been running for a long time
    418 *    then reschedule ourselves.
    419 */
    420void vmbus_on_event(unsigned long data)
    421{
    422	struct vmbus_channel *channel = (void *) data;
    423	unsigned long time_limit = jiffies + 2;
    424
    425	trace_vmbus_on_event(channel);
    426
    427	hv_debug_delay_test(channel, INTERRUPT_DELAY);
    428	do {
    429		void (*callback_fn)(void *);
    430
    431		/* A channel once created is persistent even when
    432		 * there is no driver handling the device. An
    433		 * unloading driver sets the onchannel_callback to NULL.
    434		 */
    435		callback_fn = READ_ONCE(channel->onchannel_callback);
    436		if (unlikely(callback_fn == NULL))
    437			return;
    438
    439		(*callback_fn)(channel->channel_callback_context);
    440
    441		if (channel->callback_mode != HV_CALL_BATCHED)
    442			return;
    443
    444		if (likely(hv_end_read(&channel->inbound) == 0))
    445			return;
    446
    447		hv_begin_read(&channel->inbound);
    448	} while (likely(time_before(jiffies, time_limit)));
    449
    450	/* The time limit (2 jiffies) has been reached */
    451	tasklet_schedule(&channel->callback_event);
    452}
    453
    454/*
    455 * vmbus_post_msg - Send a msg on the vmbus's message connection
    456 */
    457int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
    458{
    459	struct vmbus_channel_message_header *hdr;
    460	union hv_connection_id conn_id;
    461	int ret = 0;
    462	int retries = 0;
    463	u32 usec = 1;
    464
    465	conn_id.asu32 = 0;
    466	conn_id.u.id = vmbus_connection.msg_conn_id;
    467
    468	/*
    469	 * hv_post_message() can have transient failures because of
    470	 * insufficient resources. Retry the operation a couple of
    471	 * times before giving up.
    472	 */
    473	while (retries < 100) {
    474		ret = hv_post_message(conn_id, 1, buffer, buflen);
    475
    476		switch (ret) {
    477		case HV_STATUS_INVALID_CONNECTION_ID:
    478			/*
    479			 * See vmbus_negotiate_version(): VMBus protocol 5.0
    480			 * and higher require that we must use
    481			 * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
    482			 * Contact message, but on old hosts that only
    483			 * support VMBus protocol 4.0 or lower, here we get
    484			 * HV_STATUS_INVALID_CONNECTION_ID and we should
    485			 * return an error immediately without retrying.
    486			 */
    487			hdr = buffer;
    488			if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
    489				return -EINVAL;
    490			/*
    491			 * We could get this if we send messages too
    492			 * frequently.
    493			 */
    494			ret = -EAGAIN;
    495			break;
    496		case HV_STATUS_INSUFFICIENT_MEMORY:
    497		case HV_STATUS_INSUFFICIENT_BUFFERS:
    498			ret = -ENOBUFS;
    499			break;
    500		case HV_STATUS_SUCCESS:
    501			return ret;
    502		default:
    503			pr_err("hv_post_msg() failed; error code:%d\n", ret);
    504			return -EINVAL;
    505		}
    506
    507		retries++;
    508		if (can_sleep && usec > 1000)
    509			msleep(usec / 1000);
    510		else if (usec < MAX_UDELAY_MS * 1000)
    511			udelay(usec);
    512		else
    513			mdelay(usec / 1000);
    514
    515		if (retries < 22)
    516			usec *= 2;
    517	}
    518	return ret;
    519}
    520
    521/*
    522 * vmbus_set_event - Send an event notification to the parent
    523 */
    524void vmbus_set_event(struct vmbus_channel *channel)
    525{
    526	u32 child_relid = channel->offermsg.child_relid;
    527
    528	if (!channel->is_dedicated_interrupt)
    529		vmbus_send_interrupt(child_relid);
    530
    531	++channel->sig_events;
    532
    533	if (hv_isolation_type_snp())
    534		hv_ghcb_hypercall(HVCALL_SIGNAL_EVENT, &channel->sig_event,
    535				NULL, sizeof(channel->sig_event));
    536	else
    537		hv_do_fast_hypercall8(HVCALL_SIGNAL_EVENT, channel->sig_event);
    538}
    539EXPORT_SYMBOL_GPL(vmbus_set_event);