summaryrefslogtreecommitdiffstats
path: root/sys/dev/hyperv/utilities/hv_util.c
diff options
context:
space:
mode:
authorgrehan <grehan@FreeBSD.org>2013-09-09 08:07:46 +0000
committergrehan <grehan@FreeBSD.org>2013-09-09 08:07:46 +0000
commit182a56e295b4378df6a37e1b8422fb6eec08613a (patch)
treef5547d3cd15ee1a4dc5d59529652353928079365 /sys/dev/hyperv/utilities/hv_util.c
parent9394ef331eb7d0ba7f22583970cc84b62ad9f19a (diff)
downloadFreeBSD-src-182a56e295b4378df6a37e1b8422fb6eec08613a.zip
FreeBSD-src-182a56e295b4378df6a37e1b8422fb6eec08613a.tar.gz
Latest update from Microsoft.
Obtained from: Microsoft Hyper-v dev team
Diffstat (limited to 'sys/dev/hyperv/utilities/hv_util.c')
-rw-r--r--sys/dev/hyperv/utilities/hv_util.c135
1 files changed, 63 insertions, 72 deletions
diff --git a/sys/dev/hyperv/utilities/hv_util.c b/sys/dev/hyperv/utilities/hv_util.c
index 43e4213..63fe93d 100644
--- a/sys/dev/hyperv/utilities/hv_util.c
+++ b/sys/dev/hyperv/utilities/hv_util.c
@@ -37,41 +37,19 @@
#include <sys/module.h>
#include <sys/reboot.h>
#include <sys/timetc.h>
+#include <sys/syscallsubr.h>
#include <dev/hyperv/include/hyperv.h>
+#include "hv_kvp.h"
-#define HV_SHUT_DOWN 0
-#define HV_TIME_SYNCH 1
-#define HV_HEART_BEAT 2
-#define HV_KVP 3
-#define HV_MAX_UTIL_SERVICES 4
-
-#define HV_NANO_SEC 1000000000L /* 10^ 9 nanosecs = 1 sec */
-
-#define HV_WLTIMEDELTA 116444736000000000L /* in 100ns unit */
-#define HV_ICTIMESYNCFLAG_PROBE 0
-#define HV_ICTIMESYNCFLAG_SYNC 1
-#define HV_ICTIMESYNCFLAG_SAMPLE 2
-
-typedef struct hv_vmbus_service {
- hv_guid guid; /* Hyper-V GUID */
- char* name; /* name of service */
- boolean_t enabled; /* service enabled */
- hv_work_queue* work_queue; /* background work queue */
- /*
- * function to initialize service
- */
- int (*init)(struct hv_vmbus_service *);
- /*
- * function to process Hyper-V messages
- */
- void (*callback)(void *);
-} hv_vmbus_service;
+/* Time Sync data */
+typedef struct {
+ uint64_t data;
+} time_sync_data;
static void hv_shutdown_cb(void *context);
static void hv_heartbeat_cb(void *context);
static void hv_timesync_cb(void *context);
-static void hv_kvp_cb(void *context);
static int hv_timesync_init(hv_vmbus_service *serv);
@@ -79,7 +57,7 @@ static int hv_timesync_init(hv_vmbus_service *serv);
* Note: GUID codes below are predefined by the host hypervisor
* (Hyper-V and Azure)interface and required for correct operation.
*/
-static hv_vmbus_service service_table[] = {
+hv_vmbus_service service_table[] = {
/* Shutdown Service */
{ .guid.data = {0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB},
@@ -103,36 +81,38 @@ static hv_vmbus_service service_table[] = {
.name = "Hyper-V Heartbeat Service\n",
.enabled = TRUE,
.callback = hv_heartbeat_cb,
-
},
/* KVP (Key Value Pair) Service */
{ .guid.data = {0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6},
.name = "Hyper-V KVP Service\n",
- .enabled = FALSE,
- .callback = hv_kvp_cb,
+ .enabled = TRUE,
+ .init = hv_kvp_init,
+ .callback = hv_kvp_callback,
},
};
-/**
- * Receive buffer pointers, there is one buffer per utility service. The
+/*
+ * Receive buffer pointers. There is one buffer per utility service. The
* buffer is allocated during attach().
*/
-static uint8_t* receive_buffer[HV_MAX_UTIL_SERVICES];
+uint8_t *receive_buffer[HV_MAX_UTIL_SERVICES];
struct hv_ictimesync_data {
uint64_t parenttime;
uint64_t childtime;
uint64_t roundtriptime;
- uint8_t flags;
+ uint8_t flags;
} __packed;
-static int hv_timesync_init(hv_vmbus_service *serv)
+static int
+hv_timesync_init(hv_vmbus_service *serv)
{
+
serv->work_queue = hv_work_queue_create("Time Sync");
if (serv->work_queue == NULL)
- return (ENOMEM);
+ return (ENOMEM);
return (0);
}
@@ -141,14 +121,14 @@ hv_negotiate_version(
struct hv_vmbus_icmsg_hdr* icmsghdrp,
struct hv_vmbus_icmsg_negotiate* negop,
uint8_t* buf)
- {
+{
icmsghdrp->icmsgsize = 0x10;
negop = (struct hv_vmbus_icmsg_negotiate *)&buf[
sizeof(struct hv_vmbus_pipe_hdr) +
sizeof(struct hv_vmbus_icmsg_hdr)];
- if (negop->icframe_vercnt == 2 &&
+ if (negop->icframe_vercnt >= 2 &&
negop->icversion_data[1].major == 3) {
negop->icversion_data[0].major = 3;
negop->icversion_data[0].minor = 0;
@@ -165,9 +145,6 @@ hv_negotiate_version(
negop->icmsg_vercnt = 1;
}
-static void hv_kvp_cb(void *context)
-{
-}
/**
* Set host time based on time sync message from host
@@ -175,24 +152,33 @@ static void hv_kvp_cb(void *context)
static void
hv_set_host_time(void *context)
{
- uint64_t hosttime = (uint64_t)context;
- struct timespec ts, host_ts;
- int64_t tns, host_tns, tmp, tsec;
+ time_sync_data *time_msg = context;
+ uint64_t hosttime = time_msg->data;
+ struct timespec guest_ts, host_ts;
+ uint64_t host_tns;
+ int64_t diff;
+ int error;
- nanotime(&ts);
- tns = ts.tv_sec * HV_NANO_SEC + ts.tv_nsec;
host_tns = (hosttime - HV_WLTIMEDELTA) * 100;
-
- tmp = host_tns;
- tsec = tmp / HV_NANO_SEC;
- host_ts.tv_nsec = (long) (tmp - (tsec * HV_NANO_SEC));
- host_ts.tv_sec = tsec;
-
- /* force time sync with host after reboot, restore, etc. */
- mtx_lock(&Giant);
- tc_setclock(&host_ts);
- resettodr();
- mtx_unlock(&Giant);
+ host_ts.tv_sec = (time_t)(host_tns/HV_NANO_SEC_PER_SEC);
+ host_ts.tv_nsec = (long)(host_tns%HV_NANO_SEC_PER_SEC);
+
+ nanotime(&guest_ts);
+
+ diff = (int64_t)host_ts.tv_sec - (int64_t)guest_ts.tv_sec;
+
+ /*
+ * If host differs by 5 seconds then make the guest catch up
+ */
+ if (diff > 5 || diff < -5) {
+ error = kern_clock_settime(curthread, CLOCK_REALTIME,
+ &host_ts);
+ }
+
+ /*
+ * Free the hosttime that was allocated in hv_adj_guesttime()
+ */
+ free(time_msg, M_DEVBUF);
}
/**
@@ -209,18 +195,23 @@ hv_set_host_time(void *context)
static inline
void hv_adj_guesttime(uint64_t hosttime, uint8_t flags)
{
- static int scnt = 50;
+ time_sync_data* time_msg;
- if ((flags & HV_ICTIMESYNCFLAG_SYNC) != 0) {
- hv_queue_work_item(service_table[HV_TIME_SYNCH].work_queue,
- hv_set_host_time, (void *) hosttime);
- return;
- }
+ time_msg = malloc(sizeof(time_sync_data), M_DEVBUF, M_NOWAIT);
- if ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) {
- scnt--;
- hv_queue_work_item(service_table[HV_TIME_SYNCH].work_queue,
- hv_set_host_time, (void *) hosttime);
+ if (time_msg == NULL)
+ return;
+
+ time_msg->data = hosttime;
+
+ if ((flags & HV_ICTIMESYNCFLAG_SYNC) != 0) {
+ hv_queue_work_item(service_table[HV_TIME_SYNCH].work_queue,
+ hv_set_host_time, time_msg);
+ } else if ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0) {
+ hv_queue_work_item(service_table[HV_TIME_SYNCH].work_queue,
+ hv_set_host_time, time_msg);
+ } else {
+ free(time_msg, M_DEVBUF);
}
}
@@ -405,7 +396,7 @@ hv_util_attach(device_t dev)
receive_buffer_offset = service - &service_table[0];
device_printf(dev, "Hyper-V Service attaching: %s\n", service->name);
receive_buffer[receive_buffer_offset] =
- malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
+ malloc(4 * PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
if (service->init != NULL) {
ret = service->init(service);
@@ -415,8 +406,8 @@ hv_util_attach(device_t dev)
}
}
- ret = hv_vmbus_channel_open(hv_dev->channel, 2 * PAGE_SIZE,
- 2 * PAGE_SIZE, NULL, 0,
+ ret = hv_vmbus_channel_open(hv_dev->channel, 4 * PAGE_SIZE,
+ 4 * PAGE_SIZE, NULL, 0,
service->callback, hv_dev->channel);
if (ret)
OpenPOWER on IntegriCloud