<loader/> element.</dd>
</dl>
+ <h3><a name="elementsCPU">CPU configuration</a></h3>
+
+ <p>
+ The <code>cpu</code> element exposes options usable for configuring
+ <a href="formatdomain.html#elementsCPU">guest CPUs</a>.
+ </p>
+
+<pre>
+<domainCapabilities>
+ ...
+ <cpu>
+ <mode name='host-passthrough' supported='yes'/>
+ <mode name='host-model' supported='yes'/>
+ <mode name='custom' supported='yes'>
+ <model>Broadwell</model>
+ <model>Broadwell-noTSX</model>
+ <model>Haswell</model>
+ ...
+ </mode>
+ </cpu>
+ ...
+<domainCapabilities>
+</pre>
+
+ <p>
+ Each CPU mode understood by libvirt is described with a
+ <code>mode</code> element which tells whether the particular mode
+ is supported and provides (when applicable) more details about it:
+ </p>
+
+ <dl>
+ <dt><code>host-passthrough</code></dt>
+ <dd>No mode specific details are provided.</dd>
+
+ <dt><code>host-model</code></dt>
+ <dd>No mode specific details are provided yet.</dd>
+
+ <dt><code>custom</code></dt>
+ <dd>
+ The <code>mode</code> element contains a list of supported CPU
+ models, each described by a dedicated <code>model</code> element.
+ </dd>
+ </dl>
+
<h3><a name="elementsDevices">Devices</a></h3>
<p>
<optional>
<ref name='os'/>
</optional>
+ <optional>
+ <ref name='cpu'/>
+ </optional>
<optional>
<ref name='devices'/>
</optional>
</element>
</define>
+ <define name='cpu'>
+ <element name='cpu'>
+ <ref name='cpuHost'/>
+ <ref name='cpuHostModel'/>
+ <ref name='cpuCustom'/>
+ </element>
+ </define>
+
+ <define name='cpuHost'>
+ <element name='mode'>
+ <attribute name='name'>
+ <value>host-passthrough</value>
+ </attribute>
+ <ref name='supported'/>
+ </element>
+ </define>
+
+ <define name='cpuHostModel'>
+ <element name='mode'>
+ <attribute name='name'>
+ <value>host-model</value>
+ </attribute>
+ <ref name='supported'/>
+ </element>
+ </define>
+
+ <define name='cpuCustom'>
+ <element name='mode'>
+ <attribute name='name'>
+ <value>custom</value>
+ </attribute>
+ <ref name='supported'/>
+ <zeroOrMore>
+ <element name='model'>
+ <text/>
+ </element>
+ </zeroOrMore>
+ </element>
+ </define>
+
<define name='devices'>
<element name='devices'>
<interleave>
#define VIR_FROM_THIS VIR_FROM_CAPABILITIES
static virClassPtr virDomainCapsClass;
+static virClassPtr virDomainCapsCPUModelsClass;
static void virDomainCapsDispose(void *obj);
+static void virDomainCapsCPUModelsDispose(void *obj);
static int virDomainCapsOnceInit(void)
{
sizeof(virDomainCaps),
virDomainCapsDispose)))
return -1;
+
+ virDomainCapsCPUModelsClass = virClassNew(virClassForObject(),
+ "virDomainCapsCPUModelsClass",
+ sizeof(virDomainCapsCPUModels),
+ virDomainCapsCPUModelsDispose);
+ if (!virDomainCapsCPUModelsClass)
+ return -1;
+
return 0;
}
VIR_FREE(caps->path);
VIR_FREE(caps->machine);
+ virObjectUnref(caps->cpu.custom);
virDomainCapsStringValuesFree(&caps->os.loader.values);
}
+static void
+virDomainCapsCPUModelsDispose(void *obj)
+{
+ virDomainCapsCPUModelsPtr cpuModels = obj;
+ size_t i;
+
+ for (i = 0; i < cpuModels->nmodels; i++)
+ VIR_FREE(cpuModels->models[i].name);
+
+ VIR_FREE(cpuModels->models);
+}
+
+
virDomainCapsPtr
virDomainCapsNew(const char *path,
const char *machine,
}
+virDomainCapsCPUModelsPtr
+virDomainCapsCPUModelsNew(size_t nmodels)
+{
+ virDomainCapsCPUModelsPtr cpuModels = NULL;
+
+ if (virDomainCapsInitialize() < 0)
+ return NULL;
+
+ if (!(cpuModels = virObjectNew(virDomainCapsCPUModelsClass)))
+ return NULL;
+
+ if (VIR_ALLOC_N(cpuModels->models, nmodels) < 0)
+ goto error;
+ cpuModels->nmodels_max = nmodels;
+
+ return cpuModels;
+
+ error:
+ virObjectUnref(cpuModels);
+ return NULL;
+}
+
+
+virDomainCapsCPUModelsPtr
+virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old)
+{
+ virDomainCapsCPUModelsPtr cpuModels;
+ size_t i;
+
+ if (!(cpuModels = virDomainCapsCPUModelsNew(old->nmodels)))
+ return NULL;
+
+ for (i = 0; i < old->nmodels; i++) {
+ if (virDomainCapsCPUModelsAdd(cpuModels, old->models[i].name, -1) < 0)
+ goto error;
+ }
+
+ return cpuModels;
+
+ error:
+ virObjectUnref(cpuModels);
+ return NULL;
+}
+
+
+int
+virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels,
+ char **name)
+{
+ if (VIR_RESIZE_N(cpuModels->models, cpuModels->nmodels_max,
+ cpuModels->nmodels, 1) < 0)
+ return -1;
+
+ VIR_STEAL_PTR(cpuModels->models[cpuModels->nmodels++].name, *name);
+ return 0;
+}
+
+
+int
+virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels,
+ const char *name,
+ ssize_t nameLen)
+{
+ char *copy = NULL;
+
+ if (VIR_STRNDUP(copy, name, nameLen) < 0)
+ goto error;
+
+ if (virDomainCapsCPUModelsAddSteal(cpuModels, ©) < 0)
+ goto error;
+
+ return 0;
+
+ error:
+ VIR_FREE(copy);
+ return -1;
+}
+
+
int
virDomainCapsEnumSet(virDomainCapsEnumPtr capsEnum,
const char *capsEnumName,
FORMAT_EPILOGUE(os);
}
+static void
+virDomainCapsCPUCustomFormat(virBufferPtr buf,
+ virDomainCapsCPUModelsPtr custom)
+{
+ size_t i;
+
+ virBufferAdjustIndent(buf, 2);
+
+ for (i = 0; i < custom->nmodels; i++) {
+ virBufferAsprintf(buf, "<model>%s</model>\n",
+ custom->models[i].name);
+ }
+
+ virBufferAdjustIndent(buf, -2);
+}
+
+static void
+virDomainCapsCPUFormat(virBufferPtr buf,
+ virDomainCapsCPUPtr cpu)
+{
+ virBufferAddLit(buf, "<cpu>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferAsprintf(buf, "<mode name='%s' supported='%s'/>\n",
+ virCPUModeTypeToString(VIR_CPU_MODE_HOST_PASSTHROUGH),
+ cpu->hostPassthrough ? "yes" : "no");
+
+ virBufferAsprintf(buf, "<mode name='%s' supported='%s'/>\n",
+ virCPUModeTypeToString(VIR_CPU_MODE_HOST_MODEL),
+ cpu->hostModel ? "yes" : "no");
+
+ virBufferAsprintf(buf, "<mode name='%s' ",
+ virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM));
+ if (cpu->custom && cpu->custom->nmodels) {
+ virBufferAddLit(buf, "supported='yes'>\n");
+ virDomainCapsCPUCustomFormat(buf, cpu->custom);
+ virBufferAddLit(buf, "</mode>\n");
+ } else {
+ virBufferAddLit(buf, "supported='no'/>\n");
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</cpu>\n");
+}
+
static void
virDomainCapsDeviceDiskFormat(virBufferPtr buf,
virDomainCapsDeviceDiskPtr const disk)
virBufferAsprintf(buf, "<vcpu max='%d'/>\n", caps->maxvcpus);
virDomainCapsOSFormat(buf, &caps->os);
+ virDomainCapsCPUFormat(buf, &caps->cpu);
virBufferAddLit(buf, "<devices>\n");
virBufferAdjustIndent(buf, 2);
virDomainCapsEnum version; /* Info about virGICVersion */
};
+typedef struct _virDomainCapsCPUModel virDomainCapsCPUModel;
+typedef virDomainCapsCPUModel *virDomainCapsCPUModelPtr;
+struct _virDomainCapsCPUModel {
+ char *name;
+};
+
+typedef struct _virDomainCapsCPUModels virDomainCapsCPUModels;
+typedef virDomainCapsCPUModels *virDomainCapsCPUModelsPtr;
+struct _virDomainCapsCPUModels {
+ virObject parent;
+
+ size_t nmodels_max;
+ size_t nmodels;
+ virDomainCapsCPUModelPtr models;
+};
+
+typedef struct _virDomainCapsCPU virDomainCapsCPU;
+typedef virDomainCapsCPU *virDomainCapsCPUPtr;
+struct _virDomainCapsCPU {
+ bool hostPassthrough;
+ bool hostModel;
+ virDomainCapsCPUModelsPtr custom;
+};
+
struct _virDomainCaps {
virObjectLockable parent;
int maxvcpus;
virDomainCapsOS os;
+ virDomainCapsCPU cpu;
virDomainCapsDeviceDisk disk;
virDomainCapsDeviceGraphics graphics;
virDomainCapsDeviceVideo video;
virArch arch,
virDomainVirtType virttype);
+virDomainCapsCPUModelsPtr virDomainCapsCPUModelsNew(size_t nmodels);
+virDomainCapsCPUModelsPtr virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old);
+int virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels,
+ char **name);
+int virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels,
+ const char *name,
+ ssize_t nameLen);
+
# define VIR_DOMAIN_CAPS_ENUM_SET(capsEnum, ...) \
do { \
unsigned int __values[] = {__VA_ARGS__}; \
# conf/domain_capabilities.h
+virDomainCapsCPUModelsAdd;
+virDomainCapsCPUModelsAddSteal;
+virDomainCapsCPUModelsCopy;
+virDomainCapsCPUModelsNew;
virDomainCapsEnumClear;
virDomainCapsEnumSet;
virDomainCapsFormat;
<machine>my-machine-type</machine>
<arch>x86_64</arch>
<os supported='no'/>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='no'/>
<graphics supported='no'/>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='yes'/>
+ <mode name='host-model' supported='yes'/>
+ <mode name='custom' supported='yes'>
+ <model>Model1</model>
+ <model>Model2</model>
+ <model>Model3</model>
+ </mode>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
<os supported='yes'>
<loader supported='no'/>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
<os supported='yes'>
<loader supported='no'/>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
</enum>
</loader>
</os>
+ <cpu>
+ <mode name='host-passthrough' supported='no'/>
+ <mode name='host-model' supported='no'/>
+ <mode name='custom' supported='no'/>
+ </cpu>
<devices>
<disk supported='yes'>
<enum name='diskDevice'>
{
virDomainCapsOSPtr os = &domCaps->os;
virDomainCapsLoaderPtr loader = &os->loader;
+ virDomainCapsCPUPtr cpu = &domCaps->cpu;
virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
virDomainCapsDeviceGraphicsPtr graphics = &domCaps->graphics;
virDomainCapsDeviceVideoPtr video = &domCaps->video;
NULL) < 0)
return -1;
+ cpu->hostPassthrough = true;
+ cpu->hostModel = true;
+ if (!(cpu->custom = virDomainCapsCPUModelsNew(3)) ||
+ virDomainCapsCPUModelsAdd(cpu->custom, "Model1", -1) < 0 ||
+ virDomainCapsCPUModelsAdd(cpu->custom, "Model2", -1) < 0 ||
+ virDomainCapsCPUModelsAdd(cpu->custom, "Model3", -1) < 0)
+ return -1;
+
disk->supported = true;
SET_ALL_BITS(disk->diskDevice);
SET_ALL_BITS(disk->bus);