Index: sys/dev/hyperv/utilities/hv_heartbeat.c =================================================================== --- sys/dev/hyperv/utilities/hv_heartbeat.c +++ sys/dev/hyperv/utilities/hv_heartbeat.c @@ -39,6 +39,12 @@ #include #include "vmbus_if.h" +#define HB_MAJOR 3 +#define HB_MINOR 0 +#define HB_VERSION VMBUS_IC_VERSION(HB_MAJOR, HB_MINOR) + +#define HB_WS2008_MAJOR 1 +#define HB_WS2008_VERSION VMBUS_IC_VERSION(HB_WS2008_MAJOR, HB_MINOR) static const struct vmbus_ic_desc vmbus_heartbeat_descs[] = { { @@ -58,7 +64,9 @@ int dlen, error; uint64_t xactid; void *data; + uint32_t vmbus_version, fw_ver, msg_ver; + vmbus_version = VMBUS_GET_VERSION(device_get_parent(sc->ic_dev), sc->ic_dev); /* * Receive request. */ @@ -80,7 +88,16 @@ */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: - error = vmbus_ic_negomsg(sc, data, &dlen); + switch(vmbus_version) { + case VMBUS_VERSION_WS2008: + fw_ver = UTIL_WS2008_FW_VERSION; + msg_ver = HB_WS2008_VERSION; + break; + default: + fw_ver = UTIL_FW_VERSION; + msg_ver = HB_VERSION; + } + error = vmbus_ic_negomsg(sc->ic_dev, data, &dlen, fw_ver, msg_ver); if (error) return; break; Index: sys/dev/hyperv/utilities/hv_kvp.h =================================================================== --- sys/dev/hyperv/utilities/hv_kvp.h +++ sys/dev/hyperv/utilities/hv_kvp.h @@ -28,7 +28,7 @@ #ifndef _KVP_H #define _KVP_H - +#include "vmbus_icreg.h" /* * An implementation of HyperV key value pair (KVP) functionality for FreeBSD * @@ -178,9 +178,10 @@ }__attribute__((packed)); struct hv_kvp_hdr { - uint8_t operation; - uint8_t pool; - uint16_t pad; + struct vmbus_icmsg_hdr ic_hdr; + uint8_t operation; + uint8_t pool; + uint16_t pad; } __attribute__((packed)); struct hv_kvp_exchg_msg_value { Index: sys/dev/hyperv/utilities/hv_kvp.c =================================================================== --- sys/dev/hyperv/utilities/hv_kvp.c +++ sys/dev/hyperv/utilities/hv_kvp.c @@ -61,7 +61,9 @@ #include #include +#include #include +#include #include "hv_util.h" #include "unicode.h" @@ -74,6 +76,18 @@ #define KVP_ERROR 1 #define kvp_hdr hdr.kvp_hdr +#define KVP_WS2008_MAJOR 1 +#define KVP_WS2008_MINOR 0 +#define KVP_WS2008_VERSION VMBUS_IC_VERSION(KVP_WS2008_MAJOR, KVP_WS2008_MINOR) + +#define KVP_WIN7_MAJOR 3 +#define KVP_WIN7_MINOR 0 +#define KVP_WIN7_VERSION VMBUS_IC_VERSION(KVP_WIN7_MAJOR, KVP_WIN7_MINOR) + +#define KVP_WIN8_MAJOR 4 +#define KVP_WIN8_MINOR 0 +#define KVP_WIN8_VERSION VMBUS_IC_VERSION(KVP_WIN8_MAJOR, KVP_WIN8_MINOR) + /* hv_kvp debug control */ static int hv_kvp_log = 0; @@ -207,53 +221,9 @@ sc->host_msg_len = rcv_len; sc->host_msg_id = request_id; sc->rcv_buf = rcv_buf; - sc->host_kvp_msg = (struct hv_kvp_msg *)&rcv_buf[ - sizeof(struct hv_vmbus_pipe_hdr) + - sizeof(struct hv_vmbus_icmsg_hdr)]; -} - - -/* - * hv_kvp - version neogtiation function - */ -static void -hv_kvp_negotiate_version(struct hv_vmbus_icmsg_hdr *icmsghdrp, uint8_t *buf) -{ - struct hv_vmbus_icmsg_negotiate *negop; - int icframe_vercnt; - int icmsg_vercnt; - - icmsghdrp->icmsgsize = 0x10; - - negop = (struct hv_vmbus_icmsg_negotiate *)&buf[ - sizeof(struct hv_vmbus_pipe_hdr) + - sizeof(struct hv_vmbus_icmsg_hdr)]; - icframe_vercnt = negop->icframe_vercnt; - icmsg_vercnt = negop->icmsg_vercnt; - - /* - * Select the framework version number we will support - */ - if ((icframe_vercnt >= 2) && (negop->icversion_data[1].major == 3)) { - icframe_vercnt = 3; - if (icmsg_vercnt > 2) - icmsg_vercnt = 4; - else - icmsg_vercnt = 3; - } else { - icframe_vercnt = 1; - icmsg_vercnt = 1; - } - - negop->icframe_vercnt = 1; - negop->icmsg_vercnt = 1; - negop->icversion_data[0].major = icframe_vercnt; - negop->icversion_data[0].minor = 0; - negop->icversion_data[1].major = icmsg_vercnt; - negop->icversion_data[1].minor = 0; + sc->host_kvp_msg = (struct hv_kvp_msg *)rcv_buf; } - /* * Convert ip related info in umsg from utf8 to utf16 and store in hmsg */ @@ -569,16 +539,16 @@ static void hv_kvp_respond_host(hv_kvp_sc *sc, int error) { - struct hv_vmbus_icmsg_hdr *hv_icmsg_hdrp; + struct vmbus_icmsg_hdr *hv_icmsg_hdrp; - hv_icmsg_hdrp = (struct hv_vmbus_icmsg_hdr *) - &sc->rcv_buf[sizeof(struct hv_vmbus_pipe_hdr)]; + hv_icmsg_hdrp = (struct vmbus_icmsg_hdr *)sc->rcv_buf; if (error) error = HV_KVP_E_FAIL; - hv_icmsg_hdrp->status = error; - hv_icmsg_hdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION | HV_ICMSGHDRFLAG_RESPONSE; + hv_icmsg_hdrp->ic_status = error; + hv_icmsg_hdrp->ic_flags = HV_ICMSGHDRFLAG_TRANSACTION | + HV_ICMSGHDRFLAG_RESPONSE; error = vmbus_chan_send(vmbus_get_channel(sc->dev), VMBUS_CHANPKT_TYPE_INBAND, 0, sc->rcv_buf, sc->host_msg_len, @@ -621,15 +591,17 @@ struct vmbus_channel *channel; uint32_t recvlen = 0; uint64_t requestid; - struct hv_vmbus_icmsg_hdr *icmsghdrp; - int ret = 0; - hv_kvp_sc *sc; + struct vmbus_icmsg_hdr *icmsghdrp; + int ret = 0, error; + hv_kvp_sc *sc; + uint32_t vmbus_version, fw_ver, msg_ver; hv_kvp_log_info("%s: entering hv_kvp_process_request\n", __func__); sc = (hv_kvp_sc*)context; kvp_buf = sc->util_sc.receive_buffer; channel = vmbus_get_channel(sc->dev); + vmbus_version = VMBUS_GET_VERSION(device_get_parent(sc->dev), sc->dev); recvlen = sc->util_sc.ic_buflen; ret = vmbus_chan_recv(channel, kvp_buf, &recvlen, &requestid); @@ -637,14 +609,25 @@ /* XXX check recvlen to make sure that it contains enough data */ while ((ret == 0) && (recvlen > 0)) { - - icmsghdrp = (struct hv_vmbus_icmsg_hdr *) - &kvp_buf[sizeof(struct hv_vmbus_pipe_hdr)]; + icmsghdrp = (struct vmbus_icmsg_hdr *)kvp_buf; hv_kvp_transaction_init(sc, recvlen, requestid, kvp_buf); - if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) { - hv_kvp_negotiate_version(icmsghdrp, kvp_buf); - hv_kvp_respond_host(sc, ret); + if (icmsghdrp->ic_type == HV_ICMSGTYPE_NEGOTIATE) { + switch(vmbus_version) { + case VMBUS_VERSION_WS2008: + fw_ver = UTIL_WS2008_FW_VERSION; + msg_ver = KVP_WS2008_VERSION; + break; + case VMBUS_VERSION_WIN7: + fw_ver = UTIL_FW_VERSION; + msg_ver = KVP_WIN7_VERSION; + default: + fw_ver = UTIL_FW_VERSION; + msg_ver = KVP_WIN8_VERSION; + } + error = vmbus_ic_negomsg(sc->dev, kvp_buf, &recvlen, + fw_ver, msg_ver); + hv_kvp_respond_host(sc, error); /* * It is ok to not acquire the mutex before setting Index: sys/dev/hyperv/utilities/hv_shutdown.c =================================================================== --- sys/dev/hyperv/utilities/hv_shutdown.c +++ sys/dev/hyperv/utilities/hv_shutdown.c @@ -41,6 +41,13 @@ #include "vmbus_if.h" +#define SD_MAJOR 3 +#define SD_MINOR 0 +#define SD_VERSION VMBUS_IC_VERSION(SD_MAJOR, SD_MINOR) + +#define SD_WS2008_MAJOR 1 +#define SD_WS2008_VERSION VMBUS_IC_VERSION(SD_WS2008_MAJOR, SD_MINOR) + static const struct vmbus_ic_desc vmbus_shutdown_descs[] = { { .ic_guid = { .hv_guid = { @@ -60,7 +67,9 @@ int dlen, error, do_shutdown = 0; uint64_t xactid; void *data; + uint32_t vmbus_version, fw_ver, msg_ver; + vmbus_version = VMBUS_GET_VERSION(device_get_parent(sc->ic_dev), sc->ic_dev); /* * Receive request. */ @@ -82,7 +91,16 @@ */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: - error = vmbus_ic_negomsg(sc, data, &dlen); + switch(vmbus_version) { + case VMBUS_VERSION_WS2008: + fw_ver = UTIL_WS2008_FW_VERSION; + msg_ver = SD_WS2008_VERSION; + break; + default: + fw_ver = UTIL_FW_VERSION; + msg_ver = SD_VERSION; + } + error = vmbus_ic_negomsg(sc->ic_dev, data, &dlen, fw_ver, msg_ver); if (error) return; break; Index: sys/dev/hyperv/utilities/hv_timesync.c =================================================================== --- sys/dev/hyperv/utilities/hv_timesync.c +++ sys/dev/hyperv/utilities/hv_timesync.c @@ -42,6 +42,13 @@ #include "vmbus_if.h" +#define TS_MAJOR 3 +#define TS_MINOR 0 +#define TS_VERSION VMBUS_IC_VERSION(TS_MAJOR, TS_MINOR) + +#define TS_WS2008_MAJOR 1 +#define TS_WS2008_VERSION VMBUS_IC_VERSION(TS_WS2008_MAJOR, TS_MINOR) + static const struct vmbus_ic_desc vmbus_timesync_descs[] = { { .ic_guid = { .hv_guid = { @@ -140,6 +147,9 @@ int dlen, error; uint64_t xactid; void *data; + uint32_t vmbus_version, fw_ver, msg_ver; + + vmbus_version = VMBUS_GET_VERSION(device_get_parent(sc->ic_dev), sc->ic_dev); /* * Receive request. @@ -162,7 +172,16 @@ */ switch (hdr->ic_type) { case VMBUS_ICMSG_TYPE_NEGOTIATE: - error = vmbus_ic_negomsg(sc, data, &dlen); + switch(vmbus_version) { + case VMBUS_VERSION_WS2008: + fw_ver = UTIL_WS2008_FW_VERSION; + msg_ver = TS_WS2008_VERSION; + break; + default: + fw_ver = UTIL_FW_VERSION; + msg_ver = TS_VERSION; + } + error = vmbus_ic_negomsg(sc->ic_dev, data, &dlen, fw_ver, msg_ver); if (error) return; break; Index: sys/dev/hyperv/utilities/hv_util.h =================================================================== --- sys/dev/hyperv/utilities/hv_util.h +++ sys/dev/hyperv/utilities/hv_util.h @@ -51,9 +51,20 @@ #define VMBUS_IC_DESC_END { .ic_desc = NULL } -int hv_util_attach(device_t dev, vmbus_chan_callback_t cb); -int hv_util_detach(device_t dev); -int vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]); -int vmbus_ic_negomsg(struct hv_util_sc *, void *data, int *dlen); +int hv_util_attach(device_t dev, vmbus_chan_callback_t cb); +int hv_util_detach(device_t dev); +int vmbus_ic_probe(device_t dev, const struct vmbus_ic_desc descs[]); +int vmbus_ic_negomsg(device_t dev, void *data, int *dlen0, + uint32_t fw_ver, uint32_t msg_ver); +/* + * Framework version for util services. + */ +#define UTIL_FW_MINOR 0 + +#define UTIL_WS2008_FW_MAJOR 1 +#define UTIL_WS2008_FW_VERSION VMBUS_IC_VERSION(UTIL_WS2008_FW_MAJOR, UTIL_FW_MINOR) + +#define UTIL_FW_MAJOR 3 +#define UTIL_FW_VERSION VMBUS_IC_VERSION(UTIL_FW_MAJOR, UTIL_FW_MINOR) #endif Index: sys/dev/hyperv/utilities/hv_util.c =================================================================== --- sys/dev/hyperv/utilities/hv_util.c +++ sys/dev/hyperv/utilities/hv_util.c @@ -54,42 +54,23 @@ CTASSERT(VMBUS_IC_NEGOSZ < VMBUS_IC_BRSIZE); int -vmbus_ic_negomsg(struct hv_util_sc *sc, void *data, int *dlen0) +vmbus_ic_negomsg(device_t dev, void *data, int *dlen0, + uint32_t fw_ver, uint32_t msg_ver) { struct vmbus_icmsg_negotiate *nego; - int cnt, major, dlen = *dlen0; + int i, cnt, dlen = *dlen0; + uint32_t sel_fw_ver, sel_msg_ver; + boolean_t found = FALSE; + nego = data; /* * Preliminary message size verification */ if (dlen < sizeof(*nego)) { - device_printf(sc->ic_dev, "truncated ic negotiate, len %d\n", - dlen); - return EINVAL; - } - nego = data; - - cnt = nego->ic_fwver_cnt + nego->ic_msgver_cnt; - if (dlen < __offsetof(struct vmbus_icmsg_negotiate, ic_ver[cnt])) { - device_printf(sc->ic_dev, "ic negotiate does not contain " - "versions %d\n", dlen); + device_printf(dev, "truncated ic negotiate, len %d\n", dlen); return EINVAL; } - /* Select major version; XXX looks wrong. */ - if (nego->ic_fwver_cnt >= 2 && VMBUS_ICVER_MAJOR(nego->ic_ver[1]) == 3) - major = 3; - else - major = 1; - - /* One framework version */ - nego->ic_fwver_cnt = 1; - nego->ic_ver[0] = VMBUS_IC_VERSION(major, 0); - - /* One message version */ - nego->ic_msgver_cnt = 1; - nego->ic_ver[1] = VMBUS_IC_VERSION(major, 0); - /* Update data size */ nego->ic_hdr.ic_dsize = VMBUS_IC_NEGOSZ - sizeof(struct vmbus_icmsg_hdr); @@ -98,7 +79,69 @@ if (dlen < VMBUS_IC_NEGOSZ) *dlen0 = VMBUS_IC_NEGOSZ; - return 0; + cnt = nego->ic_fwver_cnt + nego->ic_msgver_cnt; + if (dlen < __offsetof(struct vmbus_icmsg_negotiate, ic_ver[cnt])) { + device_printf(dev, "ic negotiate does not contain versions %d\n", + dlen); + return EINVAL; + } + + /* + * Select the framework version number we will support. + */ + for (i = 0; i < nego->ic_fwver_cnt; i++) { + if (nego->ic_ver[i] == fw_ver) { + sel_fw_ver = nego->ic_ver[i]; + found = TRUE; + break; + } + } + + if (!found) + goto handle_error; + found = FALSE; + + /* + * Select the message version number we will support. + */ + for (i = nego->ic_fwver_cnt; + i < nego->ic_fwver_cnt + nego->ic_msgver_cnt; i++) { + if (nego->ic_ver[i] == msg_ver) { + sel_msg_ver = nego->ic_ver[i]; + found = TRUE; + break; + } + } + +handle_error: + if (bootverbose) { + device_printf(dev, "selected framework ver: [%d:%d]\n", + VMBUS_ICVER_MAJOR(sel_fw_ver), VMBUS_ICVER_MINOR(sel_fw_ver)); + for (i = 0; i < nego->ic_fwver_cnt; i++) { + device_printf(dev, "host provided framework ver: [%d:%d]\n", + VMBUS_ICVER_MAJOR(nego->ic_ver[i]), + VMBUS_ICVER_MINOR(nego->ic_ver[i])); + } + device_printf(dev, "selected message ver: [%d:%d]\n", + VMBUS_ICVER_MAJOR(sel_msg_ver), VMBUS_ICVER_MINOR(sel_msg_ver)); + for (i = nego->ic_fwver_cnt; + i < nego->ic_fwver_cnt + nego->ic_msgver_cnt; i++) { + device_printf(dev, "host provided message ver: [%d:%d]\n", + VMBUS_ICVER_MAJOR(nego->ic_ver[i]), + VMBUS_ICVER_MINOR(nego->ic_ver[i])); + } + } + if (!found) { + nego->ic_fwver_cnt = 0; + nego->ic_msgver_cnt = 0; + } else { + nego->ic_fwver_cnt = 1; + nego->ic_msgver_cnt = 1; + } + + nego->ic_ver[0] = sel_fw_ver; + nego->ic_ver[1] = sel_msg_ver; + return found ? 0 : 1; } int Index: sys/dev/hyperv/utilities/hv_utilreg.h =================================================================== --- sys/dev/hyperv/utilities/hv_utilreg.h +++ sys/dev/hyperv/utilities/hv_utilreg.h @@ -48,44 +48,4 @@ #define HV_ICMSGHDRFLAG_REQUEST 2 #define HV_ICMSGHDRFLAG_RESPONSE 4 -typedef struct hv_vmbus_pipe_hdr { - uint32_t flags; - uint32_t msgsize; -} __packed hv_vmbus_pipe_hdr; - -typedef struct hv_vmbus_ic_version { - uint16_t major; - uint16_t minor; -} __packed hv_vmbus_ic_version; - -typedef struct hv_vmbus_icmsg_hdr { - hv_vmbus_ic_version icverframe; - uint16_t icmsgtype; - hv_vmbus_ic_version icvermsg; - uint16_t icmsgsize; - uint32_t status; - uint8_t ictransaction_id; - uint8_t icflags; - uint8_t reserved[2]; -} __packed hv_vmbus_icmsg_hdr; - -typedef struct hv_vmbus_icmsg_negotiate { - uint16_t icframe_vercnt; - uint16_t icmsg_vercnt; - uint32_t reserved; - hv_vmbus_ic_version icversion_data[1]; /* any size array */ -} __packed hv_vmbus_icmsg_negotiate; - -typedef struct hv_vmbus_shutdown_msg_data { - uint32_t reason_code; - uint32_t timeout_seconds; - uint32_t flags; - uint8_t display_message[2048]; -} __packed hv_vmbus_shutdown_msg_data; - -typedef struct hv_vmbus_heartbeat_msg_data { - uint64_t seq_num; - uint32_t reserved[8]; -} __packed hv_vmbus_heartbeat_msg_data; - #endif /* !_HV_UTILREG_H_ */ Index: sys/dev/hyperv/utilities/vmbus_icreg.h =================================================================== --- sys/dev/hyperv/utilities/vmbus_icreg.h +++ sys/dev/hyperv/utilities/vmbus_icreg.h @@ -39,6 +39,11 @@ #define VMBUS_ICMSG_STATUS_OK 0x00000000 #define VMBUS_ICMSG_STATUS_FAIL 0x80004005 +/* + * Version for both framework and message is + * 32 bits long with major on higher 16 bits + * and minor on lower 16 bits. + */ #define VMBUS_IC_VERSION(major, minor) ((major) | (((uint32_t)(minor)) << 16)) #define VMBUS_ICVER_MAJOR(ver) ((ver) & 0xffff) #define VMBUS_ICVER_MINOR(ver) (((ver) & 0xffff0000) >> 16)