xref: /linux/drivers/hv/hv_util.c (revision 80d443e8876602be2c130f79c4de81e12e2a700d)
1 /*
2  * Copyright (c) 2010, Microsoft Corporation.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15  * Place - Suite 330, Boston, MA 02111-1307 USA.
16  *
17  * Authors:
18  *   Haiyang Zhang <haiyangz@microsoft.com>
19  *   Hank Janssen  <hjanssen@microsoft.com>
20  */
21 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22 
23 #include <linux/kernel.h>
24 #include <linux/init.h>
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <linux/sysctl.h>
28 #include <linux/reboot.h>
29 #include <linux/hyperv.h>
30 
31 #include "hyperv_vmbus.h"
32 
33 #define SD_MAJOR	3
34 #define SD_MINOR	0
35 #define SD_VERSION	(SD_MAJOR << 16 | SD_MINOR)
36 
37 #define SD_MAJOR_1	1
38 #define SD_VERSION_1	(SD_MAJOR_1 << 16 | SD_MINOR)
39 
40 #define TS_MAJOR	4
41 #define TS_MINOR	0
42 #define TS_VERSION	(TS_MAJOR << 16 | TS_MINOR)
43 
44 #define TS_MAJOR_1	1
45 #define TS_VERSION_1	(TS_MAJOR_1 << 16 | TS_MINOR)
46 
47 #define TS_MAJOR_3	3
48 #define TS_VERSION_3	(TS_MAJOR_3 << 16 | TS_MINOR)
49 
50 #define HB_MAJOR	3
51 #define HB_MINOR	0
52 #define HB_VERSION	(HB_MAJOR << 16 | HB_MINOR)
53 
54 #define HB_MAJOR_1	1
55 #define HB_VERSION_1	(HB_MAJOR_1 << 16 | HB_MINOR)
56 
57 static int sd_srv_version;
58 static int ts_srv_version;
59 static int hb_srv_version;
60 static int util_fw_version;
61 
62 static void shutdown_onchannelcallback(void *context);
63 static struct hv_util_service util_shutdown = {
64 	.util_cb = shutdown_onchannelcallback,
65 };
66 
67 static int hv_timesync_init(struct hv_util_service *srv);
68 static void hv_timesync_deinit(void);
69 
70 static void timesync_onchannelcallback(void *context);
71 static struct hv_util_service util_timesynch = {
72 	.util_cb = timesync_onchannelcallback,
73 	.util_init = hv_timesync_init,
74 	.util_deinit = hv_timesync_deinit,
75 };
76 
77 static void heartbeat_onchannelcallback(void *context);
78 static struct hv_util_service util_heartbeat = {
79 	.util_cb = heartbeat_onchannelcallback,
80 };
81 
82 static struct hv_util_service util_kvp = {
83 	.util_cb = hv_kvp_onchannelcallback,
84 	.util_init = hv_kvp_init,
85 	.util_deinit = hv_kvp_deinit,
86 };
87 
88 static struct hv_util_service util_vss = {
89 	.util_cb = hv_vss_onchannelcallback,
90 	.util_init = hv_vss_init,
91 	.util_deinit = hv_vss_deinit,
92 };
93 
94 static struct hv_util_service util_fcopy = {
95 	.util_cb = hv_fcopy_onchannelcallback,
96 	.util_init = hv_fcopy_init,
97 	.util_deinit = hv_fcopy_deinit,
98 };
99 
100 static void perform_shutdown(struct work_struct *dummy)
101 {
102 	orderly_poweroff(true);
103 }
104 
105 /*
106  * Perform the shutdown operation in a thread context.
107  */
108 static DECLARE_WORK(shutdown_work, perform_shutdown);
109 
110 static void shutdown_onchannelcallback(void *context)
111 {
112 	struct vmbus_channel *channel = context;
113 	u32 recvlen;
114 	u64 requestid;
115 	bool execute_shutdown = false;
116 	u8  *shut_txf_buf = util_shutdown.recv_buffer;
117 
118 	struct shutdown_msg_data *shutdown_msg;
119 
120 	struct icmsg_hdr *icmsghdrp;
121 	struct icmsg_negotiate *negop = NULL;
122 
123 	vmbus_recvpacket(channel, shut_txf_buf,
124 			 PAGE_SIZE, &recvlen, &requestid);
125 
126 	if (recvlen > 0) {
127 		icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
128 			sizeof(struct vmbuspipe_hdr)];
129 
130 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
131 			vmbus_prep_negotiate_resp(icmsghdrp, negop,
132 					shut_txf_buf, util_fw_version,
133 					sd_srv_version);
134 		} else {
135 			shutdown_msg =
136 				(struct shutdown_msg_data *)&shut_txf_buf[
137 					sizeof(struct vmbuspipe_hdr) +
138 					sizeof(struct icmsg_hdr)];
139 
140 			switch (shutdown_msg->flags) {
141 			case 0:
142 			case 1:
143 				icmsghdrp->status = HV_S_OK;
144 				execute_shutdown = true;
145 
146 				pr_info("Shutdown request received -"
147 					    " graceful shutdown initiated\n");
148 				break;
149 			default:
150 				icmsghdrp->status = HV_E_FAIL;
151 				execute_shutdown = false;
152 
153 				pr_info("Shutdown request received -"
154 					    " Invalid request\n");
155 				break;
156 			}
157 		}
158 
159 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
160 			| ICMSGHDRFLAG_RESPONSE;
161 
162 		vmbus_sendpacket(channel, shut_txf_buf,
163 				       recvlen, requestid,
164 				       VM_PKT_DATA_INBAND, 0);
165 	}
166 
167 	if (execute_shutdown == true)
168 		schedule_work(&shutdown_work);
169 }
170 
171 /*
172  * Set the host time in a process context.
173  */
174 
175 struct adj_time_work {
176 	struct work_struct work;
177 	u64	host_time;
178 	u64	ref_time;
179 	u8	flags;
180 };
181 
182 static void hv_set_host_time(struct work_struct *work)
183 {
184 	struct adj_time_work	*wrk;
185 	s64 host_tns;
186 	u64 newtime;
187 	struct timespec host_ts;
188 
189 	wrk = container_of(work, struct adj_time_work, work);
190 
191 	newtime = wrk->host_time;
192 	if (ts_srv_version > TS_VERSION_3) {
193 		/*
194 		 * Some latency has been introduced since Hyper-V generated
195 		 * its time sample. Take that latency into account before
196 		 * using TSC reference time sample from Hyper-V.
197 		 *
198 		 * This sample is given by TimeSync v4 and above hosts.
199 		 */
200 		u64 current_tick;
201 
202 		rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
203 		newtime += (current_tick - wrk->ref_time);
204 	}
205 	host_tns = (newtime - WLTIMEDELTA) * 100;
206 	host_ts = ns_to_timespec(host_tns);
207 
208 	do_settimeofday(&host_ts);
209 }
210 
211 /*
212  * Synchronize time with host after reboot, restore, etc.
213  *
214  * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
215  * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
216  * message after the timesync channel is opened. Since the hv_utils module is
217  * loaded after hv_vmbus, the first message is usually missed. This bit is
218  * considered a hard request to discipline the clock.
219  *
220  * ICTIMESYNCFLAG_SAMPLE bit indicates a time sample from host. This is
221  * typically used as a hint to the guest. The guest is under no obligation
222  * to discipline the clock.
223  */
224 static struct adj_time_work  wrk;
225 static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 flags)
226 {
227 
228 	/*
229 	 * This check is safe since we are executing in the
230 	 * interrupt context and time synch messages arre always
231 	 * delivered on the same CPU.
232 	 */
233 	if (work_pending(&wrk.work))
234 		return;
235 
236 	wrk.host_time = hosttime;
237 	wrk.ref_time = reftime;
238 	wrk.flags = flags;
239 	if ((flags & (ICTIMESYNCFLAG_SYNC | ICTIMESYNCFLAG_SAMPLE)) != 0) {
240 		schedule_work(&wrk.work);
241 	}
242 }
243 
244 /*
245  * Time Sync Channel message handler.
246  */
247 static void timesync_onchannelcallback(void *context)
248 {
249 	struct vmbus_channel *channel = context;
250 	u32 recvlen;
251 	u64 requestid;
252 	struct icmsg_hdr *icmsghdrp;
253 	struct ictimesync_data *timedatap;
254 	struct ictimesync_ref_data *refdata;
255 	u8 *time_txf_buf = util_timesynch.recv_buffer;
256 	struct icmsg_negotiate *negop = NULL;
257 
258 	vmbus_recvpacket(channel, time_txf_buf,
259 			 PAGE_SIZE, &recvlen, &requestid);
260 
261 	if (recvlen > 0) {
262 		icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
263 				sizeof(struct vmbuspipe_hdr)];
264 
265 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
266 			vmbus_prep_negotiate_resp(icmsghdrp, negop,
267 						time_txf_buf,
268 						util_fw_version,
269 						ts_srv_version);
270 			pr_info("Using TimeSync version %d.%d\n",
271 				ts_srv_version >> 16, ts_srv_version & 0xFFFF);
272 		} else {
273 			if (ts_srv_version > TS_VERSION_3) {
274 				refdata = (struct ictimesync_ref_data *)
275 					&time_txf_buf[
276 					sizeof(struct vmbuspipe_hdr) +
277 					sizeof(struct icmsg_hdr)];
278 
279 				adj_guesttime(refdata->parenttime,
280 						refdata->vmreferencetime,
281 						refdata->flags);
282 			} else {
283 				timedatap = (struct ictimesync_data *)
284 					&time_txf_buf[
285 					sizeof(struct vmbuspipe_hdr) +
286 					sizeof(struct icmsg_hdr)];
287 				adj_guesttime(timedatap->parenttime,
288 						0,
289 						timedatap->flags);
290 			}
291 		}
292 
293 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
294 			| ICMSGHDRFLAG_RESPONSE;
295 
296 		vmbus_sendpacket(channel, time_txf_buf,
297 				recvlen, requestid,
298 				VM_PKT_DATA_INBAND, 0);
299 	}
300 }
301 
302 /*
303  * Heartbeat functionality.
304  * Every two seconds, Hyper-V send us a heartbeat request message.
305  * we respond to this message, and Hyper-V knows we are alive.
306  */
307 static void heartbeat_onchannelcallback(void *context)
308 {
309 	struct vmbus_channel *channel = context;
310 	u32 recvlen;
311 	u64 requestid;
312 	struct icmsg_hdr *icmsghdrp;
313 	struct heartbeat_msg_data *heartbeat_msg;
314 	u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
315 	struct icmsg_negotiate *negop = NULL;
316 
317 	while (1) {
318 
319 		vmbus_recvpacket(channel, hbeat_txf_buf,
320 				 PAGE_SIZE, &recvlen, &requestid);
321 
322 		if (!recvlen)
323 			break;
324 
325 		icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
326 				sizeof(struct vmbuspipe_hdr)];
327 
328 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
329 			vmbus_prep_negotiate_resp(icmsghdrp, negop,
330 				hbeat_txf_buf, util_fw_version,
331 				hb_srv_version);
332 		} else {
333 			heartbeat_msg =
334 				(struct heartbeat_msg_data *)&hbeat_txf_buf[
335 					sizeof(struct vmbuspipe_hdr) +
336 					sizeof(struct icmsg_hdr)];
337 
338 			heartbeat_msg->seq_num += 1;
339 		}
340 
341 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
342 			| ICMSGHDRFLAG_RESPONSE;
343 
344 		vmbus_sendpacket(channel, hbeat_txf_buf,
345 				       recvlen, requestid,
346 				       VM_PKT_DATA_INBAND, 0);
347 	}
348 }
349 
350 static int util_probe(struct hv_device *dev,
351 			const struct hv_vmbus_device_id *dev_id)
352 {
353 	struct hv_util_service *srv =
354 		(struct hv_util_service *)dev_id->driver_data;
355 	int ret;
356 
357 	srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
358 	if (!srv->recv_buffer)
359 		return -ENOMEM;
360 	srv->channel = dev->channel;
361 	if (srv->util_init) {
362 		ret = srv->util_init(srv);
363 		if (ret) {
364 			ret = -ENODEV;
365 			goto error1;
366 		}
367 	}
368 
369 	/*
370 	 * The set of services managed by the util driver are not performance
371 	 * critical and do not need batched reading. Furthermore, some services
372 	 * such as KVP can only handle one message from the host at a time.
373 	 * Turn off batched reading for all util drivers before we open the
374 	 * channel.
375 	 */
376 
377 	set_channel_read_state(dev->channel, false);
378 
379 	hv_set_drvdata(dev, srv);
380 
381 	/*
382 	 * Based on the host; initialize the framework and
383 	 * service version numbers we will negotiate.
384 	 */
385 	switch (vmbus_proto_version) {
386 	case (VERSION_WS2008):
387 		util_fw_version = UTIL_WS2K8_FW_VERSION;
388 		sd_srv_version = SD_VERSION_1;
389 		ts_srv_version = TS_VERSION_1;
390 		hb_srv_version = HB_VERSION_1;
391 		break;
392 	case VERSION_WIN7:
393 	case VERSION_WIN8:
394 	case VERSION_WIN8_1:
395 		util_fw_version = UTIL_FW_VERSION;
396 		sd_srv_version = SD_VERSION;
397 		ts_srv_version = TS_VERSION_3;
398 		hb_srv_version = HB_VERSION;
399 		break;
400 	case VERSION_WIN10:
401 	default:
402 		util_fw_version = UTIL_FW_VERSION;
403 		sd_srv_version = SD_VERSION;
404 		ts_srv_version = TS_VERSION;
405 		hb_srv_version = HB_VERSION;
406 	}
407 
408 	ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
409 			srv->util_cb, dev->channel);
410 	if (ret)
411 		goto error;
412 
413 	return 0;
414 
415 error:
416 	if (srv->util_deinit)
417 		srv->util_deinit();
418 error1:
419 	kfree(srv->recv_buffer);
420 	return ret;
421 }
422 
423 static int util_remove(struct hv_device *dev)
424 {
425 	struct hv_util_service *srv = hv_get_drvdata(dev);
426 
427 	if (srv->util_deinit)
428 		srv->util_deinit();
429 	vmbus_close(dev->channel);
430 	kfree(srv->recv_buffer);
431 
432 	return 0;
433 }
434 
435 static const struct hv_vmbus_device_id id_table[] = {
436 	/* Shutdown guid */
437 	{ HV_SHUTDOWN_GUID,
438 	  .driver_data = (unsigned long)&util_shutdown
439 	},
440 	/* Time synch guid */
441 	{ HV_TS_GUID,
442 	  .driver_data = (unsigned long)&util_timesynch
443 	},
444 	/* Heartbeat guid */
445 	{ HV_HEART_BEAT_GUID,
446 	  .driver_data = (unsigned long)&util_heartbeat
447 	},
448 	/* KVP guid */
449 	{ HV_KVP_GUID,
450 	  .driver_data = (unsigned long)&util_kvp
451 	},
452 	/* VSS GUID */
453 	{ HV_VSS_GUID,
454 	  .driver_data = (unsigned long)&util_vss
455 	},
456 	/* File copy GUID */
457 	{ HV_FCOPY_GUID,
458 	  .driver_data = (unsigned long)&util_fcopy
459 	},
460 	{ },
461 };
462 
463 MODULE_DEVICE_TABLE(vmbus, id_table);
464 
465 /* The one and only one */
466 static  struct hv_driver util_drv = {
467 	.name = "hv_util",
468 	.id_table = id_table,
469 	.probe =  util_probe,
470 	.remove =  util_remove,
471 };
472 
473 static int hv_timesync_init(struct hv_util_service *srv)
474 {
475 	INIT_WORK(&wrk.work, hv_set_host_time);
476 	return 0;
477 }
478 
479 static void hv_timesync_deinit(void)
480 {
481 	cancel_work_sync(&wrk.work);
482 }
483 
484 static int __init init_hyperv_utils(void)
485 {
486 	pr_info("Registering HyperV Utility Driver\n");
487 
488 	return vmbus_driver_register(&util_drv);
489 }
490 
491 static void exit_hyperv_utils(void)
492 {
493 	pr_info("De-Registered HyperV Utility Driver\n");
494 
495 	vmbus_driver_unregister(&util_drv);
496 }
497 
498 module_init(init_hyperv_utils);
499 module_exit(exit_hyperv_utils);
500 
501 MODULE_DESCRIPTION("Hyper-V Utilities");
502 MODULE_LICENSE("GPL");
503