* src/esx/esx_driver.c: add esxSupportsLongMode() and update esxCapsInit() * src/esx/esx_vi.[ch]: Add AnyType handling for lists * src/esx/esx_vi_types.c: bind VI type HostCpuIdInfo
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 96d5976..745b744 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -27,6 +27,7 @@ * - Memory model: http://www.vmware.com/pdf/esx3_memory.pdf * - VI API reference: http://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/ * - VMX-file parameters: http://www.sanbarrow.com/vmx.html + * - CPUID: http://www.sandpile.org/ia32/cpuid.htm */ #include <config.h> @@ -62,19 +63,144 @@ typedef struct _esxPrivate { char *transport; int32_t maxVcpus; esxVI_Boolean supportsVMotion; + esxVI_Boolean supportsLongMode; /* aka x86_64 */ int32_t usedCpuTimeCounterId; } esxPrivate; +static esxVI_Boolean +esxSupportsLongMode(virConnectPtr conn) +{ + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + esxVI_HostCpuIdInfo *hostCpuIdInfoList = NULL; + esxVI_HostCpuIdInfo *hostCpuIdInfo = NULL; + char edxLongModeBit = '?'; + char edxFirstBit = '?'; + + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + goto failure; + } + + if (priv->supportsLongMode != esxVI_Boolean_Undefined) { + return priv->supportsLongMode; + } + + if (esxVI_EnsureSession(conn, priv->host) < 0) { + goto failure; + } + + if (esxVI_String_AppendValueToList(conn, &propertyNameList, + "hardware.cpuFeature") < 0 || + esxVI_GetObjectContent(conn, priv->host, priv->host->hostFolder, + "HostSystem", propertyNameList, + esxVI_Boolean_True, &hostSystem) < 0) { + goto failure; + } + + if (hostSystem == NULL) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Could not retrieve the HostSystem object"); + goto failure; + } + + for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL; + dynamicProperty = dynamicProperty->_next) { + if (STREQ(dynamicProperty->name, "hardware.cpuFeature")) { + if (esxVI_HostCpuIdInfo_CastListFromAnyType + (conn, dynamicProperty->val, &hostCpuIdInfoList) < 0) { + goto failure; + } + + for (hostCpuIdInfo = hostCpuIdInfoList; hostCpuIdInfo != NULL; + hostCpuIdInfo = hostCpuIdInfo->_next) { + if (hostCpuIdInfo->level->value == -2147483647) { /* 0x80000001 */ + #define _SKIP4 "%*c%*c%*c%*c" + #define _SKIP12 _SKIP4":"_SKIP4":"_SKIP4 + + /* Expected format: "--X-:----:----:----:----:----:----:----" */ + if (sscanf(hostCpuIdInfo->edx, + "%*c%*c%c%*c:"_SKIP12":"_SKIP12":%*c%*c%*c%c", + &edxLongModeBit, &edxFirstBit) != 2) { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "HostSystem property 'hardware.cpuFeature[].edx' " + "with value '%s' doesn't have expected format " + "'----:----:----:----:----:----:----:----'", + hostCpuIdInfo->edx); + goto failure; + } + + #undef _SKIP4 + #undef _SKIP12 + + if (edxLongModeBit == '1') { + priv->supportsLongMode = esxVI_Boolean_True; + } else if (edxLongModeBit == '0') { + priv->supportsLongMode = esxVI_Boolean_False; + } else { + ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Bit 29 (Long Mode) of HostSystem property " + "'hardware.cpuFeature[].edx' with value '%s' " + "has unexpected value '%c', expecting '0' " + "or '1'", hostCpuIdInfo->edx, edxLongModeBit); + goto failure; + } + + break; + } + } + + break; + } else { + VIR_WARN("Unexpected '%s' property", dynamicProperty->name); + } + } + + cleanup: + esxVI_String_Free(&propertyNameList); + esxVI_ObjectContent_Free(&hostSystem); + esxVI_HostCpuIdInfo_Free(&hostCpuIdInfoList); + + return priv->supportsLongMode; + + failure: + priv->supportsLongMode = esxVI_Boolean_Undefined; + + goto cleanup; +} + + + static virCapsPtr esxCapsInit(virConnectPtr conn) { + esxPrivate *priv = (esxPrivate *)conn->privateData; + esxVI_Boolean supportsLongMode = esxVI_Boolean_Undefined; virCapsPtr caps = NULL; virCapsGuestPtr guest = NULL; - /* FIXME: Need to detect real host architecture */ - caps = virCapabilitiesNew("i686", 1, 1); + if (priv->phantom) { + ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID, + "Not possible with a phantom connection"); + return NULL; + } + + supportsLongMode = esxSupportsLongMode(conn); + + if (supportsLongMode == esxVI_Boolean_Undefined) { + return NULL; + } + + if (supportsLongMode == esxVI_Boolean_True) { + caps = virCapabilitiesNew("x86_64", 1, 1); + } else { + caps = virCapabilitiesNew("i686", 1, 1); + } if (caps == NULL) { virReportOOMError(conn); @@ -84,9 +210,9 @@ esxCapsInit(virConnectPtr conn) virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x00, 0x50, 0x56 }); virCapabilitiesAddHostMigrateTransport(caps, "esx"); - /* FIXME: Need to detect real host architecture and word size */ - guest = - virCapabilitiesAddGuest(caps, "hvm", "i686", 32, NULL, NULL, 0, NULL); + /* i686 */ + guest = virCapabilitiesAddGuest(caps, "hvm", "i686", 32, NULL, NULL, 0, + NULL); if (guest == NULL) { goto failure; @@ -101,6 +227,25 @@ esxCapsInit(virConnectPtr conn) goto failure; } + /* x86_64 */ + if (supportsLongMode == esxVI_Boolean_True) { + guest = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 64, NULL, NULL, + 0, NULL); + + if (guest == NULL) { + goto failure; + } + + /* + * FIXME: Maybe distinguish betwen ESX and GSX here, see + * esxVMX_ParseConfig() and VIR_DOMAIN_VIRT_VMWARE + */ + if (virCapabilitiesAddGuestDomain(guest, "vmware", NULL, NULL, 0, + NULL) == NULL) { + goto failure; + } + } + return caps; failure: @@ -181,6 +326,7 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) priv->phantom = phantom; priv->maxVcpus = -1; priv->supportsVMotion = esxVI_Boolean_Undefined; + priv->supportsLongMode = esxVI_Boolean_Undefined; priv->usedCpuTimeCounterId = -1; /* Request credentials and login to non-phantom host/vCenter */ @@ -331,7 +477,11 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) } VIR_FREE(vCenter); + } + conn->privateData = priv; + + if (! phantom) { /* Setup capabilities */ priv->caps = esxCapsInit(conn); @@ -340,8 +490,6 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED) } } - conn->privateData = priv; - return VIR_DRV_OPEN_SUCCESS; failure: diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 29443db..32e9be3 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -833,6 +833,74 @@ esxVI_List_DeepCopy(virConnectPtr conn, esxVI_List **destList, } int +esxVI_List_CastFromAnyType(virConnectPtr conn, esxVI_AnyType *anyType, + esxVI_List **list, + esxVI_List_CastFromAnyTypeFunc castFromAnyTypeFunc, + esxVI_List_FreeFunc freeFunc) +{ + int result = 0; + xmlNodePtr childNode = NULL; + esxVI_AnyType *childAnyType = NULL; + esxVI_List *item = NULL; + + if (list == NULL || *list != NULL || + castFromAnyTypeFunc == NULL || freeFunc == NULL) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument"); + goto failure; + } + + if (anyType == NULL) { + return 0; + } + + if (! STRPREFIX(anyType->other, "ArrayOf")) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Expecting type to begin with 'ArrayOf' but found '%s'", + anyType->other); + goto failure; + } + + for (childNode = anyType->_node->xmlChildrenNode; childNode != NULL; + childNode = childNode->next) { + if (childNode->type != XML_ELEMENT_NODE) { + ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, + "Wrong XML element type %d", childNode->type); + goto failure; + } + + esxVI_AnyType_Free(&childAnyType); + + if (esxVI_AnyType_Deserialize(conn, childNode, &childAnyType) < 0) { + goto failure; + } + + item = NULL; + + if (castFromAnyTypeFunc(conn, childAnyType, &item) < 0) { + goto failure; + } + + if (esxVI_List_Append(conn, list, item) < 0) { + goto failure; + } + } + + + cleanup: + esxVI_AnyType_Free(&childAnyType); + + return result; + + failure: + freeFunc(list); + + result = -1; + + goto cleanup; +} + + +int esxVI_List_Serialize(virConnectPtr conn, esxVI_List *list, const char *element, virBufferPtr output, esxVI_Boolean required, esxVI_List_SerializeFunc serializeFunc) diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index 2aeea55..992f201 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -150,6 +150,9 @@ struct _esxVI_List { typedef int (*esxVI_List_FreeFunc) (esxVI_List **item); typedef int (*esxVI_List_DeepCopyFunc) (virConnectPtr conn, esxVI_List **dest, esxVI_List *src); +typedef int (*esxVI_List_CastFromAnyTypeFunc) (virConnectPtr conn, + esxVI_AnyType *anyType, + esxVI_List **item); typedef int (*esxVI_List_SerializeFunc) (virConnectPtr conn, esxVI_List *item, const char *element, virBufferPtr output, @@ -162,6 +165,10 @@ int esxVI_List_DeepCopy(virConnectPtr conn, esxVI_List **destList, esxVI_List *srcList, esxVI_List_DeepCopyFunc deepCopyFunc, esxVI_List_FreeFunc freeFunc); +int esxVI_List_CastFromAnyType(virConnectPtr conn, esxVI_AnyType *anyType, + esxVI_List **list, + esxVI_List_CastFromAnyTypeFunc castFromAnyTypeFunc, + esxVI_List_FreeFunc freeFunc); int esxVI_List_Serialize(virConnectPtr conn, esxVI_List *list, const char *element, virBufferPtr output, esxVI_Boolean required, diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index 1c6e112..09cdec3 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -115,6 +115,21 @@ +#define ESX_VI__TEMPLATE__LIST__CAST_FROM_ANY_TYPE(_type) \ + int \ + esxVI_##_type##_CastListFromAnyType(virConnectPtr conn, \ + esxVI_AnyType *anyType, \ + esxVI_##_type **list) \ + { \ + return esxVI_List_CastFromAnyType \ + (conn, anyType, (esxVI_List **)list, \ + (esxVI_List_CastFromAnyTypeFunc) \ + esxVI_##_type##_CastFromAnyType, \ + (esxVI_List_FreeFunc)esxVI_##_type##_Free); \ + } + + + #define ESX_VI__TEMPLATE__LIST__SERIALIZE(_type) \ int \ esxVI_##_type##_SerializeList(virConnectPtr conn, esxVI_##_type *list, \ @@ -1467,6 +1482,51 @@ ESX_VI__TEMPLATE__LIST__DESERIALIZE(DynamicProperty); + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: HostCpuIdInfo + */ + +/* esxVI_HostCpuIdInfo_Alloc */ +ESX_VI__TEMPLATE__ALLOC(HostCpuIdInfo); + +/* esxVI_HostCpuIdInfo_Free */ +ESX_VI__TEMPLATE__FREE(HostCpuIdInfo, +{ + esxVI_HostCpuIdInfo_Free(&item->_next); + + VIR_FREE(item->vendor); + VIR_FREE(item->eax); + VIR_FREE(item->ebx); + VIR_FREE(item->ecx); + VIR_FREE(item->edx); +}); + +/* esxVI_HostCpuIdInfo_CastFromAnyType */ +ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(HostCpuIdInfo); + +/* esxVI_HostCpuIdInfo_CastListFromAnyType */ +ESX_VI__TEMPLATE__LIST__CAST_FROM_ANY_TYPE(HostCpuIdInfo); + +/* esxVI_HostCpuIdInfo_Deserialize */ +ESX_VI__TEMPLATE__DESERIALIZE(HostCpuIdInfo, +{ + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Int, level); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, vendor); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, eax); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, ebx); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, ecx); + ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, edx); +}, +{ + ESX_VI__TEMPLATE__PROPERTY__REQUIRED(level); +}); + +/* esxVI_HostCpuIdInfo_DeserializeList */ +ESX_VI__TEMPLATE__LIST__DESERIALIZE(HostCpuIdInfo); + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VI Type: SelectionSpec */ diff --git a/src/esx/esx_vi_types.h b/src/esx/esx_vi_types.h index 1599b05..8738ab3 100644 --- a/src/esx/esx_vi_types.h +++ b/src/esx/esx_vi_types.h @@ -71,6 +71,7 @@ typedef enum _esxVI_VirtualMachinePowerState esxVI_VirtualMachinePowerState; typedef struct _esxVI_Fault esxVI_Fault; typedef struct _esxVI_ManagedObjectReference esxVI_ManagedObjectReference; typedef struct _esxVI_DynamicProperty esxVI_DynamicProperty; +typedef struct _esxVI_HostCpuIdInfo esxVI_HostCpuIdInfo; typedef struct _esxVI_SelectionSpec esxVI_SelectionSpec; typedef struct _esxVI_TraversalSpec esxVI_TraversalSpec; typedef struct _esxVI_ObjectSpec esxVI_ObjectSpec; @@ -527,7 +528,39 @@ int esxVI_DynamicProperty_Deserialize(virConnectPtr conn, xmlNodePtr node, esxVI_DynamicProperty **dynamicProperty); int esxVI_DynamicProperty_DeserializeList (virConnectPtr conn, xmlNodePtr node, - esxVI_DynamicProperty **dynamicProperty); + esxVI_DynamicProperty **dynamicPropertyList); + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * VI Type: HostCpuIdInfo + */ + +struct _esxVI_HostCpuIdInfo { + esxVI_HostCpuIdInfo *_next; /* optional */ + + esxVI_Int *level; /* required */ + char *vendor; /* optional */ + char *eax; /* optional */ + char *ebx; /* optional */ + char *ecx; /* optional */ + char *edx; /* optional */ +}; + +int esxVI_HostCpuIdInfo_Alloc(virConnectPtr conn, + esxVI_HostCpuIdInfo **hostCpuIdInfo); +void esxVI_HostCpuIdInfo_Free(esxVI_HostCpuIdInfo **hostCpuIdInfoList); +int esxVI_HostCpuIdInfo_CastFromAnyType(virConnectPtr conn, + esxVI_AnyType *anyType, + esxVI_HostCpuIdInfo **hostCpuIdInfo); +int esxVI_HostCpuIdInfo_CastListFromAnyType + (virConnectPtr conn, esxVI_AnyType *anyType, + esxVI_HostCpuIdInfo **hostCpuIdInfoList); +int esxVI_HostCpuIdInfo_Deserialize(virConnectPtr conn, xmlNodePtr node, + esxVI_HostCpuIdInfo **hostCpuIdInfo); +int esxVI_HostCpuIdInfo_DeserializeList + (virConnectPtr conn, xmlNodePtr node, + esxVI_HostCpuIdInfo **hostCpuIdInfoList); @@ -632,7 +665,7 @@ int esxVI_PropertyChange_Deserialize(virConnectPtr conn, xmlNodePtr node, esxVI_PropertyChange **propertyChange); int esxVI_PropertyChange_DeserializeList (virConnectPtr conn, xmlNodePtr node, - esxVI_PropertyChange **propertyChange); + esxVI_PropertyChange **propertyChangeList);
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list