diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index e31a271a5824763c5bd95cdb75c92f1537596af6..03961fb4bad8859faca094f36946ed82b9655b2d 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1198,6 +1198,7 @@
<model fallback='allow'>core2duo</model>
<vendor>Intel</vendor>
<topology sockets='1' cores='2' threads='1'/>
+ <cache level='3' mode='emulate'/>
<feature policy='disable' name='lahf_lm'/>
</cpu>
...
@@ -1211,6 +1212,7 @@
<cpu mode='host-passthrough'>
+ <cache mode='passthrough'/>
<feature policy='disable' name='lahf_lm'/>
...
@@ -1434,6 +1436,39 @@
Since 0.8.5 the policy
attribute can be omitted and will default to require
.
+
+ cache
+ Since 3.3.0 the cache
+ element describes the virtual CPU cache. If the element is missing,
+ the hypervisor will use a sensible default.
+
+
+ level
+ - This optional attribute specifies which cache level is described
+ by the element. Missing attribute means the element describes all
+ CPU cache levels at once. Mixing
cache
elements with
+ the level
attribute set and those without the
+ attribute is forbidden.
+
+ mode
+ -
+ The following values are supported:
+
+ emulate
+ - The hypervisor will provide a fake CPU cache data.
+
+ passthrough
+ - The real CPU cache data reported by the host CPU will be
+ passed through to the virtual CPU.
+
+ disable
+ - The virtual CPU will report no CPU cache of the specified
+ level (or no cache at all if the
level
attribute
+ is missing).
+
+
+
+
diff --git a/docs/schemas/cputypes.rng b/docs/schemas/cputypes.rng
index 8189114e3c3032711e53aec2e1628790e71b31a7..3eef16abce1eb4d75b1a21463dfce42ec1790c4d 100644
--- a/docs/schemas/cputypes.rng
+++ b/docs/schemas/cputypes.rng
@@ -142,4 +142,25 @@
+
+
+
+
+
+ 1
+ 2
+ 3
+
+
+
+
+
+ emulate
+ passthrough
+ disable
+
+
+
+
+
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index eb4b0f7437babbc7f06c80f93effb57218c2e7d1..7a9b4b70241bcea97104e42a4a19b0d0649af4fe 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4548,6 +4548,9 @@
+
+
+
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 623b1699fd6e699e7c33541d60cb6cea3ffb573d..1b098c47662f48037dab7655bf582279090eabf9 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -62,6 +62,12 @@ VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST,
"disable",
"forbid")
+VIR_ENUM_IMPL(virCPUCacheMode, VIR_CPU_CACHE_MODE_LAST,
+ "emulate",
+ "passthrough",
+ "disable")
+
+
void
virCPUDefFreeFeatures(virCPUDefPtr def)
{
@@ -92,6 +98,7 @@ virCPUDefFree(virCPUDefPtr def)
return;
virCPUDefFreeModel(def);
+ VIR_FREE(def->cache);
VIR_FREE(def);
}
@@ -204,7 +211,18 @@ virCPUDefCopyWithoutModel(const virCPUDef *cpu)
copy->threads = cpu->threads;
copy->arch = cpu->arch;
+ if (cpu->cache) {
+ if (VIR_ALLOC(copy->cache) < 0)
+ goto error;
+
+ *copy->cache = *cpu->cache;
+ }
+
return copy;
+
+ error:
+ virCPUDefFree(copy);
+ return NULL;
}
@@ -489,6 +507,41 @@ virCPUDefParseXML(xmlNodePtr node,
def->features[i].policy = policy;
}
+ if (virXPathInt("count(./cache)", ctxt, &n) < 0) {
+ goto cleanup;
+ } else if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("at most one CPU cache element may be specified"));
+ goto cleanup;
+ } else if (n == 1) {
+ int level = -1;
+ char *strmode;
+ int mode;
+
+ if (virXPathBoolean("boolean(./cache[1]/@level)", ctxt) == 1 &&
+ (virXPathInt("string(./cache[1]/@level)", ctxt, &level) < 0 ||
+ level < 1 || level > 3)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid CPU cache level, must be in range [1,3]"));
+ goto cleanup;
+ }
+
+ if (!(strmode = virXPathString("string(./cache[1]/@mode)", ctxt)) ||
+ (mode = virCPUCacheModeTypeFromString(strmode)) < 0) {
+ VIR_FREE(strmode);
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing or invalid CPU cache mode"));
+ goto cleanup;
+ }
+ VIR_FREE(strmode);
+
+ if (VIR_ALLOC(def->cache) < 0)
+ goto cleanup;
+
+ def->cache->level = level;
+ def->cache->mode = mode;
+ }
+
cleanup:
ctxt->node = oldnode;
VIR_FREE(fallback);
@@ -662,6 +715,15 @@ virCPUDefFormatBuf(virBufferPtr buf,
virBufferAddLit(buf, "/>\n");
}
+ if (def->cache) {
+ virBufferAddLit(buf, "cache->level != -1)
+ virBufferAsprintf(buf, "level='%d' ", def->cache->level);
+ virBufferAsprintf(buf, "mode='%s'",
+ virCPUCacheModeTypeToString(def->cache->mode));
+ virBufferAddLit(buf, "/>\n");
+ }
+
for (i = 0; i < def->nfeatures; i++) {
virCPUFeatureDefPtr feature = def->features + i;
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index 3e02deed4bc595778a491e952ed001e5eed1497a..09438b68b479032730e3bbabe859dbcd4a236d87 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -103,6 +103,24 @@ struct _virCPUFeatureDef {
};
+typedef enum {
+ VIR_CPU_CACHE_MODE_EMULATE,
+ VIR_CPU_CACHE_MODE_PASSTHROUGH,
+ VIR_CPU_CACHE_MODE_DISABLE,
+
+ VIR_CPU_CACHE_MODE_LAST
+} virCPUCacheMode;
+
+VIR_ENUM_DECL(virCPUCacheMode);
+
+typedef struct _virCPUCacheDef virCPUCacheDef;
+typedef virCPUCacheDef *virCPUCacheDefPtr;
+struct _virCPUCacheDef {
+ int level; /* -1 for unspecified */
+ virCPUCacheMode mode;
+};
+
+
typedef struct _virCPUDef virCPUDef;
typedef virCPUDef *virCPUDefPtr;
struct _virCPUDef {
@@ -121,6 +139,7 @@ struct _virCPUDef {
size_t nfeatures;
size_t nfeatures_max;
virCPUFeatureDefPtr features;
+ virCPUCacheDefPtr cache;
};
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 170ecce7def22f759ad91d77861351b3563419e9..e6901a8f12ceb392cf8595521c092bfdec804e91 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -67,6 +67,8 @@ virCapabilitiesSetNetPrefix;
# conf/cpu_conf.h
+virCPUCacheModeTypeFromString;
+virCPUCacheModeTypeToString;
virCPUDefAddFeature;
virCPUDefCopy;
virCPUDefCopyModel;
diff --git a/tests/genericxml2xmlindata/generic-cpu-cache-disable.xml b/tests/genericxml2xmlindata/generic-cpu-cache-disable.xml
new file mode 100644
index 0000000000000000000000000000000000000000..25f65cc6e1277610bcb331d2a3159ce56f2f255c
--- /dev/null
+++ b/tests/genericxml2xmlindata/generic-cpu-cache-disable.xml
@@ -0,0 +1,20 @@
+
+ foo
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+
+
diff --git a/tests/genericxml2xmlindata/generic-cpu-cache-emulate.xml b/tests/genericxml2xmlindata/generic-cpu-cache-emulate.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6ea57cbf61b31f26da9d86613822bdf21dbced5f
--- /dev/null
+++ b/tests/genericxml2xmlindata/generic-cpu-cache-emulate.xml
@@ -0,0 +1,20 @@
+
+ foo
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+
+
diff --git a/tests/genericxml2xmlindata/generic-cpu-cache-passthrough.xml b/tests/genericxml2xmlindata/generic-cpu-cache-passthrough.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8d4c186c9b4a09d06716c710ede9a3192c5e18de
--- /dev/null
+++ b/tests/genericxml2xmlindata/generic-cpu-cache-passthrough.xml
@@ -0,0 +1,20 @@
+
+ foo
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+
+
diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c
index 1cda18cd9389e4ce7812c105f91a23d36a6d3aca..5bce00e211b300df1414f2dec24d9796c730b726 100644
--- a/tests/genericxml2xmltest.c
+++ b/tests/genericxml2xmltest.c
@@ -100,6 +100,10 @@ mymain(void)
DO_TEST("vcpus-individual");
+ DO_TEST("cpu-cache-emulate");
+ DO_TEST("cpu-cache-passthrough");
+ DO_TEST("cpu-cache-disable");
+
virObjectUnref(caps);
virObjectUnref(xmlopt);