diff options
author | grehan <grehan@FreeBSD.org> | 2013-09-09 08:07:46 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2013-09-09 08:07:46 +0000 |
commit | 182a56e295b4378df6a37e1b8422fb6eec08613a (patch) | |
tree | f5547d3cd15ee1a4dc5d59529652353928079365 /sys/dev/hyperv/utilities/hv_util.c | |
parent | 9394ef331eb7d0ba7f22583970cc84b62ad9f19a (diff) | |
download | FreeBSD-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.c | 135 |
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) |