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_WS2008_MAJOR 1 38 #define SD_WS2008_VERSION (SD_WS2008_MAJOR << 16 | SD_MINOR) 39 40 #define TS_MAJOR 3 41 #define TS_MINOR 0 42 #define TS_VERSION (TS_MAJOR << 16 | TS_MINOR) 43 44 #define TS_WS2008_MAJOR 1 45 #define TS_WS2008_VERSION (TS_WS2008_MAJOR << 16 | TS_MINOR) 46 47 #define HB_MAJOR 3 48 #define HB_MINOR 0 49 #define HB_VERSION (HB_MAJOR << 16 | HB_MINOR) 50 51 #define HB_WS2008_MAJOR 1 52 #define HB_WS2008_VERSION (HB_WS2008_MAJOR << 16 | HB_MINOR) 53 54 static int sd_srv_version; 55 static int ts_srv_version; 56 static int hb_srv_version; 57 static int util_fw_version; 58 59 static void shutdown_onchannelcallback(void *context); 60 static struct hv_util_service util_shutdown = { 61 .util_cb = shutdown_onchannelcallback, 62 }; 63 64 static void timesync_onchannelcallback(void *context); 65 static struct hv_util_service util_timesynch = { 66 .util_cb = timesync_onchannelcallback, 67 }; 68 69 static void heartbeat_onchannelcallback(void *context); 70 static struct hv_util_service util_heartbeat = { 71 .util_cb = heartbeat_onchannelcallback, 72 }; 73 74 static struct hv_util_service util_kvp = { 75 .util_cb = hv_kvp_onchannelcallback, 76 .util_init = hv_kvp_init, 77 .util_deinit = hv_kvp_deinit, 78 }; 79 80 static struct hv_util_service util_vss = { 81 .util_cb = hv_vss_onchannelcallback, 82 .util_init = hv_vss_init, 83 .util_deinit = hv_vss_deinit, 84 }; 85 86 static struct hv_util_service util_fcopy = { 87 .util_cb = hv_fcopy_onchannelcallback, 88 .util_init = hv_fcopy_init, 89 .util_deinit = hv_fcopy_deinit, 90 }; 91 92 static void perform_shutdown(struct work_struct *dummy) 93 { 94 orderly_poweroff(true); 95 } 96 97 /* 98 * Perform the shutdown operation in a thread context. 99 */ 100 static DECLARE_WORK(shutdown_work, perform_shutdown); 101 102 static void shutdown_onchannelcallback(void *context) 103 { 104 struct vmbus_channel *channel = context; 105 u32 recvlen; 106 u64 requestid; 107 bool execute_shutdown = false; 108 u8 *shut_txf_buf = util_shutdown.recv_buffer; 109 110 struct shutdown_msg_data *shutdown_msg; 111 112 struct icmsg_hdr *icmsghdrp; 113 struct icmsg_negotiate *negop = NULL; 114 115 vmbus_recvpacket(channel, shut_txf_buf, 116 PAGE_SIZE, &recvlen, &requestid); 117 118 if (recvlen > 0) { 119 icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[ 120 sizeof(struct vmbuspipe_hdr)]; 121 122 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 123 vmbus_prep_negotiate_resp(icmsghdrp, negop, 124 shut_txf_buf, util_fw_version, 125 sd_srv_version); 126 } else { 127 shutdown_msg = 128 (struct shutdown_msg_data *)&shut_txf_buf[ 129 sizeof(struct vmbuspipe_hdr) + 130 sizeof(struct icmsg_hdr)]; 131 132 switch (shutdown_msg->flags) { 133 case 0: 134 case 1: 135 icmsghdrp->status = HV_S_OK; 136 execute_shutdown = true; 137 138 pr_info("Shutdown request received -" 139 " graceful shutdown initiated\n"); 140 break; 141 default: 142 icmsghdrp->status = HV_E_FAIL; 143 execute_shutdown = false; 144 145 pr_info("Shutdown request received -" 146 " Invalid request\n"); 147 break; 148 } 149 } 150 151 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION 152 | ICMSGHDRFLAG_RESPONSE; 153 154 vmbus_sendpacket(channel, shut_txf_buf, 155 recvlen, requestid, 156 VM_PKT_DATA_INBAND, 0); 157 } 158 159 if (execute_shutdown == true) 160 schedule_work(&shutdown_work); 161 } 162 163 /* 164 * Set guest time to host UTC time. 165 */ 166 static inline void do_adj_guesttime(u64 hosttime) 167 { 168 s64 host_tns; 169 struct timespec host_ts; 170 171 host_tns = (hosttime - WLTIMEDELTA) * 100; 172 host_ts = ns_to_timespec(host_tns); 173 174 do_settimeofday(&host_ts); 175 } 176 177 /* 178 * Set the host time in a process context. 179 */ 180 181 struct adj_time_work { 182 struct work_struct work; 183 u64 host_time; 184 }; 185 186 static void hv_set_host_time(struct work_struct *work) 187 { 188 struct adj_time_work *wrk; 189 190 wrk = container_of(work, struct adj_time_work, work); 191 do_adj_guesttime(wrk->host_time); 192 kfree(wrk); 193 } 194 195 /* 196 * Synchronize time with host after reboot, restore, etc. 197 * 198 * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM. 199 * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time 200 * message after the timesync channel is opened. Since the hv_utils module is 201 * loaded after hv_vmbus, the first message is usually missed. The other 202 * thing is, systime is automatically set to emulated hardware clock which may 203 * not be UTC time or in the same time zone. So, to override these effects, we 204 * use the first 50 time samples for initial system time setting. 205 */ 206 static inline void adj_guesttime(u64 hosttime, u8 flags) 207 { 208 struct adj_time_work *wrk; 209 static s32 scnt = 50; 210 211 wrk = kmalloc(sizeof(struct adj_time_work), GFP_ATOMIC); 212 if (wrk == NULL) 213 return; 214 215 wrk->host_time = hosttime; 216 if ((flags & ICTIMESYNCFLAG_SYNC) != 0) { 217 INIT_WORK(&wrk->work, hv_set_host_time); 218 schedule_work(&wrk->work); 219 return; 220 } 221 222 if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) { 223 scnt--; 224 INIT_WORK(&wrk->work, hv_set_host_time); 225 schedule_work(&wrk->work); 226 } else 227 kfree(wrk); 228 } 229 230 /* 231 * Time Sync Channel message handler. 232 */ 233 static void timesync_onchannelcallback(void *context) 234 { 235 struct vmbus_channel *channel = context; 236 u32 recvlen; 237 u64 requestid; 238 struct icmsg_hdr *icmsghdrp; 239 struct ictimesync_data *timedatap; 240 u8 *time_txf_buf = util_timesynch.recv_buffer; 241 struct icmsg_negotiate *negop = NULL; 242 243 vmbus_recvpacket(channel, time_txf_buf, 244 PAGE_SIZE, &recvlen, &requestid); 245 246 if (recvlen > 0) { 247 icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[ 248 sizeof(struct vmbuspipe_hdr)]; 249 250 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 251 vmbus_prep_negotiate_resp(icmsghdrp, negop, 252 time_txf_buf, 253 util_fw_version, 254 ts_srv_version); 255 } else { 256 timedatap = (struct ictimesync_data *)&time_txf_buf[ 257 sizeof(struct vmbuspipe_hdr) + 258 sizeof(struct icmsg_hdr)]; 259 adj_guesttime(timedatap->parenttime, timedatap->flags); 260 } 261 262 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION 263 | ICMSGHDRFLAG_RESPONSE; 264 265 vmbus_sendpacket(channel, time_txf_buf, 266 recvlen, requestid, 267 VM_PKT_DATA_INBAND, 0); 268 } 269 } 270 271 /* 272 * Heartbeat functionality. 273 * Every two seconds, Hyper-V send us a heartbeat request message. 274 * we respond to this message, and Hyper-V knows we are alive. 275 */ 276 static void heartbeat_onchannelcallback(void *context) 277 { 278 struct vmbus_channel *channel = context; 279 u32 recvlen; 280 u64 requestid; 281 struct icmsg_hdr *icmsghdrp; 282 struct heartbeat_msg_data *heartbeat_msg; 283 u8 *hbeat_txf_buf = util_heartbeat.recv_buffer; 284 struct icmsg_negotiate *negop = NULL; 285 286 vmbus_recvpacket(channel, hbeat_txf_buf, 287 PAGE_SIZE, &recvlen, &requestid); 288 289 if (recvlen > 0) { 290 icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[ 291 sizeof(struct vmbuspipe_hdr)]; 292 293 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 294 vmbus_prep_negotiate_resp(icmsghdrp, negop, 295 hbeat_txf_buf, util_fw_version, 296 hb_srv_version); 297 } else { 298 heartbeat_msg = 299 (struct heartbeat_msg_data *)&hbeat_txf_buf[ 300 sizeof(struct vmbuspipe_hdr) + 301 sizeof(struct icmsg_hdr)]; 302 303 heartbeat_msg->seq_num += 1; 304 } 305 306 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION 307 | ICMSGHDRFLAG_RESPONSE; 308 309 vmbus_sendpacket(channel, hbeat_txf_buf, 310 recvlen, requestid, 311 VM_PKT_DATA_INBAND, 0); 312 } 313 } 314 315 static int util_probe(struct hv_device *dev, 316 const struct hv_vmbus_device_id *dev_id) 317 { 318 struct hv_util_service *srv = 319 (struct hv_util_service *)dev_id->driver_data; 320 int ret; 321 322 srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL); 323 if (!srv->recv_buffer) 324 return -ENOMEM; 325 if (srv->util_init) { 326 ret = srv->util_init(srv); 327 if (ret) { 328 ret = -ENODEV; 329 goto error1; 330 } 331 } 332 333 /* 334 * The set of services managed by the util driver are not performance 335 * critical and do not need batched reading. Furthermore, some services 336 * such as KVP can only handle one message from the host at a time. 337 * Turn off batched reading for all util drivers before we open the 338 * channel. 339 */ 340 341 set_channel_read_state(dev->channel, false); 342 343 ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0, 344 srv->util_cb, dev->channel); 345 if (ret) 346 goto error; 347 348 hv_set_drvdata(dev, srv); 349 /* 350 * Based on the host; initialize the framework and 351 * service version numbers we will negotiate. 352 */ 353 switch (vmbus_proto_version) { 354 case (VERSION_WS2008): 355 util_fw_version = UTIL_WS2K8_FW_VERSION; 356 sd_srv_version = SD_WS2008_VERSION; 357 ts_srv_version = TS_WS2008_VERSION; 358 hb_srv_version = HB_WS2008_VERSION; 359 break; 360 361 default: 362 util_fw_version = UTIL_FW_VERSION; 363 sd_srv_version = SD_VERSION; 364 ts_srv_version = TS_VERSION; 365 hb_srv_version = HB_VERSION; 366 } 367 368 return 0; 369 370 error: 371 if (srv->util_deinit) 372 srv->util_deinit(); 373 error1: 374 kfree(srv->recv_buffer); 375 return ret; 376 } 377 378 static int util_remove(struct hv_device *dev) 379 { 380 struct hv_util_service *srv = hv_get_drvdata(dev); 381 382 vmbus_close(dev->channel); 383 if (srv->util_deinit) 384 srv->util_deinit(); 385 kfree(srv->recv_buffer); 386 387 return 0; 388 } 389 390 static const struct hv_vmbus_device_id id_table[] = { 391 /* Shutdown guid */ 392 { HV_SHUTDOWN_GUID, 393 .driver_data = (unsigned long)&util_shutdown 394 }, 395 /* Time synch guid */ 396 { HV_TS_GUID, 397 .driver_data = (unsigned long)&util_timesynch 398 }, 399 /* Heartbeat guid */ 400 { HV_HEART_BEAT_GUID, 401 .driver_data = (unsigned long)&util_heartbeat 402 }, 403 /* KVP guid */ 404 { HV_KVP_GUID, 405 .driver_data = (unsigned long)&util_kvp 406 }, 407 /* VSS GUID */ 408 { HV_VSS_GUID, 409 .driver_data = (unsigned long)&util_vss 410 }, 411 /* File copy GUID */ 412 { HV_FCOPY_GUID, 413 .driver_data = (unsigned long)&util_fcopy 414 }, 415 { }, 416 }; 417 418 MODULE_DEVICE_TABLE(vmbus, id_table); 419 420 /* The one and only one */ 421 static struct hv_driver util_drv = { 422 .name = "hv_util", 423 .id_table = id_table, 424 .probe = util_probe, 425 .remove = util_remove, 426 }; 427 428 static int __init init_hyperv_utils(void) 429 { 430 pr_info("Registering HyperV Utility Driver\n"); 431 432 return vmbus_driver_register(&util_drv); 433 } 434 435 static void exit_hyperv_utils(void) 436 { 437 pr_info("De-Registered HyperV Utility Driver\n"); 438 439 vmbus_driver_unregister(&util_drv); 440 } 441 442 module_init(init_hyperv_utils); 443 module_exit(exit_hyperv_utils); 444 445 MODULE_DESCRIPTION("Hyper-V Utilities"); 446 MODULE_LICENSE("GPL"); 447