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 "hv_kvp.h"
32 
33 
34 static void shutdown_onchannelcallback(void *context);
35 static struct hv_util_service util_shutdown = {
36 	.util_cb = shutdown_onchannelcallback,
37 };
38 
39 static void timesync_onchannelcallback(void *context);
40 static struct hv_util_service util_timesynch = {
41 	.util_cb = timesync_onchannelcallback,
42 };
43 
44 static void heartbeat_onchannelcallback(void *context);
45 static struct hv_util_service util_heartbeat = {
46 	.util_cb = heartbeat_onchannelcallback,
47 };
48 
49 static struct hv_util_service util_kvp = {
50 	.util_cb = hv_kvp_onchannelcallback,
51 	.util_init = hv_kvp_init,
52 	.util_deinit = hv_kvp_deinit,
53 };
54 
shutdown_onchannelcallback(void * context)55 static void shutdown_onchannelcallback(void *context)
56 {
57 	struct vmbus_channel *channel = context;
58 	u32 recvlen;
59 	u64 requestid;
60 	u8  execute_shutdown = false;
61 	u8  *shut_txf_buf = util_shutdown.recv_buffer;
62 
63 	struct shutdown_msg_data *shutdown_msg;
64 
65 	struct icmsg_hdr *icmsghdrp;
66 	struct icmsg_negotiate *negop = NULL;
67 
68 	vmbus_recvpacket(channel, shut_txf_buf,
69 			 PAGE_SIZE, &recvlen, &requestid);
70 
71 	if (recvlen > 0) {
72 		icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
73 			sizeof(struct vmbuspipe_hdr)];
74 
75 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
76 			vmbus_prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf);
77 		} else {
78 			shutdown_msg =
79 				(struct shutdown_msg_data *)&shut_txf_buf[
80 					sizeof(struct vmbuspipe_hdr) +
81 					sizeof(struct icmsg_hdr)];
82 
83 			switch (shutdown_msg->flags) {
84 			case 0:
85 			case 1:
86 				icmsghdrp->status = HV_S_OK;
87 				execute_shutdown = true;
88 
89 				pr_info("Shutdown request received -"
90 					    " graceful shutdown initiated\n");
91 				break;
92 			default:
93 				icmsghdrp->status = HV_E_FAIL;
94 				execute_shutdown = false;
95 
96 				pr_info("Shutdown request received -"
97 					    " Invalid request\n");
98 				break;
99 			}
100 		}
101 
102 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
103 			| ICMSGHDRFLAG_RESPONSE;
104 
105 		vmbus_sendpacket(channel, shut_txf_buf,
106 				       recvlen, requestid,
107 				       VM_PKT_DATA_INBAND, 0);
108 	}
109 
110 	if (execute_shutdown == true)
111 		orderly_poweroff(true);
112 }
113 
114 /*
115  * Set guest time to host UTC time.
116  */
do_adj_guesttime(u64 hosttime)117 static inline void do_adj_guesttime(u64 hosttime)
118 {
119 	s64 host_tns;
120 	struct timespec host_ts;
121 
122 	host_tns = (hosttime - WLTIMEDELTA) * 100;
123 	host_ts = ns_to_timespec(host_tns);
124 
125 	do_settimeofday(&host_ts);
126 }
127 
128 /*
129  * Set the host time in a process context.
130  */
131 
132 struct adj_time_work {
133 	struct work_struct work;
134 	u64	host_time;
135 };
136 
hv_set_host_time(struct work_struct * work)137 static void hv_set_host_time(struct work_struct *work)
138 {
139 	struct adj_time_work	*wrk;
140 
141 	wrk = container_of(work, struct adj_time_work, work);
142 	do_adj_guesttime(wrk->host_time);
143 	kfree(wrk);
144 }
145 
146 /*
147  * Synchronize time with host after reboot, restore, etc.
148  *
149  * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
150  * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
151  * message after the timesync channel is opened. Since the hv_utils module is
152  * loaded after hv_vmbus, the first message is usually missed. The other
153  * thing is, systime is automatically set to emulated hardware clock which may
154  * not be UTC time or in the same time zone. So, to override these effects, we
155  * use the first 50 time samples for initial system time setting.
156  */
adj_guesttime(u64 hosttime,u8 flags)157 static inline void adj_guesttime(u64 hosttime, u8 flags)
158 {
159 	struct adj_time_work    *wrk;
160 	static s32 scnt = 50;
161 
162 	wrk = kmalloc(sizeof(struct adj_time_work), GFP_ATOMIC);
163 	if (wrk == NULL)
164 		return;
165 
166 	wrk->host_time = hosttime;
167 	if ((flags & ICTIMESYNCFLAG_SYNC) != 0) {
168 		INIT_WORK(&wrk->work, hv_set_host_time);
169 		schedule_work(&wrk->work);
170 		return;
171 	}
172 
173 	if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) {
174 		scnt--;
175 		INIT_WORK(&wrk->work, hv_set_host_time);
176 		schedule_work(&wrk->work);
177 	} else
178 		kfree(wrk);
179 }
180 
181 /*
182  * Time Sync Channel message handler.
183  */
timesync_onchannelcallback(void * context)184 static void timesync_onchannelcallback(void *context)
185 {
186 	struct vmbus_channel *channel = context;
187 	u32 recvlen;
188 	u64 requestid;
189 	struct icmsg_hdr *icmsghdrp;
190 	struct ictimesync_data *timedatap;
191 	u8 *time_txf_buf = util_timesynch.recv_buffer;
192 
193 	vmbus_recvpacket(channel, time_txf_buf,
194 			 PAGE_SIZE, &recvlen, &requestid);
195 
196 	if (recvlen > 0) {
197 		icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
198 				sizeof(struct vmbuspipe_hdr)];
199 
200 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
201 			vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf);
202 		} else {
203 			timedatap = (struct ictimesync_data *)&time_txf_buf[
204 				sizeof(struct vmbuspipe_hdr) +
205 				sizeof(struct icmsg_hdr)];
206 			adj_guesttime(timedatap->parenttime, timedatap->flags);
207 		}
208 
209 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
210 			| ICMSGHDRFLAG_RESPONSE;
211 
212 		vmbus_sendpacket(channel, time_txf_buf,
213 				recvlen, requestid,
214 				VM_PKT_DATA_INBAND, 0);
215 	}
216 }
217 
218 /*
219  * Heartbeat functionality.
220  * Every two seconds, Hyper-V send us a heartbeat request message.
221  * we respond to this message, and Hyper-V knows we are alive.
222  */
heartbeat_onchannelcallback(void * context)223 static void heartbeat_onchannelcallback(void *context)
224 {
225 	struct vmbus_channel *channel = context;
226 	u32 recvlen;
227 	u64 requestid;
228 	struct icmsg_hdr *icmsghdrp;
229 	struct heartbeat_msg_data *heartbeat_msg;
230 	u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
231 
232 	vmbus_recvpacket(channel, hbeat_txf_buf,
233 			 PAGE_SIZE, &recvlen, &requestid);
234 
235 	if (recvlen > 0) {
236 		icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
237 				sizeof(struct vmbuspipe_hdr)];
238 
239 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
240 			vmbus_prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf);
241 		} else {
242 			heartbeat_msg =
243 				(struct heartbeat_msg_data *)&hbeat_txf_buf[
244 					sizeof(struct vmbuspipe_hdr) +
245 					sizeof(struct icmsg_hdr)];
246 
247 			heartbeat_msg->seq_num += 1;
248 		}
249 
250 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
251 			| ICMSGHDRFLAG_RESPONSE;
252 
253 		vmbus_sendpacket(channel, hbeat_txf_buf,
254 				       recvlen, requestid,
255 				       VM_PKT_DATA_INBAND, 0);
256 	}
257 }
258 
util_probe(struct hv_device * dev,const struct hv_vmbus_device_id * dev_id)259 static int util_probe(struct hv_device *dev,
260 			const struct hv_vmbus_device_id *dev_id)
261 {
262 	struct hv_util_service *srv =
263 		(struct hv_util_service *)dev_id->driver_data;
264 	int ret;
265 
266 	srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
267 	if (!srv->recv_buffer)
268 		return -ENOMEM;
269 	if (srv->util_init) {
270 		ret = srv->util_init(srv);
271 		if (ret) {
272 			ret = -ENODEV;
273 			goto error1;
274 		}
275 	}
276 
277 	ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL, 0,
278 			srv->util_cb, dev->channel);
279 	if (ret)
280 		goto error;
281 
282 	hv_set_drvdata(dev, srv);
283 	return 0;
284 
285 error:
286 	if (srv->util_deinit)
287 		srv->util_deinit();
288 error1:
289 	kfree(srv->recv_buffer);
290 	return ret;
291 }
292 
util_remove(struct hv_device * dev)293 static int util_remove(struct hv_device *dev)
294 {
295 	struct hv_util_service *srv = hv_get_drvdata(dev);
296 
297 	vmbus_close(dev->channel);
298 	if (srv->util_deinit)
299 		srv->util_deinit();
300 	kfree(srv->recv_buffer);
301 
302 	return 0;
303 }
304 
305 static const struct hv_vmbus_device_id id_table[] = {
306 	/* Shutdown guid */
307 	{ VMBUS_DEVICE(0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
308 		       0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB)
309 	  .driver_data = (unsigned long)&util_shutdown },
310 	/* Time synch guid */
311 	{ VMBUS_DEVICE(0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
312 		       0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf)
313 	  .driver_data = (unsigned long)&util_timesynch },
314 	/* Heartbeat guid */
315 	{ VMBUS_DEVICE(0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
316 		       0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d)
317 	  .driver_data = (unsigned long)&util_heartbeat },
318 	/* KVP guid */
319 	{ VMBUS_DEVICE(0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
320 		       0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3,  0xe6)
321 	  .driver_data = (unsigned long)&util_kvp },
322 	{ },
323 };
324 
325 MODULE_DEVICE_TABLE(vmbus, id_table);
326 
327 /* The one and only one */
328 static  struct hv_driver util_drv = {
329 	.name = "hv_util",
330 	.id_table = id_table,
331 	.probe =  util_probe,
332 	.remove =  util_remove,
333 };
334 
init_hyperv_utils(void)335 static int __init init_hyperv_utils(void)
336 {
337 	pr_info("Registering HyperV Utility Driver\n");
338 
339 	return vmbus_driver_register(&util_drv);
340 }
341 
exit_hyperv_utils(void)342 static void exit_hyperv_utils(void)
343 {
344 	pr_info("De-Registered HyperV Utility Driver\n");
345 
346 	vmbus_driver_unregister(&util_drv);
347 }
348 
349 module_init(init_hyperv_utils);
350 module_exit(exit_hyperv_utils);
351 
352 MODULE_DESCRIPTION("Hyper-V Utilities");
353 MODULE_VERSION(HV_DRV_VERSION);
354 MODULE_LICENSE("GPL");
355