]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/hyperv/utilities/hv_util.c
MFC 295307,295308,295309,295606
[FreeBSD/stable/10.git] / sys / dev / hyperv / utilities / hv_util.c
1 /*-
2  * Copyright (c) 2014 Microsoft Corp.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 /*
30  * A common driver for all hyper-V util services.
31  */
32
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/bus.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/reboot.h>
39 #include <sys/timetc.h>
40 #include <sys/syscallsubr.h>
41
42 #include <dev/hyperv/include/hyperv.h>
43 #include "hv_kvp.h"
44
45 /* Time Sync data */
46 typedef struct {
47         uint64_t data;
48 } time_sync_data;
49
50 static void hv_shutdown_cb(void *context);
51 static void hv_heartbeat_cb(void *context);
52 static void hv_timesync_cb(void *context);
53
54 static int hv_timesync_init(hv_vmbus_service *serv);
55 static int hv_timesync_uninit(hv_vmbus_service *serv);
56 static void hv_set_host_time(void *context, int pending);
57
58 /*
59  * Note: GUID codes below are predefined by the host hypervisor
60  * (Hyper-V and Azure)interface and required for correct operation.
61  */
62 hv_vmbus_service service_table[] = {
63         /* Shutdown Service */
64         { .guid.data = {0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
65                         0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB},
66           .name  = "Hyper-V Shutdown Service\n",
67           .enabled = TRUE,
68           .callback = hv_shutdown_cb,
69         },
70
71         /* Time Synch Service */
72         { .guid.data = {0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
73                         0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf},
74           .name = "Hyper-V Time Synch Service\n",
75           .enabled = TRUE,
76           .init = hv_timesync_init,
77           .callback = hv_timesync_cb,
78           .uninit = hv_timesync_uninit,
79         },
80
81         /* Heartbeat Service */
82         { .guid.data = {0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
83                         0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d},
84           .name = "Hyper-V Heartbeat Service\n",
85           .enabled = TRUE,
86           .callback = hv_heartbeat_cb,
87         },
88
89         /* KVP (Key Value Pair) Service */
90         { .guid.data = {0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
91                         0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3,  0xe6},
92           .name = "Hyper-V KVP Service\n",
93           .enabled = TRUE,
94           .init = hv_kvp_init,
95           .callback = hv_kvp_callback,
96         },
97 };
98
99 /*
100  * Receive buffer pointers. There is one buffer per utility service. The
101  * buffer is allocated during attach().
102  */
103 uint8_t *receive_buffer[HV_MAX_UTIL_SERVICES];
104
105 static boolean_t destroyed_kvp = FALSE;
106
107 struct hv_ictimesync_data {
108         uint64_t    parenttime;
109         uint64_t    childtime;
110         uint64_t    roundtriptime;
111         uint8_t     flags;
112 } __packed;
113
114 static int
115 hv_timesync_init(hv_vmbus_service *serv)
116 {
117         void *time_msg = malloc(sizeof(time_sync_data), M_DEVBUF, M_WAITOK);
118         TASK_INIT(&serv->task, 1, hv_set_host_time, time_msg);
119         return (0);
120 }
121
122 static int
123 hv_timesync_uninit(hv_vmbus_service *serv)
124 {
125         taskqueue_drain(taskqueue_thread, &serv->task);
126         free(serv->task.ta_context, M_DEVBUF);
127         return (0);
128 }
129
130 static void
131 hv_negotiate_version(
132         struct hv_vmbus_icmsg_hdr*              icmsghdrp,
133         struct hv_vmbus_icmsg_negotiate*        negop,
134         uint8_t*                                buf)
135 {
136         icmsghdrp->icmsgsize = 0x10;
137
138         negop = (struct hv_vmbus_icmsg_negotiate *)&buf[
139                 sizeof(struct hv_vmbus_pipe_hdr) +
140                 sizeof(struct hv_vmbus_icmsg_hdr)];
141
142         if (negop->icframe_vercnt >= 2 &&
143             negop->icversion_data[1].major == 3) {
144                 negop->icversion_data[0].major = 3;
145                 negop->icversion_data[0].minor = 0;
146                 negop->icversion_data[1].major = 3;
147                 negop->icversion_data[1].minor = 0;
148         } else {
149                 negop->icversion_data[0].major = 1;
150                 negop->icversion_data[0].minor = 0;
151                 negop->icversion_data[1].major = 1;
152                 negop->icversion_data[1].minor = 0;
153         }
154
155         negop->icframe_vercnt = 1;
156         negop->icmsg_vercnt = 1;
157 }
158
159
160 /**
161  * Set host time based on time sync message from host
162  */
163 static void
164 hv_set_host_time(void *context, int pending)
165 {
166         time_sync_data* time_msg = (time_sync_data*) context;
167         uint64_t hosttime = time_msg->data;
168         struct timespec guest_ts, host_ts;
169         uint64_t host_tns;
170         int64_t diff;
171         int error;
172
173         host_tns = (hosttime - HV_WLTIMEDELTA) * 100;
174         host_ts.tv_sec = (time_t)(host_tns/HV_NANO_SEC_PER_SEC);
175         host_ts.tv_nsec = (long)(host_tns%HV_NANO_SEC_PER_SEC);
176
177         nanotime(&guest_ts);
178
179         diff = (int64_t)host_ts.tv_sec - (int64_t)guest_ts.tv_sec;
180
181         /*
182          * If host differs by 5 seconds then make the guest catch up
183          */
184         if (diff > 5 || diff < -5) {
185                 error = kern_clock_settime(curthread, CLOCK_REALTIME,
186                     &host_ts);
187         }
188 }
189
190 /**
191  * @brief Synchronize time with host after reboot, restore, etc.
192  *
193  * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
194  * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
195  * message after the timesync channel is opened. Since the hv_utils module is
196  * loaded after hv_vmbus, the first message is usually missed. The other
197  * thing is, systime is automatically set to emulated hardware clock which may
198  * not be UTC time or in the same time zone. So, to override these effects, we
199  * use the first 50 time samples for initial system time setting.
200  */
201 static inline
202 void hv_adj_guesttime(uint64_t hosttime, uint8_t flags)
203 {
204         time_sync_data* time_msg = service_table[HV_TIME_SYNCH].task.ta_context;
205
206         time_msg->data = hosttime;
207
208         if (((flags & HV_ICTIMESYNCFLAG_SYNC) != 0) ||
209                 ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0)) {
210                 taskqueue_enqueue(taskqueue_thread, &service_table[HV_TIME_SYNCH].task);
211         }
212 }
213
214 /**
215  * Time Sync Channel message handler
216  */
217 static void
218 hv_timesync_cb(void *context)
219 {
220         hv_vmbus_channel*       channel = context;
221         hv_vmbus_icmsg_hdr*     icmsghdrp;
222         uint32_t                recvlen;
223         uint64_t                requestId;
224         int                     ret;
225         uint8_t*                time_buf;
226         struct hv_ictimesync_data* timedatap;
227
228         time_buf = receive_buffer[HV_TIME_SYNCH];
229
230         ret = hv_vmbus_channel_recv_packet(channel, time_buf,
231                                             PAGE_SIZE, &recvlen, &requestId);
232
233         if ((ret == 0) && recvlen > 0) {
234             icmsghdrp = (struct hv_vmbus_icmsg_hdr *) &time_buf[
235                 sizeof(struct hv_vmbus_pipe_hdr)];
236
237             if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
238                 hv_negotiate_version(icmsghdrp, NULL, time_buf);
239             } else {
240                 timedatap = (struct hv_ictimesync_data *) &time_buf[
241                     sizeof(struct hv_vmbus_pipe_hdr) +
242                         sizeof(struct hv_vmbus_icmsg_hdr)];
243                 hv_adj_guesttime(timedatap->parenttime, timedatap->flags);
244             }
245
246             icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION
247                 | HV_ICMSGHDRFLAG_RESPONSE;
248
249             hv_vmbus_channel_send_packet(channel, time_buf,
250                 recvlen, requestId,
251                 HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
252         }
253 }
254
255 /**
256  * Shutdown
257  */
258 static void
259 hv_shutdown_cb(void *context)
260 {
261         uint8_t*                buf;
262         hv_vmbus_channel*               channel = context;
263         uint8_t                 execute_shutdown = 0;
264         hv_vmbus_icmsg_hdr*             icmsghdrp;
265         uint32_t                recv_len;
266         uint64_t                request_id;
267         int                             ret;
268         hv_vmbus_shutdown_msg_data*     shutdown_msg;
269
270         buf = receive_buffer[HV_SHUT_DOWN];
271
272         ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE,
273                                             &recv_len, &request_id);
274
275         if ((ret == 0) && recv_len > 0) {
276
277             icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
278                 &buf[sizeof(struct hv_vmbus_pipe_hdr)];
279
280             if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
281                 hv_negotiate_version(icmsghdrp, NULL, buf);
282
283             } else {
284                 shutdown_msg =
285                     (struct hv_vmbus_shutdown_msg_data *)
286                     &buf[sizeof(struct hv_vmbus_pipe_hdr) +
287                         sizeof(struct hv_vmbus_icmsg_hdr)];
288
289                 switch (shutdown_msg->flags) {
290                     case 0:
291                     case 1:
292                         icmsghdrp->status = HV_S_OK;
293                         execute_shutdown = 1;
294                         if(bootverbose)
295                             printf("Shutdown request received -"
296                                     " graceful shutdown initiated\n");
297                         break;
298                     default:
299                         icmsghdrp->status = HV_E_FAIL;
300                         execute_shutdown = 0;
301                         printf("Shutdown request received -"
302                             " Invalid request\n");
303                         break;
304                     }
305             }
306
307             icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION |
308                                  HV_ICMSGHDRFLAG_RESPONSE;
309
310             hv_vmbus_channel_send_packet(channel, buf,
311                                         recv_len, request_id,
312                                         HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
313         }
314
315         if (execute_shutdown)
316             shutdown_nice(RB_POWEROFF);
317 }
318
319 /**
320  * Process heartbeat message
321  */
322 static void
323 hv_heartbeat_cb(void *context)
324 {
325         uint8_t*                buf;
326         hv_vmbus_channel*       channel = context;
327         uint32_t                recvlen;
328         uint64_t                requestid;
329         int                     ret;
330
331         struct hv_vmbus_heartbeat_msg_data*     heartbeat_msg;
332         struct hv_vmbus_icmsg_hdr*              icmsghdrp;
333
334         buf = receive_buffer[HV_HEART_BEAT];
335
336         ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE, &recvlen,
337                                             &requestid);
338
339         if ((ret == 0) && recvlen > 0) {
340
341             icmsghdrp = (struct hv_vmbus_icmsg_hdr *)
342                 &buf[sizeof(struct hv_vmbus_pipe_hdr)];
343
344             if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
345                 hv_negotiate_version(icmsghdrp, NULL, buf);
346
347             } else {
348                 heartbeat_msg =
349                     (struct hv_vmbus_heartbeat_msg_data *)
350                         &buf[sizeof(struct hv_vmbus_pipe_hdr) +
351                              sizeof(struct hv_vmbus_icmsg_hdr)];
352
353                 heartbeat_msg->seq_num += 1;
354             }
355
356             icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION |
357                                  HV_ICMSGHDRFLAG_RESPONSE;
358
359             hv_vmbus_channel_send_packet(channel, buf, recvlen, requestid,
360                 HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0);
361         }
362 }
363
364
365 static int
366 hv_util_probe(device_t dev)
367 {
368         int i;
369         int rtn_value = ENXIO;
370
371         for (i = 0; i < HV_MAX_UTIL_SERVICES; i++) {
372             const char *p = vmbus_get_type(dev);
373             if (service_table[i].enabled && !memcmp(p, &service_table[i].guid, sizeof(hv_guid))) {
374                 device_set_softc(dev, (void *) (&service_table[i]));
375                 rtn_value = BUS_PROBE_DEFAULT;
376             }
377         }
378
379         return rtn_value;
380 }
381
382 static int
383 hv_util_attach(device_t dev)
384 {
385         struct hv_device*               hv_dev;
386         struct hv_vmbus_service*        service;
387         int                             ret;
388         size_t                          receive_buffer_offset;
389
390         hv_dev = vmbus_get_devctx(dev);
391         service = device_get_softc(dev);
392         receive_buffer_offset = service - &service_table[0];
393         device_printf(dev, "Hyper-V Service attaching: %s\n", service->name);
394         receive_buffer[receive_buffer_offset] =
395                 malloc(4 * PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
396
397         if (service->init != NULL) {
398             ret = service->init(service);
399             if (ret) {
400                 ret = ENODEV;
401                 goto error0;
402             }
403         }
404
405         /*
406          * These services are not performance critical and do not need
407          * batched reading. Furthermore, some services such as KVP can
408          * only handle one message from the host at a time.
409          * Turn off batched reading for all util drivers before we open the
410          * channel.
411          */
412         hv_set_channel_read_state(hv_dev->channel, FALSE);
413
414         ret = hv_vmbus_channel_open(hv_dev->channel, 4 * PAGE_SIZE,
415                     4 * PAGE_SIZE, NULL, 0,
416                     service->callback, hv_dev->channel);
417
418         if (ret)
419             goto error0;
420
421         return (0);
422
423         error0:
424
425             free(receive_buffer[receive_buffer_offset], M_DEVBUF);
426             receive_buffer[receive_buffer_offset] = NULL;
427
428         return (ret);
429 }
430
431 static int
432 hv_util_detach(device_t dev)
433 {
434         struct hv_device*               hv_dev;
435         struct hv_vmbus_service*        service;
436         size_t                          receive_buffer_offset;
437
438         if (!destroyed_kvp) {
439                 hv_kvp_deinit();
440                 destroyed_kvp = TRUE;
441         }
442
443         hv_dev = vmbus_get_devctx(dev);
444
445         hv_vmbus_channel_close(hv_dev->channel);
446         service = device_get_softc(dev);
447         receive_buffer_offset = service - &service_table[0];
448
449         if (service->uninit != NULL)
450             service->uninit(service);
451
452         free(receive_buffer[receive_buffer_offset], M_DEVBUF);
453         receive_buffer[receive_buffer_offset] = NULL;
454         return (0);
455 }
456
457 static int
458 hv_util_modevent(module_t mod, int event, void *arg)
459 {
460         switch (event) {
461         case MOD_LOAD:
462                 break;
463         case MOD_UNLOAD:
464                 break;
465         default:
466                 break;
467         }
468         return (0);
469 }
470
471 static device_method_t util_methods[] = {
472         /* Device interface */
473         DEVMETHOD(device_probe, hv_util_probe),
474         DEVMETHOD(device_attach, hv_util_attach),
475         DEVMETHOD(device_detach, hv_util_detach),
476         DEVMETHOD(device_shutdown, bus_generic_shutdown),
477         { 0, 0 } }
478 ;
479
480 static driver_t util_driver = { "hyperv-utils", util_methods, 0 };
481
482 static devclass_t util_devclass;
483
484 DRIVER_MODULE(hv_utils, vmbus, util_driver, util_devclass, hv_util_modevent, 0);
485 MODULE_VERSION(hv_utils, 1);
486 MODULE_DEPEND(hv_utils, vmbus, 1, 1, 1);