mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
ESX 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
This commit is contained in:
parent
af4c893eb7
commit
15b0c4ffdb
@ -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:
|
||||
|
@ -832,6 +832,74 @@ esxVI_List_DeepCopy(virConnectPtr conn, esxVI_List **destList,
|
||||
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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user