[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] ESX [06/12]: Add x86_64 detection based on the CPUID



* 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);
 
 
 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]