qemu/qemu-Support-specifying-the-cache-size-presented-to-.patch
Jiabo Feng 74b61da994 QEMU update to version 6.2.0-107:
- qemu: Support specifying the cache size presented to guest
- hw/core/machine-smp: Initialize caches_bitmap before reading
- qapi/qom: Define cache enumeration and properties for machine
- linux-aio: fix unbalanced plugged counter in laio_io_unplug()

Signed-off-by: Jiabo Feng <fengjiabo1@huawei.com>
(cherry picked from commit 5453be865c307703cc43847588fa63ef74ac1ae0)
2025-03-26 21:10:58 +08:00

311 lines
14 KiB
Diff

From 152b6db246ca73a4eb1683afb59e8020645e0f79 Mon Sep 17 00:00:00 2001
From: huangchengfei <huangchengfei3@huawei.com>
Date: Fri, 7 Mar 2025 16:09:50 +0800
Subject: [PATCH] qemu: Support specifying the cache size presented to guest
Add configuration item to specifying the cache size presented to guest in Bytes.
for example:
-machine virt,\
smp-cache.0.cache=l1i,smp-cache.0.size=32768,\
smp-cache.1.cache=l1d,smp-cache.1.size=32768,\
smp-cache.2.cache=l2,smp-cache.2.size=1048576
Signed-off-by: huangchengfei <huangchengfei3@huawei.com>
---
hw/arm/virt-acpi-build.c | 40 ++++++++++++++++++++++++++++------------
hw/arm/virt.c | 18 +++++++++++++-----
hw/core/machine-smp.c | 14 ++++++++++++++
hw/core/machine.c | 2 ++
include/hw/boards.h | 4 ++++
qapi/machine.json | 15 ++++++++++-----
6 files changed, 71 insertions(+), 22 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index ed220d5d40..5ed23e627a 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -64,46 +64,62 @@
* ACPI spec, Revision 6.3
* 5.2.29.2 Cache Type Structure (Type 1)
*/
-static void build_cache_hierarchy_node(GArray *tbl, uint32_t next_level,
- uint32_t cache_type)
+static void build_cache_hierarchy_node(MachineState *ms, GArray *tbl,
+ uint32_t next_level, uint32_t cache_type)
{
build_append_byte(tbl, 1);
build_append_byte(tbl, 24);
build_append_int_noprefix(tbl, 0, 2);
build_append_int_noprefix(tbl, 127, 4);
build_append_int_noprefix(tbl, next_level, 4);
+ uint64_t cache_size;
switch (cache_type) {
case ARM_L1D_CACHE: /* L1 dcache info */
- build_append_int_noprefix(tbl, ARM_L1DCACHE_SIZE, 4);
+ cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L1D);
+ build_append_int_noprefix(tbl,
+ cache_size > 0 ? cache_size : ARM_L1DCACHE_SIZE,
+ 4);
build_append_int_noprefix(tbl, ARM_L1DCACHE_SETS, 4);
build_append_byte(tbl, ARM_L1DCACHE_ASSOCIATIVITY);
build_append_byte(tbl, ARM_L1DCACHE_ATTRIBUTES);
build_append_int_noprefix(tbl, ARM_L1DCACHE_LINE_SIZE, 2);
break;
case ARM_L1I_CACHE: /* L1 icache info */
- build_append_int_noprefix(tbl, ARM_L1ICACHE_SIZE, 4);
+ cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L1I);
+ build_append_int_noprefix(tbl,
+ cache_size > 0 ? cache_size : ARM_L1ICACHE_SIZE,
+ 4);
build_append_int_noprefix(tbl, ARM_L1ICACHE_SETS, 4);
build_append_byte(tbl, ARM_L1ICACHE_ASSOCIATIVITY);
build_append_byte(tbl, ARM_L1ICACHE_ATTRIBUTES);
build_append_int_noprefix(tbl, ARM_L1ICACHE_LINE_SIZE, 2);
break;
case ARM_L1_CACHE: /* L1 cache info */
- build_append_int_noprefix(tbl, ARM_L1CACHE_SIZE, 4);
+ cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L1);
+ build_append_int_noprefix(tbl,
+ cache_size > 0 ? cache_size : ARM_L1CACHE_SIZE,
+ 4);
build_append_int_noprefix(tbl, ARM_L1CACHE_SETS, 4);
build_append_byte(tbl, ARM_L1CACHE_ASSOCIATIVITY);
build_append_byte(tbl, ARM_L1CACHE_ATTRIBUTES);
build_append_int_noprefix(tbl, ARM_L1CACHE_LINE_SIZE, 2);
break;
case ARM_L2_CACHE: /* L2 cache info */
- build_append_int_noprefix(tbl, ARM_L2CACHE_SIZE, 4);
+ cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L2);
+ build_append_int_noprefix(tbl,
+ cache_size > 0 ? cache_size : ARM_L2CACHE_SIZE,
+ 4);
build_append_int_noprefix(tbl, ARM_L2CACHE_SETS, 4);
build_append_byte(tbl, ARM_L2CACHE_ASSOCIATIVITY);
build_append_byte(tbl, ARM_L2CACHE_ATTRIBUTES);
build_append_int_noprefix(tbl, ARM_L2CACHE_LINE_SIZE, 2);
break;
case ARM_L3_CACHE: /* L3 cache info */
- build_append_int_noprefix(tbl, ARM_L3CACHE_SIZE, 4);
+ cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L3);
+ build_append_int_noprefix(tbl,
+ cache_size > 0 ? cache_size : ARM_L3CACHE_SIZE,
+ 4);
build_append_int_noprefix(tbl, ARM_L3CACHE_SETS, 4);
build_append_byte(tbl, ARM_L3CACHE_ASSOCIATIVITY);
build_append_byte(tbl, ARM_L3CACHE_ATTRIBUTES);
@@ -140,7 +156,7 @@ static void build_pptt_arm(GArray *table_data, BIOSLinker *linker, MachineState
for (socket = 0; socket < ms->smp.sockets; socket++) {
uint32_t l3_cache_offset = table_data->len - pptt_start;
- build_cache_hierarchy_node(table_data, 0, ARM_L3_CACHE);
+ build_cache_hierarchy_node(ms, table_data, 0, ARM_L3_CACHE);
g_queue_push_tail(list,
GUINT_TO_POINTER(table_data->len - pptt_start));
@@ -179,16 +195,16 @@ static void build_pptt_arm(GArray *table_data, BIOSLinker *linker, MachineState
for (core = 0; core < ms->smp.cores; core++) {
uint32_t priv_rsrc[3] = {};
priv_rsrc[0] = table_data->len - pptt_start; /* L2 cache offset */
- build_cache_hierarchy_node(table_data, 0, ARM_L2_CACHE);
+ build_cache_hierarchy_node(ms, table_data, 0, ARM_L2_CACHE);
if (unified_l1) {
priv_rsrc[1] = table_data->len - pptt_start; /* L1 cache offset */
- build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1_CACHE);
+ build_cache_hierarchy_node(ms, table_data, priv_rsrc[0], ARM_L1_CACHE);
} else {
priv_rsrc[1] = table_data->len - pptt_start; /* L1 dcache offset */
- build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1D_CACHE);
+ build_cache_hierarchy_node(ms, table_data, priv_rsrc[0], ARM_L1D_CACHE);
priv_rsrc[2] = table_data->len - pptt_start; /* L1 icache offset */
- build_cache_hierarchy_node(table_data, priv_rsrc[0], ARM_L1I_CACHE);
+ build_cache_hierarchy_node(ms, table_data, priv_rsrc[0], ARM_L1I_CACHE);
}
if (ms->smp.threads > 1) {
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index d31675b0fd..c581f65a22 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -408,6 +408,7 @@ static void fdt_add_l3cache_nodes(const VirtMachineState *vms)
const MachineState *ms = MACHINE(vms);
int cpus_per_socket = ms->smp.clusters * ms->smp.cores * ms->smp.threads;
int sockets = (ms->smp.cpus + cpus_per_socket - 1) / cpus_per_socket;
+ uint64_t cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L3);
for (i = 0; i < sockets; i++) {
char *nodename = g_strdup_printf("/cpus/l3-cache%d", i);
@@ -416,7 +417,8 @@ static void fdt_add_l3cache_nodes(const VirtMachineState *vms)
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cache");
qemu_fdt_setprop_string(ms->fdt, nodename, "cache-unified", "true");
qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-level", 3);
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", ARM_L3CACHE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size",
+ cache_size > 0 ? cache_size : ARM_L3CACHE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size",
ARM_L3CACHE_LINE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", ARM_L3CACHE_SETS);
@@ -431,6 +433,7 @@ static void fdt_add_l2cache_nodes(const VirtMachineState *vms)
const MachineState *ms = MACHINE(vms);
int cpus_per_socket = ms->smp.clusters * ms->smp.cores * ms->smp.threads;
int cpu;
+ uint64_t cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L2);
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
char *next_path = g_strdup_printf("/cpus/l3-cache%d",
@@ -440,7 +443,8 @@ static void fdt_add_l2cache_nodes(const VirtMachineState *vms)
qemu_fdt_add_subnode(ms->fdt, nodename);
qemu_fdt_setprop_string(ms->fdt, nodename, "cache-unified", "true");
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cache");
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", ARM_L2CACHE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size",
+ cache_size > 0 ? cache_size : ARM_L2CACHE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size",
ARM_L2CACHE_LINE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", ARM_L2CACHE_SETS);
@@ -460,21 +464,25 @@ static void fdt_add_l1cache_prop(const VirtMachineState *vms,
const MachineState *ms = MACHINE(vms);
char *next_path = g_strdup_printf("/cpus/l2-cache%d", cpu);
bool unified_l1 = cpu_l1_cache_unified(0);
+ uint64_t l1d_cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L1D);
+ uint64_t l1i_cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L1I);
+ uint64_t l1_cache_size = machine_get_cache_size(ms, CACHE_LEVEL_AND_TYPE_L1);
if (unified_l1) {
- qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size", ARM_L1CACHE_SIZE);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-size",
+ l1_cache_size > 0 ? l1_cache_size : ARM_L1CACHE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-line-size",
ARM_L1CACHE_LINE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "cache-sets", ARM_L1CACHE_SETS);
} else {
qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-size",
- ARM_L1DCACHE_SIZE);
+ l1d_cache_size > 0 ? l1d_cache_size : ARM_L1DCACHE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-line-size",
ARM_L1DCACHE_LINE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "d-cache-sets",
ARM_L1DCACHE_SETS);
qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-size",
- ARM_L1ICACHE_SIZE);
+ l1i_cache_size > 0 ? l1i_cache_size : ARM_L1ICACHE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-line-size",
ARM_L1ICACHE_LINE_SIZE);
qemu_fdt_setprop_cell(ms->fdt, nodename, "i-cache-sets",
diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c
index a421a394d4..47922ec4aa 100644
--- a/hw/core/machine-smp.c
+++ b/hw/core/machine-smp.c
@@ -212,8 +212,22 @@ bool machine_parse_smp_cache(MachineState *ms,
return false;
}
+ machine_set_cache_size(ms, node->value->cache,
+ node->value->size);
set_bit(node->value->cache, caches_bitmap);
}
return true;
+}
+
+uint64_t machine_get_cache_size(const MachineState *ms,
+ CacheLevelAndType cache)
+{
+ return ms->smp_cache.props[cache].size;
+}
+
+void machine_set_cache_size(MachineState *ms, CacheLevelAndType cache,
+ uint64_t size)
+{
+ ms->smp_cache.props[cache].size = size;
}
\ No newline at end of file
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 4cdd9a7300..35a7c1d328 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -789,6 +789,7 @@ static void machine_get_smp_cache(Object *obj, Visitor *v, const char *name,
SmpCacheProperties *node = g_new(SmpCacheProperties, 1);
node->cache = cache->props[i].cache;
+ node->size = cache->props[i].size;
QAPI_LIST_APPEND(tail, node);
}
@@ -989,6 +990,7 @@ static void machine_initfn(Object *obj)
for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
ms->smp_cache.props[i].cache = (CacheLevelAndType)i;
+ ms->smp_cache.props[i].size = 0;
}
}
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 59f04caf3f..f7ba05c56a 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -39,6 +39,10 @@ void machine_parse_smp_config(MachineState *ms,
bool machine_parse_smp_cache(MachineState *ms,
const SmpCachePropertiesList *caches,
Error **errp);
+uint64_t machine_get_cache_size(const MachineState *ms,
+ CacheLevelAndType cache);
+void machine_set_cache_size(MachineState *ms, CacheLevelAndType cache,
+ uint64_t size);
/**
* machine_class_allow_dynamic_sysbus_dev: Add type to list of valid devices
diff --git a/qapi/machine.json b/qapi/machine.json
index 676e16477b..c12fa1e399 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1581,14 +1581,16 @@
#
# @l1i: L1 instruction cache.
#
+# @l1: L1 (unified) cache.
+#
# @l2: L2 (unified) cache.
#
# @l3: L3 (unified) cache
#
-# Since: 9.2
+# Since: 6.2
##
{ 'enum': 'CacheLevelAndType',
- 'data': [ 'l1d', 'l1i', 'l2', 'l3' ] }
+ 'data': [ 'l1d', 'l1i', 'l1', 'l2', 'l3' ] }
##
# @SmpCacheProperties:
@@ -1597,11 +1599,14 @@
#
# @cache: Cache name, which is the combination of cache level and cache type.
#
-# Since: 9.2
+# @size: Cache size in units of Byte.
+#
+# Since: 6.2
##
{ 'struct': 'SmpCacheProperties',
'data': {
- 'cache': 'CacheLevelAndType' } }
+ 'cache': 'CacheLevelAndType',
+ 'size': 'uint64' } }
##
# @SmpCachePropertiesWrapper:
@@ -1610,7 +1615,7 @@
#
# @caches: the list of SmpCacheProperties.
#
-# Since 9.2
+# Since 6.2
##
{ 'struct': 'SmpCachePropertiesWrapper',
'data': { 'caches': ['SmpCacheProperties'] } }
--
2.41.0.windows.1