mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-04 10:55:19 +00:00
cpu: Add support for CPU vendor
By specifying <vendor> element in CPU requirements a guest can be restricted to run only on CPUs by a given vendor. Host CPU vendor is also specified in capabilities XML. The vendor is checked when migrating a guest but it's not forced, i.e., guests configured without <vendor> element can be freely migrated.
This commit is contained in:
parent
d9332c23b4
commit
af53714f47
@ -22,6 +22,7 @@ BIOS you will see</p>
|
|||||||
<vmx/>
|
<vmx/>
|
||||||
</features>
|
</features>
|
||||||
<model>core2duo</model>
|
<model>core2duo</model>
|
||||||
|
<vendor>Intel</vendor>
|
||||||
<topology sockets="1" cores="2" threads="1"/>
|
<topology sockets="1" cores="2" threads="1"/>
|
||||||
<feature name="lahf_lm"/>
|
<feature name="lahf_lm"/>
|
||||||
<feature name='xtpr'/>
|
<feature name='xtpr'/>
|
||||||
|
@ -220,6 +220,7 @@
|
|||||||
...
|
...
|
||||||
<cpu match='exact'>
|
<cpu match='exact'>
|
||||||
<model>core2duo</model>
|
<model>core2duo</model>
|
||||||
|
<vendor>Intel</vendor>
|
||||||
<topology sockets='1' cores='2' threads='1'/>
|
<topology sockets='1' cores='2' threads='1'/>
|
||||||
<feature policy='disable' name='lahf_lm'/>
|
<feature policy='disable' name='lahf_lm'/>
|
||||||
</cpu>
|
</cpu>
|
||||||
@ -267,6 +268,13 @@
|
|||||||
definition can be found in <code>cpu_map.xml</code> file installed
|
definition can be found in <code>cpu_map.xml</code> file installed
|
||||||
in libvirt's data directory.</dd>
|
in libvirt's data directory.</dd>
|
||||||
|
|
||||||
|
<dt><code>vendor</code></dt>
|
||||||
|
<dd><span class="since">Since 0.8.3</span> the content of the
|
||||||
|
<code>vendor</code> element specifies CPU vendor requested by the
|
||||||
|
guest. If this element is missing, the guest can be run on a CPU
|
||||||
|
matching given features regardless on its vendor. The list of
|
||||||
|
supported vendors can be found in <code>cpu_map.xml</code>.</dd>
|
||||||
|
|
||||||
<dt><code>topology</code></dt>
|
<dt><code>topology</code></dt>
|
||||||
<dd>The <code>topology</code> element specifies requested topology of
|
<dd>The <code>topology</code> element specifies requested topology of
|
||||||
virtual CPU provided to the guest. Three non-zero values have to be
|
virtual CPU provided to the guest. Three non-zero values have to be
|
||||||
|
@ -79,6 +79,11 @@
|
|||||||
<element name='model'>
|
<element name='model'>
|
||||||
<text/>
|
<text/>
|
||||||
</element>
|
</element>
|
||||||
|
<optional>
|
||||||
|
<element name='vendor'>
|
||||||
|
<text/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
<element name='topology'>
|
<element name='topology'>
|
||||||
<attribute name='sockets'>
|
<attribute name='sockets'>
|
||||||
<ref name='positiveInteger'/>
|
<ref name='positiveInteger'/>
|
||||||
|
@ -1557,6 +1557,7 @@
|
|||||||
<interleave>
|
<interleave>
|
||||||
<ref name="cpuModel"/>
|
<ref name="cpuModel"/>
|
||||||
<optional>
|
<optional>
|
||||||
|
<ref name="cpuVendor"/>
|
||||||
<ref name="cpuTopology"/>
|
<ref name="cpuTopology"/>
|
||||||
</optional>
|
</optional>
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
@ -1584,6 +1585,12 @@
|
|||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name="cpuVendor">
|
||||||
|
<element name="vendor">
|
||||||
|
<text/>
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
|
|
||||||
<define name="cpuFeature">
|
<define name="cpuFeature">
|
||||||
<element name="feature">
|
<element name="feature">
|
||||||
<attribute name="policy">
|
<attribute name="policy">
|
||||||
|
@ -58,6 +58,7 @@ virCPUDefFree(virCPUDefPtr def)
|
|||||||
|
|
||||||
VIR_FREE(def->model);
|
VIR_FREE(def->model);
|
||||||
VIR_FREE(def->arch);
|
VIR_FREE(def->arch);
|
||||||
|
VIR_FREE(def->vendor);
|
||||||
|
|
||||||
for (i = 0 ; i < def->nfeatures ; i++)
|
for (i = 0 ; i < def->nfeatures ; i++)
|
||||||
VIR_FREE(def->features[i].name);
|
VIR_FREE(def->features[i].name);
|
||||||
@ -79,6 +80,7 @@ virCPUDefCopy(const virCPUDefPtr cpu)
|
|||||||
if (VIR_ALLOC(copy) < 0
|
if (VIR_ALLOC(copy) < 0
|
||||||
|| (cpu->arch && !(copy->arch = strdup(cpu->arch)))
|
|| (cpu->arch && !(copy->arch = strdup(cpu->arch)))
|
||||||
|| (cpu->model && !(copy->model = strdup(cpu->model)))
|
|| (cpu->model && !(copy->model = strdup(cpu->model)))
|
||||||
|
|| (cpu->vendor && !(copy->vendor = strdup(cpu->vendor)))
|
||||||
|| VIR_ALLOC_N(copy->features, cpu->nfeatures) < 0)
|
|| VIR_ALLOC_N(copy->features, cpu->nfeatures) < 0)
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
|
|
||||||
@ -173,6 +175,13 @@ virCPUDefParseXML(const xmlNodePtr node,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def->vendor = virXPathString("string(./vendor[1])", ctxt);
|
||||||
|
if (def->vendor && !def->model) {
|
||||||
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("CPU vendor specified without CPU model"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (virXPathNode("./topology[1]", ctxt)) {
|
if (virXPathNode("./topology[1]", ctxt)) {
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long ul;
|
unsigned long ul;
|
||||||
@ -349,6 +358,11 @@ virCPUDefFormatBuf(virBufferPtr buf,
|
|||||||
if (def->model)
|
if (def->model)
|
||||||
virBufferVSprintf(buf, "%s <model>%s</model>\n", indent, def->model);
|
virBufferVSprintf(buf, "%s <model>%s</model>\n", indent, def->model);
|
||||||
|
|
||||||
|
if (def->vendor) {
|
||||||
|
virBufferVSprintf(buf, "%s <vendor>%s</vendor>\n",
|
||||||
|
indent, def->vendor);
|
||||||
|
}
|
||||||
|
|
||||||
if (def->sockets && def->cores && def->threads) {
|
if (def->sockets && def->cores && def->threads) {
|
||||||
virBufferVSprintf(buf, "%s <topology", indent);
|
virBufferVSprintf(buf, "%s <topology", indent);
|
||||||
virBufferVSprintf(buf, " sockets='%u'", def->sockets);
|
virBufferVSprintf(buf, " sockets='%u'", def->sockets);
|
||||||
|
@ -72,6 +72,7 @@ struct _virCPUDef {
|
|||||||
int match; /* enum virCPUMatch */
|
int match; /* enum virCPUMatch */
|
||||||
char *arch;
|
char *arch;
|
||||||
char *model;
|
char *model;
|
||||||
|
char *vendor;
|
||||||
unsigned int sockets;
|
unsigned int sockets;
|
||||||
unsigned int cores;
|
unsigned int cores;
|
||||||
unsigned int threads;
|
unsigned int threads;
|
||||||
|
@ -173,14 +173,15 @@ cpuEncode(const char *arch,
|
|||||||
union cpuData **required,
|
union cpuData **required,
|
||||||
union cpuData **optional,
|
union cpuData **optional,
|
||||||
union cpuData **disabled,
|
union cpuData **disabled,
|
||||||
union cpuData **forbidden)
|
union cpuData **forbidden,
|
||||||
|
union cpuData **vendor)
|
||||||
{
|
{
|
||||||
struct cpuArchDriver *driver;
|
struct cpuArchDriver *driver;
|
||||||
|
|
||||||
VIR_DEBUG("arch=%s, cpu=%p, forced=%p, required=%p, "
|
VIR_DEBUG("arch=%s, cpu=%p, forced=%p, required=%p, "
|
||||||
"optional=%p, disabled=%p, forbidden=%p",
|
"optional=%p, disabled=%p, forbidden=%p, vendor=%p",
|
||||||
NULLSTR(arch), cpu, forced, required,
|
NULLSTR(arch), cpu, forced, required,
|
||||||
optional, disabled, forbidden);
|
optional, disabled, forbidden, vendor);
|
||||||
|
|
||||||
if ((driver = cpuGetSubDriver(arch)) == NULL)
|
if ((driver = cpuGetSubDriver(arch)) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
@ -193,7 +194,7 @@ cpuEncode(const char *arch,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return driver->encode(cpu, forced, required,
|
return driver->encode(cpu, forced, required,
|
||||||
optional, disabled, forbidden);
|
optional, disabled, forbidden, vendor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,7 +58,8 @@ typedef int
|
|||||||
union cpuData **required,
|
union cpuData **required,
|
||||||
union cpuData **optional,
|
union cpuData **optional,
|
||||||
union cpuData **disabled,
|
union cpuData **disabled,
|
||||||
union cpuData **forbidden);
|
union cpuData **forbidden,
|
||||||
|
union cpuData **vendor);
|
||||||
|
|
||||||
typedef void
|
typedef void
|
||||||
(*cpuArchDataFree) (union cpuData *data);
|
(*cpuArchDataFree) (union cpuData *data);
|
||||||
@ -119,7 +120,8 @@ cpuEncode (const char *arch,
|
|||||||
union cpuData **required,
|
union cpuData **required,
|
||||||
union cpuData **optional,
|
union cpuData **optional,
|
||||||
union cpuData **disabled,
|
union cpuData **disabled,
|
||||||
union cpuData **forbidden);
|
union cpuData **forbidden,
|
||||||
|
union cpuData **vendor);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
cpuDataFree (const char *arch,
|
cpuDataFree (const char *arch,
|
||||||
|
@ -32,9 +32,14 @@
|
|||||||
|
|
||||||
#define CPUMAPFILE PKGDATADIR "/cpu_map.xml"
|
#define CPUMAPFILE PKGDATADIR "/cpu_map.xml"
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(cpuMapElement, CPU_MAP_ELEMENT_LAST,
|
||||||
|
"vendor",
|
||||||
|
"feature",
|
||||||
|
"model")
|
||||||
|
|
||||||
|
|
||||||
static int load(xmlXPathContextPtr ctxt,
|
static int load(xmlXPathContextPtr ctxt,
|
||||||
const char *node,
|
enum cpuMapElement element,
|
||||||
cpuMapLoadCallback callback,
|
cpuMapLoadCallback callback,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
@ -47,9 +52,10 @@ static int load(xmlXPathContextPtr ctxt,
|
|||||||
cur = ctxt_node->children;
|
cur = ctxt_node->children;
|
||||||
while (cur != NULL) {
|
while (cur != NULL) {
|
||||||
if (cur->type == XML_ELEMENT_NODE &&
|
if (cur->type == XML_ELEMENT_NODE &&
|
||||||
xmlStrEqual(cur->name, BAD_CAST node)) {
|
xmlStrEqual(cur->name,
|
||||||
|
BAD_CAST cpuMapElementTypeToString(element))) {
|
||||||
ctxt->node = cur;
|
ctxt->node = cur;
|
||||||
if (callback(ctxt, data) < 0)
|
if (callback(element, ctxt, data) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,16 +72,15 @@ cleanup:
|
|||||||
|
|
||||||
|
|
||||||
int cpuMapLoad(const char *arch,
|
int cpuMapLoad(const char *arch,
|
||||||
cpuMapLoadCallback feature_cb,
|
cpuMapLoadCallback cb,
|
||||||
void *model_data,
|
void *data)
|
||||||
cpuMapLoadCallback model_cb,
|
|
||||||
void *feature_data)
|
|
||||||
{
|
{
|
||||||
xmlDocPtr xml = NULL;
|
xmlDocPtr xml = NULL;
|
||||||
xmlXPathContextPtr ctxt = NULL;
|
xmlXPathContextPtr ctxt = NULL;
|
||||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
char *xpath = NULL;
|
char *xpath = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
int element;
|
||||||
|
|
||||||
if (arch == NULL) {
|
if (arch == NULL) {
|
||||||
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
@ -83,6 +88,12 @@ int cpuMapLoad(const char *arch,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cb == NULL) {
|
||||||
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("no callback provided"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((xml = xmlParseFile(CPUMAPFILE)) == NULL) {
|
if ((xml = xmlParseFile(CPUMAPFILE)) == NULL) {
|
||||||
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
_("cannot parse CPU map file: %s"),
|
_("cannot parse CPU map file: %s"),
|
||||||
@ -107,11 +118,12 @@ int cpuMapLoad(const char *arch,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((feature_cb && load(ctxt, "feature", feature_cb, feature_data) < 0) ||
|
for (element = 0; element < CPU_MAP_ELEMENT_LAST; element++) {
|
||||||
(model_cb && load(ctxt, "model", model_cb, model_data) < 0)) {
|
if (load(ctxt, element, cb, data) < 0) {
|
||||||
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
_("cannot parse CPU map for %s architecture"), arch);
|
_("cannot parse CPU map for %s architecture"), arch);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -27,15 +27,25 @@
|
|||||||
# include "xml.h"
|
# include "xml.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum cpuMapElement {
|
||||||
|
CPU_MAP_ELEMENT_VENDOR,
|
||||||
|
CPU_MAP_ELEMENT_FEATURE,
|
||||||
|
CPU_MAP_ELEMENT_MODEL,
|
||||||
|
|
||||||
|
CPU_MAP_ELEMENT_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
VIR_ENUM_DECL(cpuMapElement)
|
||||||
|
|
||||||
|
|
||||||
typedef int
|
typedef int
|
||||||
(*cpuMapLoadCallback) (xmlXPathContextPtr ctxt,
|
(*cpuMapLoadCallback) (enum cpuMapElement element,
|
||||||
|
xmlXPathContextPtr ctxt,
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
cpuMapLoad(const char *arch,
|
cpuMapLoad(const char *arch,
|
||||||
cpuMapLoadCallback feature_cb,
|
cpuMapLoadCallback cb,
|
||||||
void *model_data,
|
void *data);
|
||||||
cpuMapLoadCallback model_cb,
|
|
||||||
void *feature_data);
|
|
||||||
|
|
||||||
#endif /* __VIR_CPU_MAP_H__ */
|
#endif /* __VIR_CPU_MAP_H__ */
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
<cpus>
|
<cpus>
|
||||||
<arch name='x86'>
|
<arch name='x86'>
|
||||||
|
<!-- vendor definitions -->
|
||||||
|
<vendor name='Intel' string='GenuineIntel'/>
|
||||||
|
<vendor name='AMD' string='AuthenticAMD'/>
|
||||||
|
|
||||||
<!-- standard features, EDX -->
|
<!-- standard features, EDX -->
|
||||||
<feature name='fpu'> <!-- CPUID_FP87 -->
|
<feature name='fpu'> <!-- CPUID_FP87 -->
|
||||||
<cpuid function='0x00000001' edx='0x00000001'/>
|
<cpuid function='0x00000001' edx='0x00000001'/>
|
||||||
@ -310,6 +314,7 @@
|
|||||||
|
|
||||||
<model name='phenom'>
|
<model name='phenom'>
|
||||||
<model name='pentiumpro'/>
|
<model name='pentiumpro'/>
|
||||||
|
<vendor name='AMD'/>
|
||||||
<feature name='mtrr'/>
|
<feature name='mtrr'/>
|
||||||
<feature name='clflush'/>
|
<feature name='clflush'/>
|
||||||
<feature name='mca'/>
|
<feature name='mca'/>
|
||||||
@ -328,6 +333,7 @@
|
|||||||
|
|
||||||
<model name='athlon'>
|
<model name='athlon'>
|
||||||
<model name='pentiumpro'/>
|
<model name='pentiumpro'/>
|
||||||
|
<vendor name='AMD'/>
|
||||||
<feature name='pse36'/>
|
<feature name='pse36'/>
|
||||||
<feature name='vme'/>
|
<feature name='vme'/>
|
||||||
<feature name='mtrr'/>
|
<feature name='mtrr'/>
|
||||||
|
@ -35,8 +35,18 @@
|
|||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_CPU
|
#define VIR_FROM_THIS VIR_FROM_CPU
|
||||||
|
|
||||||
|
#define VENDOR_STRING_LENGTH 12
|
||||||
|
|
||||||
|
|
||||||
static const char *archs[] = { "i686", "x86_64" };
|
static const char *archs[] = { "i686", "x86_64" };
|
||||||
|
|
||||||
|
struct x86_vendor {
|
||||||
|
char *name;
|
||||||
|
struct cpuX86cpuid cpuid;
|
||||||
|
|
||||||
|
struct x86_vendor *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct x86_feature {
|
struct x86_feature {
|
||||||
char *name;
|
char *name;
|
||||||
unsigned int ncpuid;
|
unsigned int ncpuid;
|
||||||
@ -47,6 +57,7 @@ struct x86_feature {
|
|||||||
|
|
||||||
struct x86_model {
|
struct x86_model {
|
||||||
char *name;
|
char *name;
|
||||||
|
const struct x86_vendor *vendor;
|
||||||
unsigned int ncpuid;
|
unsigned int ncpuid;
|
||||||
struct cpuX86cpuid *cpuid;
|
struct cpuX86cpuid *cpuid;
|
||||||
|
|
||||||
@ -54,6 +65,7 @@ struct x86_model {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct x86_map {
|
struct x86_map {
|
||||||
|
struct x86_vendor *vendors;
|
||||||
struct x86_feature *features;
|
struct x86_feature *features;
|
||||||
struct x86_model *models;
|
struct x86_model *models;
|
||||||
};
|
};
|
||||||
@ -212,6 +224,44 @@ x86DataCopy(const union cpuData *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
x86DataAddCpuid(union cpuData *data,
|
||||||
|
const struct cpuX86cpuid *cpuid)
|
||||||
|
{
|
||||||
|
struct cpuX86cpuid **cpuids;
|
||||||
|
int *len;
|
||||||
|
unsigned int pos;
|
||||||
|
unsigned int ext;
|
||||||
|
|
||||||
|
if (cpuid->function < CPUX86_EXTENDED) {
|
||||||
|
pos = cpuid->function;
|
||||||
|
ext = 0;
|
||||||
|
len = &data->x86.basic_len;
|
||||||
|
cpuids = &data->x86.basic;
|
||||||
|
} else {
|
||||||
|
pos = cpuid->function - CPUX86_EXTENDED;
|
||||||
|
ext = CPUX86_EXTENDED;
|
||||||
|
len = &data->x86.extended_len;
|
||||||
|
cpuids = &data->x86.extended;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos >= *len) {
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (VIR_ALLOC_N(*cpuids, pos + 1) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = *len; i <= pos; i++)
|
||||||
|
(*cpuids)[i].function = i + ext;
|
||||||
|
*len = pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86cpuidSetBits((*cpuids) + pos, cpuid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
x86DataSubtract(union cpuData *data1,
|
x86DataSubtract(union cpuData *data1,
|
||||||
const union cpuData *data2)
|
const union cpuData *data2)
|
||||||
@ -318,6 +368,27 @@ x86DataToCPUFeatures(virCPUDefPtr cpu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* also removes bits corresponding to vendor string from data */
|
||||||
|
static const struct x86_vendor *
|
||||||
|
x86DataToVendor(union cpuData *data,
|
||||||
|
const struct x86_map *map)
|
||||||
|
{
|
||||||
|
const struct x86_vendor *vendor = map->vendors;
|
||||||
|
struct cpuX86cpuid *cpuid;
|
||||||
|
|
||||||
|
while (vendor) {
|
||||||
|
if ((cpuid = x86DataCpuid(data, vendor->cpuid.function)) &&
|
||||||
|
x86cpuidMatchMasked(cpuid, &vendor->cpuid)) {
|
||||||
|
x86cpuidClearBits(cpuid, &vendor->cpuid);
|
||||||
|
return vendor;
|
||||||
|
}
|
||||||
|
vendor = vendor->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static virCPUDefPtr
|
static virCPUDefPtr
|
||||||
x86DataToCPU(const union cpuData *data,
|
x86DataToCPU(const union cpuData *data,
|
||||||
const struct x86_model *model,
|
const struct x86_model *model,
|
||||||
@ -326,6 +397,7 @@ x86DataToCPU(const union cpuData *data,
|
|||||||
virCPUDefPtr cpu;
|
virCPUDefPtr cpu;
|
||||||
union cpuData *copy = NULL;
|
union cpuData *copy = NULL;
|
||||||
union cpuData *modelData = NULL;
|
union cpuData *modelData = NULL;
|
||||||
|
const struct x86_vendor *vendor;
|
||||||
|
|
||||||
if (VIR_ALLOC(cpu) < 0 ||
|
if (VIR_ALLOC(cpu) < 0 ||
|
||||||
!(cpu->model = strdup(model->name)) ||
|
!(cpu->model = strdup(model->name)) ||
|
||||||
@ -333,6 +405,10 @@ x86DataToCPU(const union cpuData *data,
|
|||||||
!(modelData = x86DataFromModel(model)))
|
!(modelData = x86DataFromModel(model)))
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
|
|
||||||
|
if ((vendor = x86DataToVendor(copy, map)) &&
|
||||||
|
!(cpu->vendor = strdup(vendor->name)))
|
||||||
|
goto no_memory;
|
||||||
|
|
||||||
x86DataSubtract(copy, modelData);
|
x86DataSubtract(copy, modelData);
|
||||||
x86DataSubtract(modelData, data);
|
x86DataSubtract(modelData, data);
|
||||||
|
|
||||||
@ -357,6 +433,106 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
x86VendorFree(struct x86_vendor *vendor)
|
||||||
|
{
|
||||||
|
if (!vendor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VIR_FREE(vendor->name);
|
||||||
|
VIR_FREE(vendor);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct x86_vendor *
|
||||||
|
x86VendorFind(const struct x86_map *map,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct x86_vendor *vendor;
|
||||||
|
|
||||||
|
vendor = map->vendors;
|
||||||
|
while (vendor) {
|
||||||
|
if (STREQ(vendor->name, name))
|
||||||
|
return vendor;
|
||||||
|
|
||||||
|
vendor = vendor->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
x86VendorLoad(xmlXPathContextPtr ctxt,
|
||||||
|
struct x86_map *map)
|
||||||
|
{
|
||||||
|
struct x86_vendor *vendor = NULL;
|
||||||
|
char *string = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(vendor) < 0)
|
||||||
|
goto no_memory;
|
||||||
|
|
||||||
|
vendor->name = virXPathString("string(@name)", ctxt);
|
||||||
|
if (!vendor->name) {
|
||||||
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("Missing CPU vendor name"));
|
||||||
|
goto ignore;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x86VendorFind(map, vendor->name)) {
|
||||||
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("CPU vendor %s already defined"), vendor->name);
|
||||||
|
goto ignore;
|
||||||
|
}
|
||||||
|
|
||||||
|
string = virXPathString("string(@string)", ctxt);
|
||||||
|
if (!string) {
|
||||||
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Missing vendor string for CPU vendor %s"), vendor->name);
|
||||||
|
goto ignore;
|
||||||
|
}
|
||||||
|
if (strlen(string) != VENDOR_STRING_LENGTH) {
|
||||||
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Invalid CPU vendor string '%s'"), string);
|
||||||
|
goto ignore;
|
||||||
|
}
|
||||||
|
|
||||||
|
vendor->cpuid.function = 0;
|
||||||
|
vendor->cpuid.ebx = (string[0] ) |
|
||||||
|
(string[1] << 8) |
|
||||||
|
(string[2] << 16) |
|
||||||
|
(string[3] << 24);
|
||||||
|
vendor->cpuid.edx = (string[4] ) |
|
||||||
|
(string[5] << 8) |
|
||||||
|
(string[6] << 16) |
|
||||||
|
(string[7] << 24);
|
||||||
|
vendor->cpuid.ecx = (string[8] ) |
|
||||||
|
(string[9] << 8) |
|
||||||
|
(string[10] << 16) |
|
||||||
|
(string[11] << 24);
|
||||||
|
|
||||||
|
if (!map->vendors)
|
||||||
|
map->vendors = vendor;
|
||||||
|
else {
|
||||||
|
vendor->next = map->vendors;
|
||||||
|
map->vendors = vendor;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
VIR_FREE(string);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
no_memory:
|
||||||
|
virReportOOMError();
|
||||||
|
ret = -1;
|
||||||
|
ignore:
|
||||||
|
x86VendorFree(vendor);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
x86FeatureFree(struct x86_feature *feature)
|
x86FeatureFree(struct x86_feature *feature)
|
||||||
{
|
{
|
||||||
@ -389,9 +565,8 @@ x86FeatureFind(const struct x86_map *map,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
x86FeatureLoad(xmlXPathContextPtr ctxt,
|
x86FeatureLoad(xmlXPathContextPtr ctxt,
|
||||||
void *data)
|
struct x86_map *map)
|
||||||
{
|
{
|
||||||
struct x86_map *map = data;
|
|
||||||
xmlNodePtr *nodes = NULL;
|
xmlNodePtr *nodes = NULL;
|
||||||
xmlNodePtr ctxt_node = ctxt->node;
|
xmlNodePtr ctxt_node = ctxt->node;
|
||||||
struct x86_feature *feature = NULL;
|
struct x86_feature *feature = NULL;
|
||||||
@ -500,6 +675,7 @@ x86ModelCopy(const struct x86_model *model)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy->vendor = model->vendor;
|
||||||
copy->ncpuid = model->ncpuid;
|
copy->ncpuid = model->ncpuid;
|
||||||
for (i = 0; i < model->ncpuid; i++)
|
for (i = 0; i < model->ncpuid; i++)
|
||||||
copy->cpuid[i] = model->cpuid[i];
|
copy->cpuid[i] = model->cpuid[i];
|
||||||
@ -788,11 +964,11 @@ x86ModelCompare(const struct x86_model *model1,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
x86ModelLoad(xmlXPathContextPtr ctxt,
|
x86ModelLoad(xmlXPathContextPtr ctxt,
|
||||||
void *data)
|
struct x86_map *map)
|
||||||
{
|
{
|
||||||
struct x86_map *map = data;
|
|
||||||
xmlNodePtr *nodes = NULL;
|
xmlNodePtr *nodes = NULL;
|
||||||
struct x86_model *model = NULL;
|
struct x86_model *model = NULL;
|
||||||
|
char *vendor = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i;
|
int i;
|
||||||
int n;
|
int n;
|
||||||
@ -832,11 +1008,22 @@ x86ModelLoad(xmlXPathContextPtr ctxt,
|
|||||||
if (VIR_ALLOC_N(model->cpuid, ancestor->ncpuid) < 0)
|
if (VIR_ALLOC_N(model->cpuid, ancestor->ncpuid) < 0)
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
|
|
||||||
|
model->vendor = ancestor->vendor;
|
||||||
model->ncpuid = ancestor->ncpuid;
|
model->ncpuid = ancestor->ncpuid;
|
||||||
memcpy(model->cpuid, ancestor->cpuid,
|
memcpy(model->cpuid, ancestor->cpuid,
|
||||||
sizeof(*model->cpuid) * model->ncpuid);
|
sizeof(*model->cpuid) * model->ncpuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vendor = virXPathString("string(./vendor/@name)", ctxt);
|
||||||
|
if (vendor) {
|
||||||
|
if (!(model->vendor = x86VendorFind(map, vendor))) {
|
||||||
|
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Unknown vendor %s referenced by CPU model %s"),
|
||||||
|
vendor, model->name);
|
||||||
|
goto ignore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
n = virXPathNodeSet("./feature", ctxt, &nodes);
|
n = virXPathNodeSet("./feature", ctxt, &nodes);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
goto ignore;
|
goto ignore;
|
||||||
@ -872,6 +1059,7 @@ x86ModelLoad(xmlXPathContextPtr ctxt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
VIR_FREE(vendor);
|
||||||
VIR_FREE(nodes);
|
VIR_FREE(nodes);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -907,6 +1095,28 @@ x86MapFree(struct x86_map *map)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
x86MapLoadCallback(enum cpuMapElement element,
|
||||||
|
xmlXPathContextPtr ctxt,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct x86_map *map = data;
|
||||||
|
|
||||||
|
switch (element) {
|
||||||
|
case CPU_MAP_ELEMENT_VENDOR:
|
||||||
|
return x86VendorLoad(ctxt, map);
|
||||||
|
case CPU_MAP_ELEMENT_FEATURE:
|
||||||
|
return x86FeatureLoad(ctxt, map);
|
||||||
|
case CPU_MAP_ELEMENT_MODEL:
|
||||||
|
return x86ModelLoad(ctxt, map);
|
||||||
|
case CPU_MAP_ELEMENT_LAST:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct x86_map *
|
static struct x86_map *
|
||||||
x86LoadMap(void)
|
x86LoadMap(void)
|
||||||
{
|
{
|
||||||
@ -917,9 +1127,7 @@ x86LoadMap(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpuMapLoad("x86",
|
if (cpuMapLoad("x86", x86MapLoadCallback, map) < 0)
|
||||||
x86FeatureLoad, map,
|
|
||||||
x86ModelLoad, map) < 0)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
@ -965,6 +1173,13 @@ x86Compute(virCPUDefPtr host,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cpu->vendor &&
|
||||||
|
(!host->vendor || STRNEQ(cpu->vendor, host->vendor))) {
|
||||||
|
VIR_DEBUG("host CPU vendor does not match required CPU vendor %s",
|
||||||
|
cpu->vendor);
|
||||||
|
return VIR_CPU_COMPARE_INCOMPATIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(map = x86LoadMap()) ||
|
if (!(map = x86LoadMap()) ||
|
||||||
!(host_model = x86ModelFromCPU(host, map, 0)) ||
|
!(host_model = x86ModelFromCPU(host, map, 0)) ||
|
||||||
!(cpu_force = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_FORCE)) ||
|
!(cpu_force = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_FORCE)) ||
|
||||||
@ -1117,6 +1332,15 @@ x86Decode(virCPUDefPtr cpu,
|
|||||||
if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
|
if (!(cpuCandidate = x86DataToCPU(data, candidate, map)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (candidate->vendor && cpuCandidate->vendor &&
|
||||||
|
STRNEQ(candidate->vendor->name, cpuCandidate->vendor)) {
|
||||||
|
VIR_DEBUG("CPU vendor %s of model %s differs from %s; ignoring",
|
||||||
|
candidate->vendor->name, candidate->name,
|
||||||
|
cpuCandidate->vendor);
|
||||||
|
virCPUDefFree(cpuCandidate);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
if (cpu->type == VIR_CPU_TYPE_HOST) {
|
if (cpu->type == VIR_CPU_TYPE_HOST) {
|
||||||
cpuCandidate->type = VIR_CPU_TYPE_HOST;
|
cpuCandidate->type = VIR_CPU_TYPE_HOST;
|
||||||
for (i = 0; i < cpuCandidate->nfeatures; i++) {
|
for (i = 0; i < cpuCandidate->nfeatures; i++) {
|
||||||
@ -1154,6 +1378,7 @@ x86Decode(virCPUDefPtr cpu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cpu->model = cpuModel->model;
|
cpu->model = cpuModel->model;
|
||||||
|
cpu->vendor = cpuModel->vendor;
|
||||||
cpu->nfeatures = cpuModel->nfeatures;
|
cpu->nfeatures = cpuModel->nfeatures;
|
||||||
cpu->features = cpuModel->features;
|
cpu->features = cpuModel->features;
|
||||||
VIR_FREE(cpuModel);
|
VIR_FREE(cpuModel);
|
||||||
@ -1194,7 +1419,8 @@ x86Encode(const virCPUDefPtr cpu,
|
|||||||
union cpuData **required,
|
union cpuData **required,
|
||||||
union cpuData **optional,
|
union cpuData **optional,
|
||||||
union cpuData **disabled,
|
union cpuData **disabled,
|
||||||
union cpuData **forbidden)
|
union cpuData **forbidden,
|
||||||
|
union cpuData **vendor)
|
||||||
{
|
{
|
||||||
struct x86_map *map = NULL;
|
struct x86_map *map = NULL;
|
||||||
union cpuData *data_forced = NULL;
|
union cpuData *data_forced = NULL;
|
||||||
@ -1202,6 +1428,7 @@ x86Encode(const virCPUDefPtr cpu,
|
|||||||
union cpuData *data_optional = NULL;
|
union cpuData *data_optional = NULL;
|
||||||
union cpuData *data_disabled = NULL;
|
union cpuData *data_disabled = NULL;
|
||||||
union cpuData *data_forbidden = NULL;
|
union cpuData *data_forbidden = NULL;
|
||||||
|
union cpuData *data_vendor = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if ((map = x86LoadMap()) == NULL)
|
if ((map = x86LoadMap()) == NULL)
|
||||||
@ -1237,6 +1464,23 @@ x86Encode(const virCPUDefPtr cpu,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vendor) {
|
||||||
|
const struct x86_vendor *v = NULL;
|
||||||
|
|
||||||
|
if (cpu->vendor && !(v = x86VendorFind(map, cpu->vendor))) {
|
||||||
|
virCPUReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
|
_("CPU vendor %s not found"), cpu->vendor);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v &&
|
||||||
|
(VIR_ALLOC(data_vendor) < 0 ||
|
||||||
|
x86DataAddCpuid(data_vendor, &v->cpuid) < 0)) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (forced)
|
if (forced)
|
||||||
*forced = data_forced;
|
*forced = data_forced;
|
||||||
if (required)
|
if (required)
|
||||||
@ -1247,6 +1491,8 @@ x86Encode(const virCPUDefPtr cpu,
|
|||||||
*disabled = data_disabled;
|
*disabled = data_disabled;
|
||||||
if (forbidden)
|
if (forbidden)
|
||||||
*forbidden = data_forbidden;
|
*forbidden = data_forbidden;
|
||||||
|
if (vendor)
|
||||||
|
*vendor = data_vendor;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
@ -1261,6 +1507,7 @@ error:
|
|||||||
x86DataFree(data_optional);
|
x86DataFree(data_optional);
|
||||||
x86DataFree(data_disabled);
|
x86DataFree(data_disabled);
|
||||||
x86DataFree(data_forbidden);
|
x86DataFree(data_forbidden);
|
||||||
|
x86DataFree(data_vendor);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1358,6 +1605,8 @@ x86Baseline(virCPUDefPtr *cpus,
|
|||||||
union cpuData *data = NULL;
|
union cpuData *data = NULL;
|
||||||
virCPUDefPtr cpu = NULL;
|
virCPUDefPtr cpu = NULL;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
const struct x86_vendor *vendor = NULL;
|
||||||
|
struct x86_model *model = NULL;
|
||||||
|
|
||||||
if (!(map = x86LoadMap()))
|
if (!(map = x86LoadMap()))
|
||||||
goto error;
|
goto error;
|
||||||
@ -1371,13 +1620,49 @@ x86Baseline(virCPUDefPtr *cpus,
|
|||||||
cpu->type = VIR_CPU_TYPE_GUEST;
|
cpu->type = VIR_CPU_TYPE_GUEST;
|
||||||
cpu->match = VIR_CPU_MATCH_EXACT;
|
cpu->match = VIR_CPU_MATCH_EXACT;
|
||||||
|
|
||||||
|
if (cpus[0]->vendor &&
|
||||||
|
!(vendor = x86VendorFind(map, cpus[0]->vendor))) {
|
||||||
|
virCPUReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
|
_("Unknown CPU vendor %s"), cpus[0]->vendor);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 1; i < ncpus; i++) {
|
for (i = 1; i < ncpus; i++) {
|
||||||
struct x86_model *model;
|
const char *vn = NULL;
|
||||||
|
|
||||||
if (!(model = x86ModelFromCPU(cpus[i], map, 0)))
|
if (!(model = x86ModelFromCPU(cpus[i], map, 0)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
if (cpus[i]->vendor && model->vendor &&
|
||||||
|
STRNEQ(cpus[i]->vendor, model->vendor->name)) {
|
||||||
|
virCPUReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
|
_("CPU vendor %s of model %s differs from vendor %s"),
|
||||||
|
model->vendor->name, model->name, cpus[i]->vendor);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpus[i]->vendor)
|
||||||
|
vn = cpus[i]->vendor;
|
||||||
|
else if (model->vendor)
|
||||||
|
vn = model->vendor->name;
|
||||||
|
|
||||||
|
if (vn) {
|
||||||
|
if (!vendor) {
|
||||||
|
if (!(vendor = x86VendorFind(map, vn))) {
|
||||||
|
virCPUReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
|
_("Unknown CPU vendor %s"), vn);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else if (STRNEQ(vendor->name, vn)) {
|
||||||
|
virCPUReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
|
"%s", _("CPU vendors do not match"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
x86ModelIntersect(base_model, model);
|
x86ModelIntersect(base_model, model);
|
||||||
x86ModelFree(model);
|
x86ModelFree(model);
|
||||||
|
model = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(data = x86DataFromModel(base_model)))
|
if (!(data = x86DataFromModel(base_model)))
|
||||||
@ -1389,6 +1674,9 @@ x86Baseline(virCPUDefPtr *cpus,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vendor && x86DataAddCpuid(data, &vendor->cpuid) < 0)
|
||||||
|
goto no_memory;
|
||||||
|
|
||||||
if (x86Decode(cpu, data, models, nmodels, NULL) < 0)
|
if (x86Decode(cpu, data, models, nmodels, NULL) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -1404,6 +1692,7 @@ cleanup:
|
|||||||
no_memory:
|
no_memory:
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
error:
|
error:
|
||||||
|
x86ModelFree(model);
|
||||||
virCPUDefFree(cpu);
|
virCPUDefFree(cpu);
|
||||||
cpu = NULL;
|
cpu = NULL;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -83,6 +83,7 @@ virCapsPtr testQemuCapsInit(void) {
|
|||||||
0, /* match */
|
0, /* match */
|
||||||
(char *) "x86_64", /* arch */
|
(char *) "x86_64", /* arch */
|
||||||
(char *) "core2duo", /* model */
|
(char *) "core2duo", /* model */
|
||||||
|
(char *) "Intel", /* vendor */
|
||||||
1, /* sockets */
|
1, /* sockets */
|
||||||
2, /* cores */
|
2, /* cores */
|
||||||
1, /* threads */
|
1, /* threads */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user