* - 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>
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);
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;
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:
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 */
}
VIR_FREE(vCenter);
+ }
+ conn->privateData = priv;
+
+ if (! phantom) {
/* Setup capabilities */
priv->caps = esxCapsInit(conn);
}
}
- conn->privateData = priv;
-
return VIR_DRV_OPEN_SUCCESS;
failure:
return -1;
}
+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,
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,
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,
+#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, \
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * 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
*/
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;
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);
esxVI_PropertyChange **propertyChange);
int esxVI_PropertyChange_DeserializeList
(virConnectPtr conn, xmlNodePtr node,
- esxVI_PropertyChange **propertyChange);
+ esxVI_PropertyChange **propertyChangeList);