* [PATCH v10 1/6] target/arm/tcg: increase cache level for cpu=max
2025-04-28 11:07 [PATCH v10 0/6] Specifying cache topology on ARM Alireza Sanaee via
@ 2025-04-28 11:07 ` Alireza Sanaee via
2025-04-28 11:07 ` Alireza Sanaee via
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
This patch addresses cache description in the `aarch64_max_tcg_initfn`
function for cpu=max. It introduces three layers of caches and modifies
the cache description registers accordingly.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
target/arm/tcg/cpu64.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 29ab0ac79da9..1405506594c2 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1086,6 +1086,19 @@ void aarch64_max_tcg_initfn(Object *obj)
uint64_t t;
uint32_t u;
+ /*
+ * Expanded cache set
+ */
+ cpu->clidr = 0x8200123; /* 4 4 3 in 3 bit fields */
+ /* 64KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7);
+ /* 64KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 2);
+ /* 1MB L2 unified cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 1 * MiB, 7);
+ /* 2MB L3 unified cache */
+ cpu->ccsidr[4] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 2 * MiB, 7);
+
/*
* Unset ARM_FEATURE_BACKCOMPAT_CNTFRQ, which we would otherwise default
* to because we started with aarch64_a57_initfn(). A 'max' CPU might
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v10 1/6] target/arm/tcg: increase cache level for cpu=max
@ 2025-04-28 11:07 ` Alireza Sanaee via
0 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
This patch addresses cache description in the `aarch64_max_tcg_initfn`
function for cpu=max. It introduces three layers of caches and modifies
the cache description registers accordingly.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
target/arm/tcg/cpu64.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 29ab0ac79da9..1405506594c2 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1086,6 +1086,19 @@ void aarch64_max_tcg_initfn(Object *obj)
uint64_t t;
uint32_t u;
+ /*
+ * Expanded cache set
+ */
+ cpu->clidr = 0x8200123; /* 4 4 3 in 3 bit fields */
+ /* 64KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7);
+ /* 64KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 2);
+ /* 1MB L2 unified cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 1 * MiB, 7);
+ /* 2MB L3 unified cache */
+ cpu->ccsidr[4] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 2 * MiB, 7);
+
/*
* Unset ARM_FEATURE_BACKCOMPAT_CNTFRQ, which we would otherwise default
* to because we started with aarch64_a57_initfn(). A 'max' CPU might
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 2/6] arm/virt.c: add cache hierarchy to device tree
2025-04-28 11:07 [PATCH v10 0/6] Specifying cache topology on ARM Alireza Sanaee via
@ 2025-04-28 11:07 ` Alireza Sanaee via
2025-04-28 11:07 ` Alireza Sanaee via
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
Specify which layer (core/cluster/socket) caches found at in the CPU
topology. Updating cache topology to device tree (spec v0.4).
Example:
Here, 2 sockets (packages), and 2 clusters, 4 cores and 2 threads
created, in aggregate 2*2*4*2 logical cores. In the smp-cache object,
cores will have l1d and l1i. However, extending this is not difficult).
The clusters will share a unified l2 level cache, and finally sockets
will share l3. In this patch, threads will share l1 caches by default,
but this can be adjusted if case required.
Currently only three levels of caches are supported. The patch does not
allow partial declaration of caches. In another word, all caches must be
defined or caches must be skipped.
./qemu-system-aarch64 \
-machine virt,\
smp-cache.0.cache=l1i,smp-cache.0.topology=core,\
smp-cache.1.cache=l1d,smp-cache.1.topology=core,\
smp-cache.2.cache=l2,smp-cache.2.topology=cluster,\
smp-cache.3.cache=l3,smp-cache.3.topology=socket\
-cpu max \
-m 2048 \
-smp sockets=2,clusters=2,cores=4,threads=1 \
-kernel ./Image.gz \
-append "console=ttyAMA0 root=/dev/ram rdinit=/init acpi=force" \
-initrd rootfs.cpio.gz \
-bios ./edk2-aarch64-code.fd \
-nographic
For instance, following device tree will be generated for a scenario
where we have 2 sockets, 2 clusters, 2 cores and 2 threads, in total 16
PEs. L1i and L1d are private to each thread, and l2 and l3 are shared at
socket level as an example.
Limitation: SMT cores cannot share L1 cache for now. This
problem does not exist in PPTT tables.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
Co-developed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
hw/arm/virt.c | 343 ++++++++++++++++++++++++++++++++++++++++++
hw/cpu/core.c | 92 +++++++++++
include/hw/arm/virt.h | 4 +
include/hw/cpu/core.h | 25 +++
4 files changed, 464 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a96452f17a48..ece8203e9f0b 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -238,6 +238,132 @@ static const int a15irqmap[] = {
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
};
+unsigned int virt_get_caches(const VirtMachineState *vms,
+ PPTTCPUCaches *caches)
+{
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); /* assume homogeneous CPUs */
+ bool ccidx = cpu_isar_feature(any_ccidx, armcpu);
+ unsigned int num_cache, i;
+ int level_instr = 1, level_data = 1;
+
+ for (i = 0, num_cache = 0; i < CPU_MAX_CACHES; i++, num_cache++) {
+ int type = (armcpu->clidr >> (3 * i)) & 7;
+ int bank_index;
+ int level;
+ PPTTCPUCacheType cache_type;
+
+ if (type == 0) {
+ break;
+ }
+
+ switch (type) {
+ case 1:
+ cache_type = INSTRUCTION;
+ level = level_instr;
+ break;
+ case 2:
+ cache_type = DATA;
+ level = level_data;
+ break;
+ case 4:
+ cache_type = UNIFIED;
+ level = level_instr > level_data ? level_instr : level_data;
+ break;
+ case 3: /* Split - Do data first */
+ cache_type = DATA;
+ level = level_data;
+ break;
+ default:
+ error_setg(&error_abort, "Unrecognized cache type");
+ return 0;
+ }
+ /*
+ * ccsidr is indexed using both the level and whether it is
+ * an instruction cache. Unified caches use the same storage
+ * as data caches.
+ */
+ bank_index = (i * 2) | ((type == 1) ? 1 : 0);
+ if (ccidx) {
+ caches[num_cache] = (PPTTCPUCaches) {
+ .type = cache_type,
+ .level = level,
+ .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ CCIDX_LINESIZE) + 4),
+ .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ CCIDX_ASSOCIATIVITY) + 1,
+ .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
+ CCIDX_NUMSETS) + 1,
+ };
+ } else {
+ caches[num_cache] = (PPTTCPUCaches) {
+ .type = cache_type,
+ .level = level,
+ .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1, LINESIZE) + 4),
+ .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ ASSOCIATIVITY) + 1,
+ .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
+ NUMSETS) + 1,
+ };
+ }
+ caches[num_cache].size = caches[num_cache].associativity *
+ caches[num_cache].sets * caches[num_cache].linesize;
+
+ /* Break one 'split' entry up into two records */
+ if (type == 3) {
+ num_cache++;
+ bank_index = (i * 2) | 1;
+ if (ccidx) {
+ /* Instruction cache: bottom bit set when reading banked reg */
+ caches[num_cache] = (PPTTCPUCaches) {
+ .type = INSTRUCTION,
+ .level = level_instr,
+ .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ CCIDX_LINESIZE) + 4),
+ .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ CCIDX_ASSOCIATIVITY) + 1,
+ .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
+ CCIDX_NUMSETS) + 1,
+ };
+ } else {
+ caches[num_cache] = (PPTTCPUCaches) {
+ .type = INSTRUCTION,
+ .level = level_instr,
+ .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1, LINESIZE) + 4),
+ .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ ASSOCIATIVITY) + 1,
+ .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
+ NUMSETS) + 1,
+ };
+ }
+ caches[num_cache].size = caches[num_cache].associativity *
+ caches[num_cache].sets * caches[num_cache].linesize;
+ }
+ switch (type) {
+ case 1:
+ level_instr++;
+ break;
+ case 2:
+ level_data++;
+ break;
+ case 3:
+ case 4:
+ level_instr++;
+ level_data++;
+ break;
+ }
+ }
+
+ return num_cache;
+}
+
static void create_randomness(MachineState *ms, const char *node)
{
struct {
@@ -421,13 +547,96 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms)
}
}
+static void add_cache_node(void *fdt, char * nodepath, PPTTCPUCaches cache,
+ uint32_t *next_level) {
+ /* Assume L2/3 are unified caches. */
+
+ uint32_t phandle;
+
+ qemu_fdt_add_path(fdt, nodepath);
+ phandle = qemu_fdt_alloc_phandle(fdt);
+ qemu_fdt_setprop_cell(fdt, nodepath, "phandle", phandle);
+ qemu_fdt_setprop_cell(fdt, nodepath, "cache-level", cache.level);
+ qemu_fdt_setprop_cell(fdt, nodepath, "cache-size", cache.size);
+ qemu_fdt_setprop_cell(fdt, nodepath, "cache-block-size", cache.linesize);
+ qemu_fdt_setprop_cell(fdt, nodepath, "cache-sets", cache.sets);
+ qemu_fdt_setprop(fdt, nodepath, "cache-unified", NULL, 0);
+ qemu_fdt_setprop_string(fdt, nodepath, "compatible", "cache");
+ if (cache.level != 3) {
+ /* top level cache doesn't have next-level-cache property */
+ qemu_fdt_setprop_cell(fdt, nodepath, "next-level-cache", *next_level);
+ }
+
+ *next_level = phandle;
+}
+
+static bool add_cpu_cache_hierarchy(void *fdt, PPTTCPUCaches* cache,
+ uint32_t cache_cnt,
+ uint32_t top_level,
+ uint32_t bottom_level,
+ uint32_t cpu_id,
+ uint32_t *next_level) {
+ bool found_cache = false;
+ char *nodepath;
+
+ for (int level = top_level; level >= bottom_level; level--) {
+ for (int i = 0; i < cache_cnt; i++) {
+ if (i != level) {
+ continue;
+ }
+
+ nodepath = g_strdup_printf("/cpus/cpu@%d/l%d-cache",
+ cpu_id, level);
+ add_cache_node(fdt, nodepath, cache[i], next_level);
+ found_cache = true;
+ g_free(nodepath);
+
+ }
+ }
+
+ return found_cache;
+}
+
+static void set_cache_properties(void *fdt, const char *nodename,
+ const char *prefix, PPTTCPUCaches cache)
+{
+ char prop_name[64];
+
+ snprintf(prop_name, sizeof(prop_name), "%s-block-size", prefix);
+ qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.linesize);
+
+ snprintf(prop_name, sizeof(prop_name), "%s-size", prefix);
+ qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.size);
+
+ snprintf(prop_name, sizeof(prop_name), "%s-sets", prefix);
+ qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.sets);
+}
+
static void fdt_add_cpu_nodes(const VirtMachineState *vms)
{
int cpu;
int addr_cells = 1;
const MachineState *ms = MACHINE(vms);
+ const MachineClass *mc = MACHINE_GET_CLASS(ms);
const VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
int smp_cpus = ms->smp.cpus;
+ int socket_id, cluster_id, core_id;
+ uint32_t next_level = 0;
+ uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0;
+ int last_socket = -1, last_cluster = -1, last_core = -1;
+ int top_node = 3, top_cluster = 3, top_core = 3;
+ int bottom_node = 3, bottom_cluster = 3, bottom_core = 3;
+ unsigned int num_cache;
+ PPTTCPUCaches caches[16];
+ bool cache_created = false;
+
+ num_cache = virt_get_caches(vms, caches);
+
+ if (mc->smp_props.has_caches &&
+ partial_cache_description(ms, caches, num_cache)) {
+ error_setg(&error_fatal, "Missing cache description");
+ return;
+ }
/*
* See Linux Documentation/devicetree/bindings/arm/cpus.yaml
@@ -456,9 +665,14 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
for (cpu = smp_cpus - 1; cpu >= 0; cpu--) {
+ socket_id = cpu / (ms->smp.clusters * ms->smp.cores * ms->smp.threads);
+ cluster_id = cpu / (ms->smp.cores * ms->smp.threads) % ms->smp.clusters;
+ core_id = cpu / (ms->smp.threads) % ms->smp.cores;
+
char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
CPUState *cs = CPU(armcpu);
+ const char *prefix = NULL;
qemu_fdt_add_subnode(ms->fdt, nodename);
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
@@ -488,6 +702,130 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
qemu_fdt_alloc_phandle(ms->fdt));
}
+ if (!vmc->no_cpu_topology && num_cache) {
+ for (uint8_t i = 0; i < num_cache; i++) {
+ /* only level 1 in the CPU entry */
+ if (caches[i].level > 1) {
+ continue;
+ }
+
+ if (caches[i].type == INSTRUCTION) {
+ prefix = "i-cache";
+ } else if (caches[i].type == DATA) {
+ prefix = "d-cache";
+ } else if (caches[i].type == UNIFIED) {
+ error_setg(&error_fatal,
+ "Unified type is not implemented at level %d",
+ caches[i].level);
+ return;
+ } else {
+ error_setg(&error_fatal, "Undefined cache type");
+ return;
+ }
+
+ set_cache_properties(ms->fdt, nodename, prefix, caches[i]);
+ }
+ }
+
+ if (socket_id != last_socket) {
+ bottom_node = top_node;
+ /* this assumes socket as the highest topological level */
+ socket_offset = 0;
+ cluster_offset = 0;
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_SOCKET) &&
+ find_the_lowest_level_cache_defined_at_level(ms,
+ &bottom_node,
+ CPU_TOPOLOGY_LEVEL_SOCKET)) {
+
+ if (bottom_node == 1) {
+ error_report(
+ "Cannot share L1 at socket_id %d. DT limiation on "
+ "sharing at cache level = 1",
+ socket_id);
+ }
+
+ cache_created = add_cpu_cache_hierarchy(ms->fdt, caches,
+ num_cache,
+ top_node,
+ bottom_node, cpu,
+ &socket_offset);
+
+ if (!cache_created) {
+ error_setg(&error_fatal,
+ "Socket: No caches at levels %d-%d",
+ top_node, bottom_node);
+ return;
+ }
+
+ top_cluster = bottom_node - 1;
+ }
+
+ last_socket = socket_id;
+ }
+
+ if (cluster_id != last_cluster) {
+ bottom_cluster = top_cluster;
+ cluster_offset = socket_offset;
+ core_offset = 0;
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER) &&
+ find_the_lowest_level_cache_defined_at_level(ms,
+ &bottom_cluster,
+ CPU_TOPOLOGY_LEVEL_CLUSTER)) {
+
+ cache_created = add_cpu_cache_hierarchy(ms->fdt, caches,
+ num_cache,
+ top_cluster,
+ bottom_cluster, cpu,
+ &cluster_offset);
+ if (bottom_cluster == 1) {
+ error_report(
+ "Cannot share L1 at socket_id %d, cluster_id %d. "
+ "DT limitation on sharing at cache level = 1.",
+ socket_id, cluster_id);
+ }
+
+ if (!cache_created) {
+ error_setg(&error_fatal,
+ "Cluster: No caches at levels %d-%d",
+ top_cluster, bottom_cluster);
+ return;
+ }
+
+ top_core = bottom_cluster - 1;
+ } else if (top_cluster == bottom_node - 1) {
+ top_core = bottom_node - 1;
+ }
+
+ last_cluster = cluster_id;
+ }
+
+ if (core_id != last_core) {
+ bottom_core = top_core;
+ core_offset = cluster_offset;
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CORE) &&
+ find_the_lowest_level_cache_defined_at_level(ms,
+ &bottom_core,
+ CPU_TOPOLOGY_LEVEL_CORE)) {
+
+ if (bottom_core == 1) {
+ bottom_core++;
+ }
+
+ cache_created = add_cpu_cache_hierarchy(ms->fdt,
+ caches,
+ num_cache,
+ top_core,
+ bottom_core, cpu,
+ &core_offset);
+ }
+
+ last_core = core_id;
+ }
+
+ next_level = core_offset;
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "next-level-cache",
+ next_level);
+
g_free(nodename);
}
@@ -3193,6 +3531,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
hc->unplug = virt_machine_device_unplug_cb;
mc->nvdimm_supported = true;
mc->smp_props.clusters_supported = true;
+ /* Supported caches */
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1D] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1I] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L2] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L3] = true;
mc->auto_enable_numa_with_memhp = true;
mc->auto_enable_numa_with_memdev = true;
/* platform instead of architectural choice */
diff --git a/hw/cpu/core.c b/hw/cpu/core.c
index 495a5c30ffe1..3adfc3ca0001 100644
--- a/hw/cpu/core.c
+++ b/hw/cpu/core.c
@@ -102,4 +102,96 @@ static void cpu_core_register_types(void)
type_register_static(&cpu_core_type_info);
}
+bool cache_described_at(const MachineState *ms, CpuTopologyLevel level)
+{
+ if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3) == level ||
+ machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2) == level ||
+ machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I) == level ||
+ machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D) == level) {
+ return true;
+ }
+ return false;
+}
+
+int partial_cache_description(const MachineState *ms, PPTTCPUCaches *caches,
+ int num_caches)
+{
+ int level, c;
+
+ for (level = 1; level < num_caches; level++) {
+ for (c = 0; c < num_caches; c++) {
+ if (caches[c].level != level) {
+ continue;
+ }
+
+ switch (level) {
+ case 1:
+ /*
+ * L1 cache is assumed to have both L1I and L1D available.
+ * Technically both need to be checked.
+ */
+ if (machine_get_cache_topo_level(ms,
+ CACHE_LEVEL_AND_TYPE_L1I) ==
+ CPU_TOPOLOGY_LEVEL_DEFAULT) {
+ return level;
+ }
+ break;
+ case 2:
+ if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2) ==
+ CPU_TOPOLOGY_LEVEL_DEFAULT) {
+ return level;
+ }
+ break;
+ case 3:
+ if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3) ==
+ CPU_TOPOLOGY_LEVEL_DEFAULT) {
+ return level;
+ }
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function assumes l3 and l2 have unified cache and l1 is split l1d
+ * and l1i, and further prepares the lowest cache level for a topology
+ * level. The info will be fed to build_caches to create caches at the
+ * right level.
+ */
+bool find_the_lowest_level_cache_defined_at_level(const MachineState *ms,
+ int *level_found,
+ CpuTopologyLevel topo_level) {
+
+ CpuTopologyLevel level;
+
+ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I);
+ if (level == topo_level) {
+ *level_found = 1;
+ return true;
+ }
+
+ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D);
+ if (level == topo_level) {
+ *level_found = 1;
+ return true;
+ }
+
+ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2);
+ if (level == topo_level) {
+ *level_found = 2;
+ return true;
+ }
+
+ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3);
+ if (level == topo_level) {
+ *level_found = 3;
+ return true;
+ }
+
+ return false;
+}
+
type_init(cpu_core_register_types)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index c8e94e6aedc9..68ff99d6806d 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -39,6 +39,7 @@
#include "system/kvm.h"
#include "hw/intc/arm_gicv3_common.h"
#include "qom/object.h"
+#include "hw/cpu/core.h"
#define NUM_GICV2M_SPIS 64
#define NUM_VIRTIO_TRANSPORTS 32
@@ -50,6 +51,8 @@
/* GPIO pins */
#define GPIO_PIN_POWER_BUTTON 3
+#define CPU_MAX_CACHES 16
+
enum {
VIRT_FLASH,
VIRT_MEM,
@@ -189,6 +192,7 @@ OBJECT_DECLARE_TYPE(VirtMachineState, VirtMachineClass, VIRT_MACHINE)
void virt_acpi_setup(VirtMachineState *vms);
bool virt_is_acpi_enabled(VirtMachineState *vms);
+unsigned int virt_get_caches(const VirtMachineState *vms, PPTTCPUCaches *caches);
/* Return number of redistributors that fit in the specified region */
static uint32_t virt_redist_capacity(VirtMachineState *vms, int region)
diff --git a/include/hw/cpu/core.h b/include/hw/cpu/core.h
index 98ab91647eb2..a90b708b835b 100644
--- a/include/hw/cpu/core.h
+++ b/include/hw/cpu/core.h
@@ -25,6 +25,31 @@ struct CPUCore {
int nr_threads;
};
+typedef enum CPUCacheType {
+ DATA,
+ INSTRUCTION,
+ UNIFIED,
+} PPTTCPUCacheType;
+
+typedef struct PPTTCPUCaches {
+ PPTTCPUCacheType type;
+ uint32_t sets;
+ uint32_t size;
+ uint32_t level;
+ uint16_t linesize;
+ uint8_t attributes; /* write policy: 0x0 write back, 0x1 write through */
+ uint8_t associativity;
+} PPTTCPUCaches;
+
+int partial_cache_description(const MachineState *ms, PPTTCPUCaches *caches,
+ int num_caches);
+
+bool cache_described_at(const MachineState *ms, CpuTopologyLevel level);
+
+bool find_the_lowest_level_cache_defined_at_level(const MachineState *ms,
+ int *level_found,
+ CpuTopologyLevel topo_level);
+
/* Note: topology field names need to be kept in sync with
* 'CpuInstanceProperties' */
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v10 2/6] arm/virt.c: add cache hierarchy to device tree
@ 2025-04-28 11:07 ` Alireza Sanaee via
0 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
Specify which layer (core/cluster/socket) caches found at in the CPU
topology. Updating cache topology to device tree (spec v0.4).
Example:
Here, 2 sockets (packages), and 2 clusters, 4 cores and 2 threads
created, in aggregate 2*2*4*2 logical cores. In the smp-cache object,
cores will have l1d and l1i. However, extending this is not difficult).
The clusters will share a unified l2 level cache, and finally sockets
will share l3. In this patch, threads will share l1 caches by default,
but this can be adjusted if case required.
Currently only three levels of caches are supported. The patch does not
allow partial declaration of caches. In another word, all caches must be
defined or caches must be skipped.
./qemu-system-aarch64 \
-machine virt,\
smp-cache.0.cache=l1i,smp-cache.0.topology=core,\
smp-cache.1.cache=l1d,smp-cache.1.topology=core,\
smp-cache.2.cache=l2,smp-cache.2.topology=cluster,\
smp-cache.3.cache=l3,smp-cache.3.topology=socket\
-cpu max \
-m 2048 \
-smp sockets=2,clusters=2,cores=4,threads=1 \
-kernel ./Image.gz \
-append "console=ttyAMA0 root=/dev/ram rdinit=/init acpi=force" \
-initrd rootfs.cpio.gz \
-bios ./edk2-aarch64-code.fd \
-nographic
For instance, following device tree will be generated for a scenario
where we have 2 sockets, 2 clusters, 2 cores and 2 threads, in total 16
PEs. L1i and L1d are private to each thread, and l2 and l3 are shared at
socket level as an example.
Limitation: SMT cores cannot share L1 cache for now. This
problem does not exist in PPTT tables.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
Co-developed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
hw/arm/virt.c | 343 ++++++++++++++++++++++++++++++++++++++++++
hw/cpu/core.c | 92 +++++++++++
include/hw/arm/virt.h | 4 +
include/hw/cpu/core.h | 25 +++
4 files changed, 464 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index a96452f17a48..ece8203e9f0b 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -238,6 +238,132 @@ static const int a15irqmap[] = {
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
};
+unsigned int virt_get_caches(const VirtMachineState *vms,
+ PPTTCPUCaches *caches)
+{
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); /* assume homogeneous CPUs */
+ bool ccidx = cpu_isar_feature(any_ccidx, armcpu);
+ unsigned int num_cache, i;
+ int level_instr = 1, level_data = 1;
+
+ for (i = 0, num_cache = 0; i < CPU_MAX_CACHES; i++, num_cache++) {
+ int type = (armcpu->clidr >> (3 * i)) & 7;
+ int bank_index;
+ int level;
+ PPTTCPUCacheType cache_type;
+
+ if (type == 0) {
+ break;
+ }
+
+ switch (type) {
+ case 1:
+ cache_type = INSTRUCTION;
+ level = level_instr;
+ break;
+ case 2:
+ cache_type = DATA;
+ level = level_data;
+ break;
+ case 4:
+ cache_type = UNIFIED;
+ level = level_instr > level_data ? level_instr : level_data;
+ break;
+ case 3: /* Split - Do data first */
+ cache_type = DATA;
+ level = level_data;
+ break;
+ default:
+ error_setg(&error_abort, "Unrecognized cache type");
+ return 0;
+ }
+ /*
+ * ccsidr is indexed using both the level and whether it is
+ * an instruction cache. Unified caches use the same storage
+ * as data caches.
+ */
+ bank_index = (i * 2) | ((type == 1) ? 1 : 0);
+ if (ccidx) {
+ caches[num_cache] = (PPTTCPUCaches) {
+ .type = cache_type,
+ .level = level,
+ .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ CCIDX_LINESIZE) + 4),
+ .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ CCIDX_ASSOCIATIVITY) + 1,
+ .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
+ CCIDX_NUMSETS) + 1,
+ };
+ } else {
+ caches[num_cache] = (PPTTCPUCaches) {
+ .type = cache_type,
+ .level = level,
+ .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1, LINESIZE) + 4),
+ .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ ASSOCIATIVITY) + 1,
+ .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
+ NUMSETS) + 1,
+ };
+ }
+ caches[num_cache].size = caches[num_cache].associativity *
+ caches[num_cache].sets * caches[num_cache].linesize;
+
+ /* Break one 'split' entry up into two records */
+ if (type == 3) {
+ num_cache++;
+ bank_index = (i * 2) | 1;
+ if (ccidx) {
+ /* Instruction cache: bottom bit set when reading banked reg */
+ caches[num_cache] = (PPTTCPUCaches) {
+ .type = INSTRUCTION,
+ .level = level_instr,
+ .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ CCIDX_LINESIZE) + 4),
+ .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ CCIDX_ASSOCIATIVITY) + 1,
+ .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
+ CCIDX_NUMSETS) + 1,
+ };
+ } else {
+ caches[num_cache] = (PPTTCPUCaches) {
+ .type = INSTRUCTION,
+ .level = level_instr,
+ .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1, LINESIZE) + 4),
+ .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
+ CCSIDR_EL1,
+ ASSOCIATIVITY) + 1,
+ .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
+ NUMSETS) + 1,
+ };
+ }
+ caches[num_cache].size = caches[num_cache].associativity *
+ caches[num_cache].sets * caches[num_cache].linesize;
+ }
+ switch (type) {
+ case 1:
+ level_instr++;
+ break;
+ case 2:
+ level_data++;
+ break;
+ case 3:
+ case 4:
+ level_instr++;
+ level_data++;
+ break;
+ }
+ }
+
+ return num_cache;
+}
+
static void create_randomness(MachineState *ms, const char *node)
{
struct {
@@ -421,13 +547,96 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms)
}
}
+static void add_cache_node(void *fdt, char * nodepath, PPTTCPUCaches cache,
+ uint32_t *next_level) {
+ /* Assume L2/3 are unified caches. */
+
+ uint32_t phandle;
+
+ qemu_fdt_add_path(fdt, nodepath);
+ phandle = qemu_fdt_alloc_phandle(fdt);
+ qemu_fdt_setprop_cell(fdt, nodepath, "phandle", phandle);
+ qemu_fdt_setprop_cell(fdt, nodepath, "cache-level", cache.level);
+ qemu_fdt_setprop_cell(fdt, nodepath, "cache-size", cache.size);
+ qemu_fdt_setprop_cell(fdt, nodepath, "cache-block-size", cache.linesize);
+ qemu_fdt_setprop_cell(fdt, nodepath, "cache-sets", cache.sets);
+ qemu_fdt_setprop(fdt, nodepath, "cache-unified", NULL, 0);
+ qemu_fdt_setprop_string(fdt, nodepath, "compatible", "cache");
+ if (cache.level != 3) {
+ /* top level cache doesn't have next-level-cache property */
+ qemu_fdt_setprop_cell(fdt, nodepath, "next-level-cache", *next_level);
+ }
+
+ *next_level = phandle;
+}
+
+static bool add_cpu_cache_hierarchy(void *fdt, PPTTCPUCaches* cache,
+ uint32_t cache_cnt,
+ uint32_t top_level,
+ uint32_t bottom_level,
+ uint32_t cpu_id,
+ uint32_t *next_level) {
+ bool found_cache = false;
+ char *nodepath;
+
+ for (int level = top_level; level >= bottom_level; level--) {
+ for (int i = 0; i < cache_cnt; i++) {
+ if (i != level) {
+ continue;
+ }
+
+ nodepath = g_strdup_printf("/cpus/cpu@%d/l%d-cache",
+ cpu_id, level);
+ add_cache_node(fdt, nodepath, cache[i], next_level);
+ found_cache = true;
+ g_free(nodepath);
+
+ }
+ }
+
+ return found_cache;
+}
+
+static void set_cache_properties(void *fdt, const char *nodename,
+ const char *prefix, PPTTCPUCaches cache)
+{
+ char prop_name[64];
+
+ snprintf(prop_name, sizeof(prop_name), "%s-block-size", prefix);
+ qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.linesize);
+
+ snprintf(prop_name, sizeof(prop_name), "%s-size", prefix);
+ qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.size);
+
+ snprintf(prop_name, sizeof(prop_name), "%s-sets", prefix);
+ qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.sets);
+}
+
static void fdt_add_cpu_nodes(const VirtMachineState *vms)
{
int cpu;
int addr_cells = 1;
const MachineState *ms = MACHINE(vms);
+ const MachineClass *mc = MACHINE_GET_CLASS(ms);
const VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
int smp_cpus = ms->smp.cpus;
+ int socket_id, cluster_id, core_id;
+ uint32_t next_level = 0;
+ uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0;
+ int last_socket = -1, last_cluster = -1, last_core = -1;
+ int top_node = 3, top_cluster = 3, top_core = 3;
+ int bottom_node = 3, bottom_cluster = 3, bottom_core = 3;
+ unsigned int num_cache;
+ PPTTCPUCaches caches[16];
+ bool cache_created = false;
+
+ num_cache = virt_get_caches(vms, caches);
+
+ if (mc->smp_props.has_caches &&
+ partial_cache_description(ms, caches, num_cache)) {
+ error_setg(&error_fatal, "Missing cache description");
+ return;
+ }
/*
* See Linux Documentation/devicetree/bindings/arm/cpus.yaml
@@ -456,9 +665,14 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
for (cpu = smp_cpus - 1; cpu >= 0; cpu--) {
+ socket_id = cpu / (ms->smp.clusters * ms->smp.cores * ms->smp.threads);
+ cluster_id = cpu / (ms->smp.cores * ms->smp.threads) % ms->smp.clusters;
+ core_id = cpu / (ms->smp.threads) % ms->smp.cores;
+
char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
CPUState *cs = CPU(armcpu);
+ const char *prefix = NULL;
qemu_fdt_add_subnode(ms->fdt, nodename);
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
@@ -488,6 +702,130 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
qemu_fdt_alloc_phandle(ms->fdt));
}
+ if (!vmc->no_cpu_topology && num_cache) {
+ for (uint8_t i = 0; i < num_cache; i++) {
+ /* only level 1 in the CPU entry */
+ if (caches[i].level > 1) {
+ continue;
+ }
+
+ if (caches[i].type == INSTRUCTION) {
+ prefix = "i-cache";
+ } else if (caches[i].type == DATA) {
+ prefix = "d-cache";
+ } else if (caches[i].type == UNIFIED) {
+ error_setg(&error_fatal,
+ "Unified type is not implemented at level %d",
+ caches[i].level);
+ return;
+ } else {
+ error_setg(&error_fatal, "Undefined cache type");
+ return;
+ }
+
+ set_cache_properties(ms->fdt, nodename, prefix, caches[i]);
+ }
+ }
+
+ if (socket_id != last_socket) {
+ bottom_node = top_node;
+ /* this assumes socket as the highest topological level */
+ socket_offset = 0;
+ cluster_offset = 0;
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_SOCKET) &&
+ find_the_lowest_level_cache_defined_at_level(ms,
+ &bottom_node,
+ CPU_TOPOLOGY_LEVEL_SOCKET)) {
+
+ if (bottom_node == 1) {
+ error_report(
+ "Cannot share L1 at socket_id %d. DT limiation on "
+ "sharing at cache level = 1",
+ socket_id);
+ }
+
+ cache_created = add_cpu_cache_hierarchy(ms->fdt, caches,
+ num_cache,
+ top_node,
+ bottom_node, cpu,
+ &socket_offset);
+
+ if (!cache_created) {
+ error_setg(&error_fatal,
+ "Socket: No caches at levels %d-%d",
+ top_node, bottom_node);
+ return;
+ }
+
+ top_cluster = bottom_node - 1;
+ }
+
+ last_socket = socket_id;
+ }
+
+ if (cluster_id != last_cluster) {
+ bottom_cluster = top_cluster;
+ cluster_offset = socket_offset;
+ core_offset = 0;
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER) &&
+ find_the_lowest_level_cache_defined_at_level(ms,
+ &bottom_cluster,
+ CPU_TOPOLOGY_LEVEL_CLUSTER)) {
+
+ cache_created = add_cpu_cache_hierarchy(ms->fdt, caches,
+ num_cache,
+ top_cluster,
+ bottom_cluster, cpu,
+ &cluster_offset);
+ if (bottom_cluster == 1) {
+ error_report(
+ "Cannot share L1 at socket_id %d, cluster_id %d. "
+ "DT limitation on sharing at cache level = 1.",
+ socket_id, cluster_id);
+ }
+
+ if (!cache_created) {
+ error_setg(&error_fatal,
+ "Cluster: No caches at levels %d-%d",
+ top_cluster, bottom_cluster);
+ return;
+ }
+
+ top_core = bottom_cluster - 1;
+ } else if (top_cluster == bottom_node - 1) {
+ top_core = bottom_node - 1;
+ }
+
+ last_cluster = cluster_id;
+ }
+
+ if (core_id != last_core) {
+ bottom_core = top_core;
+ core_offset = cluster_offset;
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CORE) &&
+ find_the_lowest_level_cache_defined_at_level(ms,
+ &bottom_core,
+ CPU_TOPOLOGY_LEVEL_CORE)) {
+
+ if (bottom_core == 1) {
+ bottom_core++;
+ }
+
+ cache_created = add_cpu_cache_hierarchy(ms->fdt,
+ caches,
+ num_cache,
+ top_core,
+ bottom_core, cpu,
+ &core_offset);
+ }
+
+ last_core = core_id;
+ }
+
+ next_level = core_offset;
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "next-level-cache",
+ next_level);
+
g_free(nodename);
}
@@ -3193,6 +3531,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
hc->unplug = virt_machine_device_unplug_cb;
mc->nvdimm_supported = true;
mc->smp_props.clusters_supported = true;
+ /* Supported caches */
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1D] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1I] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L2] = true;
+ mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L3] = true;
mc->auto_enable_numa_with_memhp = true;
mc->auto_enable_numa_with_memdev = true;
/* platform instead of architectural choice */
diff --git a/hw/cpu/core.c b/hw/cpu/core.c
index 495a5c30ffe1..3adfc3ca0001 100644
--- a/hw/cpu/core.c
+++ b/hw/cpu/core.c
@@ -102,4 +102,96 @@ static void cpu_core_register_types(void)
type_register_static(&cpu_core_type_info);
}
+bool cache_described_at(const MachineState *ms, CpuTopologyLevel level)
+{
+ if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3) == level ||
+ machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2) == level ||
+ machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I) == level ||
+ machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D) == level) {
+ return true;
+ }
+ return false;
+}
+
+int partial_cache_description(const MachineState *ms, PPTTCPUCaches *caches,
+ int num_caches)
+{
+ int level, c;
+
+ for (level = 1; level < num_caches; level++) {
+ for (c = 0; c < num_caches; c++) {
+ if (caches[c].level != level) {
+ continue;
+ }
+
+ switch (level) {
+ case 1:
+ /*
+ * L1 cache is assumed to have both L1I and L1D available.
+ * Technically both need to be checked.
+ */
+ if (machine_get_cache_topo_level(ms,
+ CACHE_LEVEL_AND_TYPE_L1I) ==
+ CPU_TOPOLOGY_LEVEL_DEFAULT) {
+ return level;
+ }
+ break;
+ case 2:
+ if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2) ==
+ CPU_TOPOLOGY_LEVEL_DEFAULT) {
+ return level;
+ }
+ break;
+ case 3:
+ if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3) ==
+ CPU_TOPOLOGY_LEVEL_DEFAULT) {
+ return level;
+ }
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function assumes l3 and l2 have unified cache and l1 is split l1d
+ * and l1i, and further prepares the lowest cache level for a topology
+ * level. The info will be fed to build_caches to create caches at the
+ * right level.
+ */
+bool find_the_lowest_level_cache_defined_at_level(const MachineState *ms,
+ int *level_found,
+ CpuTopologyLevel topo_level) {
+
+ CpuTopologyLevel level;
+
+ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I);
+ if (level == topo_level) {
+ *level_found = 1;
+ return true;
+ }
+
+ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D);
+ if (level == topo_level) {
+ *level_found = 1;
+ return true;
+ }
+
+ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2);
+ if (level == topo_level) {
+ *level_found = 2;
+ return true;
+ }
+
+ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3);
+ if (level == topo_level) {
+ *level_found = 3;
+ return true;
+ }
+
+ return false;
+}
+
type_init(cpu_core_register_types)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index c8e94e6aedc9..68ff99d6806d 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -39,6 +39,7 @@
#include "system/kvm.h"
#include "hw/intc/arm_gicv3_common.h"
#include "qom/object.h"
+#include "hw/cpu/core.h"
#define NUM_GICV2M_SPIS 64
#define NUM_VIRTIO_TRANSPORTS 32
@@ -50,6 +51,8 @@
/* GPIO pins */
#define GPIO_PIN_POWER_BUTTON 3
+#define CPU_MAX_CACHES 16
+
enum {
VIRT_FLASH,
VIRT_MEM,
@@ -189,6 +192,7 @@ OBJECT_DECLARE_TYPE(VirtMachineState, VirtMachineClass, VIRT_MACHINE)
void virt_acpi_setup(VirtMachineState *vms);
bool virt_is_acpi_enabled(VirtMachineState *vms);
+unsigned int virt_get_caches(const VirtMachineState *vms, PPTTCPUCaches *caches);
/* Return number of redistributors that fit in the specified region */
static uint32_t virt_redist_capacity(VirtMachineState *vms, int region)
diff --git a/include/hw/cpu/core.h b/include/hw/cpu/core.h
index 98ab91647eb2..a90b708b835b 100644
--- a/include/hw/cpu/core.h
+++ b/include/hw/cpu/core.h
@@ -25,6 +25,31 @@ struct CPUCore {
int nr_threads;
};
+typedef enum CPUCacheType {
+ DATA,
+ INSTRUCTION,
+ UNIFIED,
+} PPTTCPUCacheType;
+
+typedef struct PPTTCPUCaches {
+ PPTTCPUCacheType type;
+ uint32_t sets;
+ uint32_t size;
+ uint32_t level;
+ uint16_t linesize;
+ uint8_t attributes; /* write policy: 0x0 write back, 0x1 write through */
+ uint8_t associativity;
+} PPTTCPUCaches;
+
+int partial_cache_description(const MachineState *ms, PPTTCPUCaches *caches,
+ int num_caches);
+
+bool cache_described_at(const MachineState *ms, CpuTopologyLevel level);
+
+bool find_the_lowest_level_cache_defined_at_level(const MachineState *ms,
+ int *level_found,
+ CpuTopologyLevel topo_level);
+
/* Note: topology field names need to be kept in sync with
* 'CpuInstanceProperties' */
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH v10 2/6] arm/virt.c: add cache hierarchy to device tree
2025-04-28 11:07 ` Alireza Sanaee via
(?)
@ 2025-05-11 18:20 ` Michael S. Tsirkin
2025-05-13 10:49 ` Alireza Sanaee via
-1 siblings, 1 reply; 14+ messages in thread
From: Michael S. Tsirkin @ 2025-05-11 18:20 UTC (permalink / raw)
To: Alireza Sanaee
Cc: qemu-devel, philmd, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mtosatti, peter.maydell, qemu-arm,
richard.henderson, shameerali.kolothum.thodi, shannon.zhaosl,
yangyicong, zhao1.liu
On Mon, Apr 28, 2025 at 12:07:50PM +0100, Alireza Sanaee wrote:
> Specify which layer (core/cluster/socket) caches found at in the CPU
> topology. Updating cache topology to device tree (spec v0.4).
> Example:
>
> Here, 2 sockets (packages), and 2 clusters, 4 cores and 2 threads
> created, in aggregate 2*2*4*2 logical cores. In the smp-cache object,
> cores will have l1d and l1i. However, extending this is not difficult).
> The clusters will share a unified l2 level cache, and finally sockets
> will share l3. In this patch, threads will share l1 caches by default,
> but this can be adjusted if case required.
>
> Currently only three levels of caches are supported. The patch does not
> allow partial declaration of caches. In another word, all caches must be
> defined or caches must be skipped.
>
> ./qemu-system-aarch64 \
> -machine virt,\
> smp-cache.0.cache=l1i,smp-cache.0.topology=core,\
> smp-cache.1.cache=l1d,smp-cache.1.topology=core,\
> smp-cache.2.cache=l2,smp-cache.2.topology=cluster,\
> smp-cache.3.cache=l3,smp-cache.3.topology=socket\
> -cpu max \
> -m 2048 \
> -smp sockets=2,clusters=2,cores=4,threads=1 \
> -kernel ./Image.gz \
> -append "console=ttyAMA0 root=/dev/ram rdinit=/init acpi=force" \
> -initrd rootfs.cpio.gz \
> -bios ./edk2-aarch64-code.fd \
> -nographic
>
> For instance, following device tree will be generated for a scenario
> where we have 2 sockets, 2 clusters, 2 cores and 2 threads, in total 16
> PEs. L1i and L1d are private to each thread, and l2 and l3 are shared at
> socket level as an example.
>
> Limitation: SMT cores cannot share L1 cache for now. This
> problem does not exist in PPTT tables.
>
> Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
> Co-developed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> ---
> hw/arm/virt.c | 343 ++++++++++++++++++++++++++++++++++++++++++
> hw/cpu/core.c | 92 +++++++++++
> include/hw/arm/virt.h | 4 +
> include/hw/cpu/core.h | 25 +++
> 4 files changed, 464 insertions(+)
>
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index a96452f17a48..ece8203e9f0b 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -238,6 +238,132 @@ static const int a15irqmap[] = {
> [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
> };
>
> +unsigned int virt_get_caches(const VirtMachineState *vms,
> + PPTTCPUCaches *caches)
pass an array size so we can assert on OOB at least.
> +{
> + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); /* assume homogeneous CPUs */
> + bool ccidx = cpu_isar_feature(any_ccidx, armcpu);
> + unsigned int num_cache, i;
> + int level_instr = 1, level_data = 1;
> +
> + for (i = 0, num_cache = 0; i < CPU_MAX_CACHES; i++, num_cache++) {
> + int type = (armcpu->clidr >> (3 * i)) & 7;
> + int bank_index;
> + int level;
> + PPTTCPUCacheType cache_type;
> +
> + if (type == 0) {
> + break;
> + }
> +
> + switch (type) {
> + case 1:
> + cache_type = INSTRUCTION;
> + level = level_instr;
> + break;
> + case 2:
> + cache_type = DATA;
> + level = level_data;
> + break;
> + case 4:
> + cache_type = UNIFIED;
> + level = level_instr > level_data ? level_instr : level_data;
> + break;
> + case 3: /* Split - Do data first */
> + cache_type = DATA;
> + level = level_data;
> + break;
> + default:
> + error_setg(&error_abort, "Unrecognized cache type");
> + return 0;
> + }
> + /*
> + * ccsidr is indexed using both the level and whether it is
> + * an instruction cache. Unified caches use the same storage
> + * as data caches.
> + */
> + bank_index = (i * 2) | ((type == 1) ? 1 : 0);
> + if (ccidx) {
> + caches[num_cache] = (PPTTCPUCaches) {
> + .type = cache_type,
> + .level = level,
> + .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
> + CCSIDR_EL1,
> + CCIDX_LINESIZE) + 4),
> + .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
> + CCSIDR_EL1,
> + CCIDX_ASSOCIATIVITY) + 1,
> + .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
> + CCIDX_NUMSETS) + 1,
> + };
> + } else {
> + caches[num_cache] = (PPTTCPUCaches) {
> + .type = cache_type,
> + .level = level,
> + .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
> + CCSIDR_EL1, LINESIZE) + 4),
> + .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
> + CCSIDR_EL1,
> + ASSOCIATIVITY) + 1,
> + .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
> + NUMSETS) + 1,
> + };
> + }
> + caches[num_cache].size = caches[num_cache].associativity *
> + caches[num_cache].sets * caches[num_cache].linesize;
> +
> + /* Break one 'split' entry up into two records */
> + if (type == 3) {
> + num_cache++;
> + bank_index = (i * 2) | 1;
> + if (ccidx) {
> + /* Instruction cache: bottom bit set when reading banked reg */
> + caches[num_cache] = (PPTTCPUCaches) {
> + .type = INSTRUCTION,
> + .level = level_instr,
> + .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
> + CCSIDR_EL1,
> + CCIDX_LINESIZE) + 4),
> + .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
> + CCSIDR_EL1,
> + CCIDX_ASSOCIATIVITY) + 1,
> + .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
> + CCIDX_NUMSETS) + 1,
> + };
> + } else {
> + caches[num_cache] = (PPTTCPUCaches) {
> + .type = INSTRUCTION,
> + .level = level_instr,
> + .linesize = 1 << (FIELD_EX64(armcpu->ccsidr[bank_index],
> + CCSIDR_EL1, LINESIZE) + 4),
> + .associativity = FIELD_EX64(armcpu->ccsidr[bank_index],
> + CCSIDR_EL1,
> + ASSOCIATIVITY) + 1,
> + .sets = FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL1,
> + NUMSETS) + 1,
> + };
> + }
> + caches[num_cache].size = caches[num_cache].associativity *
> + caches[num_cache].sets * caches[num_cache].linesize;
> + }
> + switch (type) {
> + case 1:
> + level_instr++;
> + break;
> + case 2:
> + level_data++;
> + break;
> + case 3:
> + case 4:
> + level_instr++;
> + level_data++;
> + break;
> + }
> + }
> +
> + return num_cache;
> +}
> +
> static void create_randomness(MachineState *ms, const char *node)
> {
> struct {
> @@ -421,13 +547,96 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms)
> }
> }
>
> +static void add_cache_node(void *fdt, char * nodepath, PPTTCPUCaches cache,
> + uint32_t *next_level) {
coding style violation
> + /* Assume L2/3 are unified caches. */
> +
> + uint32_t phandle;
> +
> + qemu_fdt_add_path(fdt, nodepath);
> + phandle = qemu_fdt_alloc_phandle(fdt);
> + qemu_fdt_setprop_cell(fdt, nodepath, "phandle", phandle);
> + qemu_fdt_setprop_cell(fdt, nodepath, "cache-level", cache.level);
> + qemu_fdt_setprop_cell(fdt, nodepath, "cache-size", cache.size);
> + qemu_fdt_setprop_cell(fdt, nodepath, "cache-block-size", cache.linesize);
> + qemu_fdt_setprop_cell(fdt, nodepath, "cache-sets", cache.sets);
> + qemu_fdt_setprop(fdt, nodepath, "cache-unified", NULL, 0);
> + qemu_fdt_setprop_string(fdt, nodepath, "compatible", "cache");
> + if (cache.level != 3) {
> + /* top level cache doesn't have next-level-cache property */
> + qemu_fdt_setprop_cell(fdt, nodepath, "next-level-cache", *next_level);
> + }
> +
> + *next_level = phandle;
> +}
> +
> +static bool add_cpu_cache_hierarchy(void *fdt, PPTTCPUCaches* cache,
> + uint32_t cache_cnt,
> + uint32_t top_level,
> + uint32_t bottom_level,
> + uint32_t cpu_id,
> + uint32_t *next_level) {
> + bool found_cache = false;
> + char *nodepath;
> +
> + for (int level = top_level; level >= bottom_level; level--) {
> + for (int i = 0; i < cache_cnt; i++) {
> + if (i != level) {
> + continue;
> + }
> +
> + nodepath = g_strdup_printf("/cpus/cpu@%d/l%d-cache",
> + cpu_id, level);
> + add_cache_node(fdt, nodepath, cache[i], next_level);
> + found_cache = true;
> + g_free(nodepath);
> +
> + }
> + }
> +
> + return found_cache;
> +}
> +
> +static void set_cache_properties(void *fdt, const char *nodename,
> + const char *prefix, PPTTCPUCaches cache)
> +{
> + char prop_name[64];
> +
> + snprintf(prop_name, sizeof(prop_name), "%s-block-size", prefix);
> + qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.linesize);
> +
> + snprintf(prop_name, sizeof(prop_name), "%s-size", prefix);
> + qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.size);
> +
> + snprintf(prop_name, sizeof(prop_name), "%s-sets", prefix);
> + qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.sets);
> +}
> +
> static void fdt_add_cpu_nodes(const VirtMachineState *vms)
> {
> int cpu;
> int addr_cells = 1;
> const MachineState *ms = MACHINE(vms);
> + const MachineClass *mc = MACHINE_GET_CLASS(ms);
> const VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
> int smp_cpus = ms->smp.cpus;
> + int socket_id, cluster_id, core_id;
> + uint32_t next_level = 0;
> + uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0;
> + int last_socket = -1, last_cluster = -1, last_core = -1;
> + int top_node = 3, top_cluster = 3, top_core = 3;
> + int bottom_node = 3, bottom_cluster = 3, bottom_core = 3;
do these one var at a time.
> + unsigned int num_cache;
> + PPTTCPUCaches caches[16];
why 16?
> + bool cache_created = false;
> +
> + num_cache = virt_get_caches(vms, caches);
> +
> + if (mc->smp_props.has_caches &&
> + partial_cache_description(ms, caches, num_cache)) {
> + error_setg(&error_fatal, "Missing cache description");
> + return;
> + }
>
> /*
> * See Linux Documentation/devicetree/bindings/arm/cpus.yaml
> @@ -456,9 +665,14 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
> qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
>
> for (cpu = smp_cpus - 1; cpu >= 0; cpu--) {
> + socket_id = cpu / (ms->smp.clusters * ms->smp.cores * ms->smp.threads);
> + cluster_id = cpu / (ms->smp.cores * ms->smp.threads) % ms->smp.clusters;
> + core_id = cpu / (ms->smp.threads) % ms->smp.cores;
> +
> char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
> ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
> CPUState *cs = CPU(armcpu);
> + const char *prefix = NULL;
>
> qemu_fdt_add_subnode(ms->fdt, nodename);
> qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
> @@ -488,6 +702,130 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
> qemu_fdt_alloc_phandle(ms->fdt));
> }
>
> + if (!vmc->no_cpu_topology && num_cache) {
> + for (uint8_t i = 0; i < num_cache; i++) {
> + /* only level 1 in the CPU entry */
> + if (caches[i].level > 1) {
> + continue;
> + }
> +
> + if (caches[i].type == INSTRUCTION) {
> + prefix = "i-cache";
> + } else if (caches[i].type == DATA) {
> + prefix = "d-cache";
> + } else if (caches[i].type == UNIFIED) {
> + error_setg(&error_fatal,
> + "Unified type is not implemented at level %d",
> + caches[i].level);
> + return;
> + } else {
> + error_setg(&error_fatal, "Undefined cache type");
> + return;
> + }
> +
> + set_cache_properties(ms->fdt, nodename, prefix, caches[i]);
> + }
> + }
> +
> + if (socket_id != last_socket) {
> + bottom_node = top_node;
> + /* this assumes socket as the highest topological level */
> + socket_offset = 0;
> + cluster_offset = 0;
> + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_SOCKET) &&
> + find_the_lowest_level_cache_defined_at_level(ms,
> + &bottom_node,
> + CPU_TOPOLOGY_LEVEL_SOCKET)) {
> +
> + if (bottom_node == 1) {
> + error_report(
> + "Cannot share L1 at socket_id %d. DT limiation on "
> + "sharing at cache level = 1",
> + socket_id);
> + }
> +
> + cache_created = add_cpu_cache_hierarchy(ms->fdt, caches,
> + num_cache,
> + top_node,
> + bottom_node, cpu,
> + &socket_offset);
> +
> + if (!cache_created) {
> + error_setg(&error_fatal,
> + "Socket: No caches at levels %d-%d",
> + top_node, bottom_node);
> + return;
> + }
> +
> + top_cluster = bottom_node - 1;
> + }
> +
> + last_socket = socket_id;
> + }
> +
> + if (cluster_id != last_cluster) {
> + bottom_cluster = top_cluster;
> + cluster_offset = socket_offset;
> + core_offset = 0;
> + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER) &&
> + find_the_lowest_level_cache_defined_at_level(ms,
> + &bottom_cluster,
> + CPU_TOPOLOGY_LEVEL_CLUSTER)) {
> +
> + cache_created = add_cpu_cache_hierarchy(ms->fdt, caches,
> + num_cache,
> + top_cluster,
> + bottom_cluster, cpu,
> + &cluster_offset);
> + if (bottom_cluster == 1) {
> + error_report(
> + "Cannot share L1 at socket_id %d, cluster_id %d. "
> + "DT limitation on sharing at cache level = 1.",
> + socket_id, cluster_id);
> + }
> +
> + if (!cache_created) {
> + error_setg(&error_fatal,
> + "Cluster: No caches at levels %d-%d",
> + top_cluster, bottom_cluster);
> + return;
> + }
> +
> + top_core = bottom_cluster - 1;
> + } else if (top_cluster == bottom_node - 1) {
> + top_core = bottom_node - 1;
> + }
> +
> + last_cluster = cluster_id;
> + }
> +
> + if (core_id != last_core) {
> + bottom_core = top_core;
> + core_offset = cluster_offset;
> + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CORE) &&
> + find_the_lowest_level_cache_defined_at_level(ms,
> + &bottom_core,
> + CPU_TOPOLOGY_LEVEL_CORE)) {
> +
> + if (bottom_core == 1) {
> + bottom_core++;
> + }
> +
> + cache_created = add_cpu_cache_hierarchy(ms->fdt,
> + caches,
> + num_cache,
> + top_core,
> + bottom_core, cpu,
> + &core_offset);
> + }
> +
> + last_core = core_id;
> + }
> +
> + next_level = core_offset;
> + qemu_fdt_setprop_cell(ms->fdt, nodename, "next-level-cache",
> + next_level);
> +
> g_free(nodename);
> }
>
> @@ -3193,6 +3531,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
> hc->unplug = virt_machine_device_unplug_cb;
> mc->nvdimm_supported = true;
> mc->smp_props.clusters_supported = true;
> + /* Supported caches */
> + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1D] = true;
> + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1I] = true;
> + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L2] = true;
> + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L3] = true;
> mc->auto_enable_numa_with_memhp = true;
> mc->auto_enable_numa_with_memdev = true;
> /* platform instead of architectural choice */
> diff --git a/hw/cpu/core.c b/hw/cpu/core.c
> index 495a5c30ffe1..3adfc3ca0001 100644
> --- a/hw/cpu/core.c
> +++ b/hw/cpu/core.c
> @@ -102,4 +102,96 @@ static void cpu_core_register_types(void)
> type_register_static(&cpu_core_type_info);
> }
>
> +bool cache_described_at(const MachineState *ms, CpuTopologyLevel level)
> +{
> + if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3) == level ||
> + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2) == level ||
> + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I) == level ||
> + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D) == level) {
> + return true;
> + }
> + return false;
> +}
> +
> +int partial_cache_description(const MachineState *ms, PPTTCPUCaches *caches,
> + int num_caches)
> +{
> + int level, c;
> +
> + for (level = 1; level < num_caches; level++) {
> + for (c = 0; c < num_caches; c++) {
> + if (caches[c].level != level) {
> + continue;
> + }
> +
> + switch (level) {
> + case 1:
> + /*
> + * L1 cache is assumed to have both L1I and L1D available.
> + * Technically both need to be checked.
> + */
> + if (machine_get_cache_topo_level(ms,
> + CACHE_LEVEL_AND_TYPE_L1I) ==
> + CPU_TOPOLOGY_LEVEL_DEFAULT) {
> + return level;
> + }
> + break;
> + case 2:
> + if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2) ==
> + CPU_TOPOLOGY_LEVEL_DEFAULT) {
> + return level;
> + }
> + break;
> + case 3:
> + if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3) ==
> + CPU_TOPOLOGY_LEVEL_DEFAULT) {
> + return level;
> + }
> + break;
> + }
> + }
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * This function assumes l3 and l2 have unified cache and l1 is split l1d
> + * and l1i, and further prepares the lowest cache level for a topology
> + * level. The info will be fed to build_caches to create caches at the
> + * right level.
> + */
> +bool find_the_lowest_level_cache_defined_at_level(const MachineState *ms,
> + int *level_found,
> + CpuTopologyLevel topo_level) {
> +
> + CpuTopologyLevel level;
> +
> + level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I);
> + if (level == topo_level) {
> + *level_found = 1;
> + return true;
> + }
> +
> + level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D);
> + if (level == topo_level) {
> + *level_found = 1;
> + return true;
> + }
> +
> + level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2);
> + if (level == topo_level) {
> + *level_found = 2;
> + return true;
> + }
> +
> + level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3);
> + if (level == topo_level) {
> + *level_found = 3;
> + return true;
> + }
> +
> + return false;
> +}
> +
> type_init(cpu_core_register_types)
> diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
> index c8e94e6aedc9..68ff99d6806d 100644
> --- a/include/hw/arm/virt.h
> +++ b/include/hw/arm/virt.h
> @@ -39,6 +39,7 @@
> #include "system/kvm.h"
> #include "hw/intc/arm_gicv3_common.h"
> #include "qom/object.h"
> +#include "hw/cpu/core.h"
>
> #define NUM_GICV2M_SPIS 64
> #define NUM_VIRTIO_TRANSPORTS 32
> @@ -50,6 +51,8 @@
> /* GPIO pins */
> #define GPIO_PIN_POWER_BUTTON 3
>
> +#define CPU_MAX_CACHES 16
> +
> enum {
> VIRT_FLASH,
> VIRT_MEM,
> @@ -189,6 +192,7 @@ OBJECT_DECLARE_TYPE(VirtMachineState, VirtMachineClass, VIRT_MACHINE)
>
> void virt_acpi_setup(VirtMachineState *vms);
> bool virt_is_acpi_enabled(VirtMachineState *vms);
> +unsigned int virt_get_caches(const VirtMachineState *vms, PPTTCPUCaches *caches);
>
> /* Return number of redistributors that fit in the specified region */
> static uint32_t virt_redist_capacity(VirtMachineState *vms, int region)
> diff --git a/include/hw/cpu/core.h b/include/hw/cpu/core.h
> index 98ab91647eb2..a90b708b835b 100644
> --- a/include/hw/cpu/core.h
> +++ b/include/hw/cpu/core.h
> @@ -25,6 +25,31 @@ struct CPUCore {
> int nr_threads;
> };
>
> +typedef enum CPUCacheType {
> + DATA,
> + INSTRUCTION,
> + UNIFIED,
> +} PPTTCPUCacheType;
Given specific values matter, you should specify them.
Also, please prefix names sensibly and consistently:
CPUCoreCacheType CPU_CORE_DATA and so on.
> +
> +typedef struct PPTTCPUCaches {
> + PPTTCPUCacheType type;
> + uint32_t sets;
> + uint32_t size;
> + uint32_t level;
> + uint16_t linesize;
> + uint8_t attributes; /* write policy: 0x0 write back, 0x1 write through */
> + uint8_t associativity;
> +} PPTTCPUCaches;
> +
> +int partial_cache_description(const MachineState *ms, PPTTCPUCaches *caches,
> + int num_caches);
> +
> +bool cache_described_at(const MachineState *ms, CpuTopologyLevel level);
> +
> +bool find_the_lowest_level_cache_defined_at_level(const MachineState *ms,
> + int *level_found,
> + CpuTopologyLevel topo_level);
> +
> /* Note: topology field names need to be kept in sync with
> * 'CpuInstanceProperties' */
same here, prefix everything with cpu_core CPUCore etc.
> --
> 2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH v10 2/6] arm/virt.c: add cache hierarchy to device tree
2025-05-11 18:20 ` Michael S. Tsirkin
@ 2025-05-13 10:49 ` Alireza Sanaee via
0 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-05-13 10:49 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: qemu-devel, philmd, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mtosatti, peter.maydell, qemu-arm,
richard.henderson, shameerali.kolothum.thodi, shannon.zhaosl,
yangyicong, zhao1.liu
On Sun, 11 May 2025 14:20:56 -0400
"Michael S. Tsirkin" <mst@redhat.com> wrote:
> On Mon, Apr 28, 2025 at 12:07:50PM +0100, Alireza Sanaee wrote:
> > Specify which layer (core/cluster/socket) caches found at in the CPU
> > topology. Updating cache topology to device tree (spec v0.4).
> > Example:
> >
> > Here, 2 sockets (packages), and 2 clusters, 4 cores and 2 threads
> > created, in aggregate 2*2*4*2 logical cores. In the smp-cache
> > object, cores will have l1d and l1i. However, extending this is
> > not difficult). The clusters will share a unified l2 level cache,
> > and finally sockets will share l3. In this patch, threads will
> > share l1 caches by default, but this can be adjusted if case
> > required.
> >
> > Currently only three levels of caches are supported. The patch
> > does not allow partial declaration of caches. In another word, all
> > caches must be defined or caches must be skipped.
> >
> > ./qemu-system-aarch64 \
> > -machine virt,\
> > smp-cache.0.cache=l1i,smp-cache.0.topology=core,\
> > smp-cache.1.cache=l1d,smp-cache.1.topology=core,\
> > smp-cache.2.cache=l2,smp-cache.2.topology=cluster,\
> > smp-cache.3.cache=l3,smp-cache.3.topology=socket\
> > -cpu max \
> > -m 2048 \
> > -smp sockets=2,clusters=2,cores=4,threads=1 \
> > -kernel ./Image.gz \
> > -append "console=ttyAMA0 root=/dev/ram rdinit=/init acpi=force"
> > \ -initrd rootfs.cpio.gz \
> > -bios ./edk2-aarch64-code.fd \
> > -nographic
> >
> > For instance, following device tree will be generated for a scenario
> > where we have 2 sockets, 2 clusters, 2 cores and 2 threads, in
> > total 16 PEs. L1i and L1d are private to each thread, and l2 and l3
> > are shared at socket level as an example.
> >
> > Limitation: SMT cores cannot share L1 cache for now. This
> > problem does not exist in PPTT tables.
> >
> > Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
> > Co-developed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> > Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> > ---
> > hw/arm/virt.c | 343
> > ++++++++++++++++++++++++++++++++++++++++++ hw/cpu/core.c |
> > 92 +++++++++++ include/hw/arm/virt.h | 4 +
> > include/hw/cpu/core.h | 25 +++
> > 4 files changed, 464 insertions(+)
> >
> > diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> > index a96452f17a48..ece8203e9f0b 100644
> > --- a/hw/arm/virt.c
> > +++ b/hw/arm/virt.c
> > @@ -238,6 +238,132 @@ static const int a15irqmap[] = {
> > [VIRT_PLATFORM_BUS] = 112, /* ...to 112 +
> > PLATFORM_BUS_NUM_IRQS -1 */ };
> >
> > +unsigned int virt_get_caches(const VirtMachineState *vms,
> > + PPTTCPUCaches *caches)
>
> pass an array size so we can assert on OOB at least.
I think OOB does not occur as we are using CPU_MAX_CACHES in the loop
which is always 16 (related to the comment you also had later in the
code).
I can still pass a len if you think this looks dubious.
>
> > +{
> > + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); /* assume
> > homogeneous CPUs */
> > + bool ccidx = cpu_isar_feature(any_ccidx, armcpu);
> > + unsigned int num_cache, i;
> > + int level_instr = 1, level_data = 1;
> > +
> > + for (i = 0, num_cache = 0; i < CPU_MAX_CACHES; i++,
> > num_cache++) {
> > + int type = (armcpu->clidr >> (3 * i)) & 7;
> > + int bank_index;
> > + int level;
> > + PPTTCPUCacheType cache_type;
> > +
> > + if (type == 0) {
> > + break;
> > + }
> > +
> > + switch (type) {
> > + case 1:
> > + cache_type = INSTRUCTION;
> > + level = level_instr;
> > + break;
> > + case 2:
> > + cache_type = DATA;
> > + level = level_data;
> > + break;
> > + case 4:
> > + cache_type = UNIFIED;
> > + level = level_instr > level_data ? level_instr :
> > level_data;
> > + break;
> > + case 3: /* Split - Do data first */
> > + cache_type = DATA;
> > + level = level_data;
> > + break;
> > + default:
> > + error_setg(&error_abort, "Unrecognized cache type");
> > + return 0;
> > + }
> > + /*
> > + * ccsidr is indexed using both the level and whether it is
> > + * an instruction cache. Unified caches use the same
> > storage
> > + * as data caches.
> > + */
> > + bank_index = (i * 2) | ((type == 1) ? 1 : 0);
> > + if (ccidx) {
> > + caches[num_cache] = (PPTTCPUCaches) {
> > + .type = cache_type,
> > + .level = level,
> > + .linesize = 1 <<
> > (FIELD_EX64(armcpu->ccsidr[bank_index],
> > + CCSIDR_EL1,
> > + CCIDX_LINESIZE) + 4),
> > + .associativity =
> > FIELD_EX64(armcpu->ccsidr[bank_index],
> > + CCSIDR_EL1,
> > + CCIDX_ASSOCIATIVITY) +
> > 1,
> > + .sets = FIELD_EX64(armcpu->ccsidr[bank_index],
> > CCSIDR_EL1,
> > + CCIDX_NUMSETS) + 1,
> > + };
> > + } else {
> > + caches[num_cache] = (PPTTCPUCaches) {
> > + .type = cache_type,
> > + .level = level,
> > + .linesize = 1 <<
> > (FIELD_EX64(armcpu->ccsidr[bank_index],
> > + CCSIDR_EL1, LINESIZE)
> > + 4),
> > + .associativity =
> > FIELD_EX64(armcpu->ccsidr[bank_index],
> > + CCSIDR_EL1,
> > + ASSOCIATIVITY) + 1,
> > + .sets = FIELD_EX64(armcpu->ccsidr[bank_index],
> > CCSIDR_EL1,
> > + NUMSETS) + 1,
> > + };
> > + }
> > + caches[num_cache].size = caches[num_cache].associativity *
> > + caches[num_cache].sets * caches[num_cache].linesize;
> > +
> > + /* Break one 'split' entry up into two records */
> > + if (type == 3) {
> > + num_cache++;
> > + bank_index = (i * 2) | 1;
> > + if (ccidx) {
> > + /* Instruction cache: bottom bit set when reading
> > banked reg */
> > + caches[num_cache] = (PPTTCPUCaches) {
> > + .type = INSTRUCTION,
> > + .level = level_instr,
> > + .linesize = 1 <<
> > (FIELD_EX64(armcpu->ccsidr[bank_index],
> > + CCSIDR_EL1,
> > + CCIDX_LINESIZE) +
> > 4),
> > + .associativity =
> > FIELD_EX64(armcpu->ccsidr[bank_index],
> > + CCSIDR_EL1,
> > +
> > CCIDX_ASSOCIATIVITY) + 1,
> > + .sets = FIELD_EX64(armcpu->ccsidr[bank_index],
> > CCSIDR_EL1,
> > + CCIDX_NUMSETS) + 1,
> > + };
> > + } else {
> > + caches[num_cache] = (PPTTCPUCaches) {
> > + .type = INSTRUCTION,
> > + .level = level_instr,
> > + .linesize = 1 <<
> > (FIELD_EX64(armcpu->ccsidr[bank_index],
> > + CCSIDR_EL1,
> > LINESIZE) + 4),
> > + .associativity =
> > FIELD_EX64(armcpu->ccsidr[bank_index],
> > + CCSIDR_EL1,
> > + ASSOCIATIVITY) + 1,
> > + .sets = FIELD_EX64(armcpu->ccsidr[bank_index],
> > CCSIDR_EL1,
> > + NUMSETS) + 1,
> > + };
> > + }
> > + caches[num_cache].size =
> > caches[num_cache].associativity *
> > + caches[num_cache].sets *
> > caches[num_cache].linesize;
> > + }
> > + switch (type) {
> > + case 1:
> > + level_instr++;
> > + break;
> > + case 2:
> > + level_data++;
> > + break;
> > + case 3:
> > + case 4:
> > + level_instr++;
> > + level_data++;
> > + break;
> > + }
> > + }
> > +
> > + return num_cache;
> > +}
> > +
> > static void create_randomness(MachineState *ms, const char *node)
> > {
> > struct {
> > @@ -421,13 +547,96 @@ static void fdt_add_timer_nodes(const
> > VirtMachineState *vms) }
> > }
> >
> > +static void add_cache_node(void *fdt, char * nodepath,
> > PPTTCPUCaches cache,
> > + uint32_t *next_level) {
>
> coding style violation
thanks. gonna fix.
>
> > + /* Assume L2/3 are unified caches. */
> > +
> > + uint32_t phandle;
> > +
> > + qemu_fdt_add_path(fdt, nodepath);
> > + phandle = qemu_fdt_alloc_phandle(fdt);
> > + qemu_fdt_setprop_cell(fdt, nodepath, "phandle", phandle);
> > + qemu_fdt_setprop_cell(fdt, nodepath, "cache-level",
> > cache.level);
> > + qemu_fdt_setprop_cell(fdt, nodepath, "cache-size", cache.size);
> > + qemu_fdt_setprop_cell(fdt, nodepath, "cache-block-size",
> > cache.linesize);
> > + qemu_fdt_setprop_cell(fdt, nodepath, "cache-sets", cache.sets);
> > + qemu_fdt_setprop(fdt, nodepath, "cache-unified", NULL, 0);
> > + qemu_fdt_setprop_string(fdt, nodepath, "compatible", "cache");
> > + if (cache.level != 3) {
> > + /* top level cache doesn't have next-level-cache property
> > */
> > + qemu_fdt_setprop_cell(fdt, nodepath, "next-level-cache",
> > *next_level);
> > + }
> > +
> > + *next_level = phandle;
> > +}
> > +
> > +static bool add_cpu_cache_hierarchy(void *fdt, PPTTCPUCaches*
> > cache,
> > + uint32_t cache_cnt,
> > + uint32_t top_level,
> > + uint32_t bottom_level,
> > + uint32_t cpu_id,
> > + uint32_t *next_level) {
> > + bool found_cache = false;
> > + char *nodepath;
> > +
> > + for (int level = top_level; level >= bottom_level; level--) {
> > + for (int i = 0; i < cache_cnt; i++) {
> > + if (i != level) {
> > + continue;
> > + }
> > +
> > + nodepath = g_strdup_printf("/cpus/cpu@%d/l%d-cache",
> > + cpu_id, level);
> > + add_cache_node(fdt, nodepath, cache[i], next_level);
> > + found_cache = true;
> > + g_free(nodepath);
> > +
> > + }
> > + }
> > +
> > + return found_cache;
> > +}
> > +
> > +static void set_cache_properties(void *fdt, const char *nodename,
> > + const char *prefix, PPTTCPUCaches
> > cache) +{
> > + char prop_name[64];
> > +
> > + snprintf(prop_name, sizeof(prop_name), "%s-block-size",
> > prefix);
> > + qemu_fdt_setprop_cell(fdt, nodename, prop_name,
> > cache.linesize); +
> > + snprintf(prop_name, sizeof(prop_name), "%s-size", prefix);
> > + qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.size);
> > +
> > + snprintf(prop_name, sizeof(prop_name), "%s-sets", prefix);
> > + qemu_fdt_setprop_cell(fdt, nodename, prop_name, cache.sets);
> > +}
> > +
> > static void fdt_add_cpu_nodes(const VirtMachineState *vms)
> > {
> > int cpu;
> > int addr_cells = 1;
> > const MachineState *ms = MACHINE(vms);
> > + const MachineClass *mc = MACHINE_GET_CLASS(ms);
> > const VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
> > int smp_cpus = ms->smp.cpus;
> > + int socket_id, cluster_id, core_id;
> > + uint32_t next_level = 0;
> > + uint32_t socket_offset = 0, cluster_offset = 0, core_offset =
> > 0;
> > + int last_socket = -1, last_cluster = -1, last_core = -1;
> > + int top_node = 3, top_cluster = 3, top_core = 3;
> > + int bottom_node = 3, bottom_cluster = 3, bottom_core = 3;
>
> do these one var at a time.
sure, will fix.
>
> > + unsigned int num_cache;
> > + PPTTCPUCaches caches[16];
>
> why 16?
The code assumes 3 layers of cache max, so if we say at l1 we
got two 1 inst cache and 1 data cache, and then 1 unified for l2 and
one unified at l3 then there are 4 instances of caches. But then things
can grow, if each level has separate data and instruction then the
value is higher.
If CPUs end up having L4, and L5 then again higher ...
I think I assumed 7 layer of caches, and then had 16 as max number of
objects possible. The value can be lower, but then it is a
choice. If we fall back to 3 layers max, then 3*2 = 6 max objects would
be fair, but then any suggestions here?
>
> > + bool cache_created = false;
> > +
> > + num_cache = virt_get_caches(vms, caches);
> > +
> > + if (mc->smp_props.has_caches &&
> > + partial_cache_description(ms, caches, num_cache)) {
> > + error_setg(&error_fatal, "Missing cache description");
> > + return;
> > + }
> >
> > /*
> > * See Linux Documentation/devicetree/bindings/arm/cpus.yaml
> > @@ -456,9 +665,14 @@ static void fdt_add_cpu_nodes(const
> > VirtMachineState *vms) qemu_fdt_setprop_cell(ms->fdt, "/cpus",
> > "#size-cells", 0x0);
> > for (cpu = smp_cpus - 1; cpu >= 0; cpu--) {
> > + socket_id = cpu / (ms->smp.clusters * ms->smp.cores *
> > ms->smp.threads);
> > + cluster_id = cpu / (ms->smp.cores * ms->smp.threads) %
> > ms->smp.clusters;
> > + core_id = cpu / (ms->smp.threads) % ms->smp.cores;
> > +
> > char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
> > ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
> > CPUState *cs = CPU(armcpu);
> > + const char *prefix = NULL;
> >
> > qemu_fdt_add_subnode(ms->fdt, nodename);
> > qemu_fdt_setprop_string(ms->fdt, nodename, "device_type",
> > "cpu"); @@ -488,6 +702,130 @@ static void fdt_add_cpu_nodes(const
> > VirtMachineState *vms) qemu_fdt_alloc_phandle(ms->fdt));
> > }
> >
> > + if (!vmc->no_cpu_topology && num_cache) {
> > + for (uint8_t i = 0; i < num_cache; i++) {
> > + /* only level 1 in the CPU entry */
> > + if (caches[i].level > 1) {
> > + continue;
> > + }
> > +
> > + if (caches[i].type == INSTRUCTION) {
> > + prefix = "i-cache";
> > + } else if (caches[i].type == DATA) {
> > + prefix = "d-cache";
> > + } else if (caches[i].type == UNIFIED) {
> > + error_setg(&error_fatal,
> > + "Unified type is not implemented at
> > level %d",
> > + caches[i].level);
> > + return;
> > + } else {
> > + error_setg(&error_fatal, "Undefined cache
> > type");
> > + return;
> > + }
> > +
> > + set_cache_properties(ms->fdt, nodename, prefix,
> > caches[i]);
> > + }
> > + }
> > +
> > + if (socket_id != last_socket) {
> > + bottom_node = top_node;
> > + /* this assumes socket as the highest topological
> > level */
> > + socket_offset = 0;
> > + cluster_offset = 0;
> > + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_SOCKET)
> > &&
> > + find_the_lowest_level_cache_defined_at_level(ms,
> > + &bottom_node,
> > + CPU_TOPOLOGY_LEVEL_SOCKET)) {
> > +
> > + if (bottom_node == 1) {
> > + error_report(
> > + "Cannot share L1 at socket_id %d. DT
> > limiation on "
> > + "sharing at cache level = 1",
> > + socket_id);
> > + }
> > +
> > + cache_created = add_cpu_cache_hierarchy(ms->fdt,
> > caches,
> > + num_cache,
> > + top_node,
> > +
> > bottom_node, cpu,
> > +
> > &socket_offset); +
> > + if (!cache_created) {
> > + error_setg(&error_fatal,
> > + "Socket: No caches at levels %d-%d",
> > + top_node, bottom_node);
> > + return;
> > + }
> > +
> > + top_cluster = bottom_node - 1;
> > + }
> > +
> > + last_socket = socket_id;
> > + }
> > +
> > + if (cluster_id != last_cluster) {
> > + bottom_cluster = top_cluster;
> > + cluster_offset = socket_offset;
> > + core_offset = 0;
> > + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER)
> > &&
> > + find_the_lowest_level_cache_defined_at_level(ms,
> > + &bottom_cluster,
> > + CPU_TOPOLOGY_LEVEL_CLUSTER)) {
> > +
> > + cache_created = add_cpu_cache_hierarchy(ms->fdt,
> > caches,
> > + num_cache,
> > +
> > top_cluster,
> > +
> > bottom_cluster, cpu,
> > +
> > &cluster_offset);
> > + if (bottom_cluster == 1) {
> > + error_report(
> > + "Cannot share L1 at socket_id %d,
> > cluster_id %d. "
> > + "DT limitation on sharing at cache level =
> > 1.",
> > + socket_id, cluster_id);
> > + }
> > +
> > + if (!cache_created) {
> > + error_setg(&error_fatal,
> > + "Cluster: No caches at levels
> > %d-%d",
> > + top_cluster, bottom_cluster);
> > + return;
> > + }
> > +
> > + top_core = bottom_cluster - 1;
> > + } else if (top_cluster == bottom_node - 1) {
> > + top_core = bottom_node - 1;
> > + }
> > +
> > + last_cluster = cluster_id;
> > + }
> > +
> > + if (core_id != last_core) {
> > + bottom_core = top_core;
> > + core_offset = cluster_offset;
> > + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CORE) &&
> > + find_the_lowest_level_cache_defined_at_level(ms,
> > + &bottom_core,
> > + CPU_TOPOLOGY_LEVEL_CORE)) {
> > +
> > + if (bottom_core == 1) {
> > + bottom_core++;
> > + }
> > +
> > + cache_created = add_cpu_cache_hierarchy(ms->fdt,
> > + caches,
> > + num_cache,
> > + top_core,
> > +
> > bottom_core, cpu,
> > +
> > &core_offset);
> > + }
> > +
> > + last_core = core_id;
> > + }
> > +
> > + next_level = core_offset;
> > + qemu_fdt_setprop_cell(ms->fdt, nodename,
> > "next-level-cache",
> > + next_level);
> > +
> > g_free(nodename);
> > }
> >
> > @@ -3193,6 +3531,11 @@ static void
> > virt_machine_class_init(ObjectClass *oc, void *data) hc->unplug =
> > virt_machine_device_unplug_cb; mc->nvdimm_supported = true;
> > mc->smp_props.clusters_supported = true;
> > + /* Supported caches */
> > + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1D] = true;
> > + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1I] = true;
> > + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L2] = true;
> > + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L3] = true;
> > mc->auto_enable_numa_with_memhp = true;
> > mc->auto_enable_numa_with_memdev = true;
> > /* platform instead of architectural choice */
> > diff --git a/hw/cpu/core.c b/hw/cpu/core.c
> > index 495a5c30ffe1..3adfc3ca0001 100644
> > --- a/hw/cpu/core.c
> > +++ b/hw/cpu/core.c
> > @@ -102,4 +102,96 @@ static void cpu_core_register_types(void)
> > type_register_static(&cpu_core_type_info);
> > }
> >
> > +bool cache_described_at(const MachineState *ms, CpuTopologyLevel
> > level) +{
> > + if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3)
> > == level ||
> > + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2)
> > == level ||
> > + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I)
> > == level ||
> > + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D)
> > == level) {
> > + return true;
> > + }
> > + return false;
> > +}
> > +
> > +int partial_cache_description(const MachineState *ms,
> > PPTTCPUCaches *caches,
> > + int num_caches)
> > +{
> > + int level, c;
> > +
> > + for (level = 1; level < num_caches; level++) {
> > + for (c = 0; c < num_caches; c++) {
> > + if (caches[c].level != level) {
> > + continue;
> > + }
> > +
> > + switch (level) {
> > + case 1:
> > + /*
> > + * L1 cache is assumed to have both L1I and L1D
> > available.
> > + * Technically both need to be checked.
> > + */
> > + if (machine_get_cache_topo_level(ms,
> > +
> > CACHE_LEVEL_AND_TYPE_L1I) ==
> > + CPU_TOPOLOGY_LEVEL_DEFAULT) {
> > + return level;
> > + }
> > + break;
> > + case 2:
> > + if (machine_get_cache_topo_level(ms,
> > CACHE_LEVEL_AND_TYPE_L2) ==
> > + CPU_TOPOLOGY_LEVEL_DEFAULT) {
> > + return level;
> > + }
> > + break;
> > + case 3:
> > + if (machine_get_cache_topo_level(ms,
> > CACHE_LEVEL_AND_TYPE_L3) ==
> > + CPU_TOPOLOGY_LEVEL_DEFAULT) {
> > + return level;
> > + }
> > + break;
> > + }
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +/*
> > + * This function assumes l3 and l2 have unified cache and l1 is
> > split l1d
> > + * and l1i, and further prepares the lowest cache level for a
> > topology
> > + * level. The info will be fed to build_caches to create caches
> > at the
> > + * right level.
> > + */
> > +bool find_the_lowest_level_cache_defined_at_level(const
> > MachineState *ms,
> > + int *level_found,
> > + CpuTopologyLevel
> > topo_level) { +
> > + CpuTopologyLevel level;
> > +
> > + level = machine_get_cache_topo_level(ms,
> > CACHE_LEVEL_AND_TYPE_L1I);
> > + if (level == topo_level) {
> > + *level_found = 1;
> > + return true;
> > + }
> > +
> > + level = machine_get_cache_topo_level(ms,
> > CACHE_LEVEL_AND_TYPE_L1D);
> > + if (level == topo_level) {
> > + *level_found = 1;
> > + return true;
> > + }
> > +
> > + level = machine_get_cache_topo_level(ms,
> > CACHE_LEVEL_AND_TYPE_L2);
> > + if (level == topo_level) {
> > + *level_found = 2;
> > + return true;
> > + }
> > +
> > + level = machine_get_cache_topo_level(ms,
> > CACHE_LEVEL_AND_TYPE_L3);
> > + if (level == topo_level) {
> > + *level_found = 3;
> > + return true;
> > + }
> > +
> > + return false;
> > +}
> > +
> > type_init(cpu_core_register_types)
> > diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
> > index c8e94e6aedc9..68ff99d6806d 100644
> > --- a/include/hw/arm/virt.h
> > +++ b/include/hw/arm/virt.h
> > @@ -39,6 +39,7 @@
> > #include "system/kvm.h"
> > #include "hw/intc/arm_gicv3_common.h"
> > #include "qom/object.h"
> > +#include "hw/cpu/core.h"
> >
> > #define NUM_GICV2M_SPIS 64
> > #define NUM_VIRTIO_TRANSPORTS 32
> > @@ -50,6 +51,8 @@
> > /* GPIO pins */
> > #define GPIO_PIN_POWER_BUTTON 3
> >
> > +#define CPU_MAX_CACHES 16
> > +
> > enum {
> > VIRT_FLASH,
> > VIRT_MEM,
> > @@ -189,6 +192,7 @@ OBJECT_DECLARE_TYPE(VirtMachineState,
> > VirtMachineClass, VIRT_MACHINE)
> > void virt_acpi_setup(VirtMachineState *vms);
> > bool virt_is_acpi_enabled(VirtMachineState *vms);
> > +unsigned int virt_get_caches(const VirtMachineState *vms,
> > PPTTCPUCaches *caches);
> > /* Return number of redistributors that fit in the specified
> > region */ static uint32_t virt_redist_capacity(VirtMachineState
> > *vms, int region) diff --git a/include/hw/cpu/core.h
> > b/include/hw/cpu/core.h index 98ab91647eb2..a90b708b835b 100644
> > --- a/include/hw/cpu/core.h
> > +++ b/include/hw/cpu/core.h
> > @@ -25,6 +25,31 @@ struct CPUCore {
> > int nr_threads;
> > };
> >
> > +typedef enum CPUCacheType {
> > + DATA,
> > + INSTRUCTION,
> > + UNIFIED,
> > +} PPTTCPUCacheType;
>
> Given specific values matter, you should specify them.
> Also, please prefix names sensibly and consistently:
> CPUCoreCacheType CPU_CORE_DATA and so on.
>
>
>
> > +
> > +typedef struct PPTTCPUCaches {
> > + PPTTCPUCacheType type;
> > + uint32_t sets;
> > + uint32_t size;
> > + uint32_t level;
> > + uint16_t linesize;
> > + uint8_t attributes; /* write policy: 0x0 write back, 0x1 write
> > through */
> > + uint8_t associativity;
> > +} PPTTCPUCaches;
> > +
> > +int partial_cache_description(const MachineState *ms,
> > PPTTCPUCaches *caches,
> > + int num_caches);
> > +
> > +bool cache_described_at(const MachineState *ms, CpuTopologyLevel
> > level); +
> > +bool find_the_lowest_level_cache_defined_at_level(const
> > MachineState *ms,
> > + int *level_found,
> > + CpuTopologyLevel
> > topo_level); +
> > /* Note: topology field names need to be kept in sync with
> > * 'CpuInstanceProperties' */
>
> same here, prefix everything with cpu_core CPUCore etc.
>
> > --
> > 2.34.1
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v10 3/6] bios-tables-test: prepare to change ARM ACPI virt PPTT
2025-04-28 11:07 [PATCH v10 0/6] Specifying cache topology on ARM Alireza Sanaee via
2025-04-28 11:07 ` Alireza Sanaee via
2025-04-28 11:07 ` Alireza Sanaee via
@ 2025-04-28 11:07 ` Alireza Sanaee via
2025-04-28 11:07 ` Alireza Sanaee via
` (2 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
Prepare to update `build_pptt` function to add cache description
functionalities, thus add binaries in this patch.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
---
tests/qtest/bios-tables-test-allowed-diff.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index dfb8523c8bf4..e84d6c695520 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1 +1,4 @@
/* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/aarch64/virt/PPTT",
+"tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt",
+"tests/data/acpi/aarch64/virt/PPTT.topology",
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v10 4/6] hw/acpi/aml-build.c: add cache hierarchy to pptt table
2025-04-28 11:07 [PATCH v10 0/6] Specifying cache topology on ARM Alireza Sanaee via
@ 2025-04-28 11:07 ` Alireza Sanaee via
2025-04-28 11:07 ` Alireza Sanaee via
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
Add cache topology to PPTT table. With this patch, both ACPI PPTT table
and device tree will represent the same cache topology given users
input.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
Co-developed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
hw/acpi/aml-build.c | 201 ++++++++++++++++++++++++++++++++-
hw/arm/virt-acpi-build.c | 8 +-
hw/loongarch/virt-acpi-build.c | 2 +-
include/hw/acpi/aml-build.h | 4 +-
include/hw/cpu/core.h | 1 +
5 files changed, 208 insertions(+), 8 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 3010325ca423..53870765a351 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -2046,6 +2046,103 @@ void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms,
acpi_table_end(linker, &table);
}
+static void build_cache_nodes(GArray *tbl, PPTTCPUCaches *cache,
+ uint32_t next_offset)
+{
+ int val;
+
+ /* Type 1 - cache */
+ build_append_byte(tbl, 1);
+ /* Length */
+ build_append_byte(tbl, 28);
+ /* Reserved */
+ build_append_int_noprefix(tbl, 0, 2);
+ /* Flags - everything except possibly the ID */
+ build_append_int_noprefix(tbl, 0xff, 4);
+ /* Offset of next cache up */
+ build_append_int_noprefix(tbl, next_offset, 4);
+ build_append_int_noprefix(tbl, cache->size, 4);
+ build_append_int_noprefix(tbl, cache->sets, 4);
+ build_append_byte(tbl, cache->associativity);
+ val = 0x3;
+ switch (cache->type) {
+ case INSTRUCTION:
+ val |= (1 << 2);
+ break;
+ case DATA:
+ val |= (0 << 2); /* Data */
+ break;
+ case UNIFIED:
+ val |= (3 << 2); /* Unified */
+ break;
+ }
+ build_append_byte(tbl, val);
+ build_append_int_noprefix(tbl, cache->linesize, 2);
+}
+
+/*
+ * builds caches from the top level (`level_high` parameter) to the bottom
+ * level (`level_low` parameter). It searches for caches found in
+ * systems' registers, and fills up the table. Then it updates the
+ * `data_offset` and `instr_offset` parameters with the offset of the data
+ * and instruction caches of the lowest level, respectively.
+ */
+static bool build_caches(GArray *table_data, uint32_t pptt_start,
+ int num_caches, PPTTCPUCaches *caches,
+ uint8_t level_high, /* Inclusive */
+ uint8_t level_low, /* Inclusive */
+ uint32_t *data_offset,
+ uint32_t *instr_offset)
+{
+ uint32_t next_level_offset_data = 0, next_level_offset_instruction = 0;
+ uint32_t this_offset, next_offset = 0;
+ int c, level;
+ bool found_cache = false;
+
+ /* Walk caches from top to bottom */
+ for (level = level_high; level >= level_low; level--) {
+ for (c = 0; c < num_caches; c++) {
+ if (caches[c].level != level) {
+ continue;
+ }
+
+ /* Assume only unified above l1 for now */
+ this_offset = table_data->len - pptt_start;
+ switch (caches[c].type) {
+ case INSTRUCTION:
+ next_offset = next_level_offset_instruction;
+ break;
+ case DATA:
+ next_offset = next_level_offset_data;
+ break;
+ case UNIFIED:
+ /* Either is fine here */
+ next_offset = next_level_offset_instruction;
+ break;
+ }
+ build_cache_nodes(table_data, &caches[c], next_offset);
+ switch (caches[c].type) {
+ case INSTRUCTION:
+ next_level_offset_instruction = this_offset;
+ break;
+ case DATA:
+ next_level_offset_data = this_offset;
+ break;
+ case UNIFIED:
+ next_level_offset_instruction = this_offset;
+ next_level_offset_data = this_offset;
+ break;
+ }
+ *data_offset = next_level_offset_data;
+ *instr_offset = next_level_offset_instruction;
+
+ found_cache = true;
+ }
+ }
+
+ return found_cache;
+}
+
/*
* ACPI spec, Revision 6.3
* 5.2.29.1 Processor hierarchy node structure (Type 0)
@@ -2146,15 +2243,24 @@ void build_spcr(GArray *table_data, BIOSLinker *linker,
* 5.2.29 Processor Properties Topology Table (PPTT)
*/
void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
- const char *oem_id, const char *oem_table_id)
+ const char *oem_id, const char *oem_table_id,
+ int num_caches, PPTTCPUCaches *caches)
{
MachineClass *mc = MACHINE_GET_CLASS(ms);
CPUArchIdList *cpus = ms->possible_cpus;
+ uint32_t core_data_offset = 0, core_instr_offset = 0;
+ uint32_t cluster_instr_offset = 0, cluster_data_offset = 0;
+ uint32_t node_data_offset = 0, node_instr_offset = 0;
+ int top_node = 3, top_cluster = 3, top_core = 3;
+ int bottom_node = 3, bottom_cluster = 3, bottom_core = 3;
int64_t socket_id = -1, cluster_id = -1, core_id = -1;
uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0;
uint32_t pptt_start = table_data->len;
uint32_t root_offset;
int n;
+ uint32_t priv_rsrc[2];
+ uint32_t num_priv = 0;
+
AcpiTable table = { .sig = "PPTT", .rev = 2,
.oem_id = oem_id, .oem_table_id = oem_table_id };
@@ -2184,11 +2290,35 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
socket_id = cpus->cpus[n].props.socket_id;
cluster_id = -1;
core_id = -1;
+ bottom_node = top_node;
+ num_priv = 0;
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_SOCKET) &&
+ find_the_lowest_level_cache_defined_at_level(
+ ms,
+ &bottom_node,
+ CPU_TOPOLOGY_LEVEL_SOCKET))
+ {
+ build_caches(table_data, pptt_start,
+ num_caches, caches,
+ top_node, bottom_node,
+ &node_data_offset, &node_instr_offset);
+
+ priv_rsrc[0] = node_instr_offset;
+ priv_rsrc[1] = node_data_offset;
+
+ if (node_instr_offset || node_data_offset) {
+ num_priv = node_instr_offset == node_data_offset ? 1 : 2;
+ }
+
+ top_cluster = bottom_node - 1;
+ }
+
socket_offset = table_data->len - pptt_start;
build_processor_hierarchy_node(table_data,
(1 << 0) | /* Physical package */
(1 << 4), /* Identical Implementation */
- root_offset, socket_id, NULL, 0);
+ root_offset, socket_id,
+ priv_rsrc, num_priv);
}
if (mc->smp_props.clusters_supported && mc->smp_props.has_clusters) {
@@ -2196,21 +2326,81 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
assert(cpus->cpus[n].props.cluster_id > cluster_id);
cluster_id = cpus->cpus[n].props.cluster_id;
core_id = -1;
+ bottom_cluster = top_cluster;
+ num_priv = 0;
+
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER) &&
+ find_the_lowest_level_cache_defined_at_level(
+ ms,
+ &bottom_cluster,
+ CPU_TOPOLOGY_LEVEL_CLUSTER))
+ {
+
+ build_caches(table_data, pptt_start,
+ num_caches, caches, top_cluster,
+ bottom_cluster, &cluster_data_offset,
+ &cluster_instr_offset);
+
+ priv_rsrc[0] = cluster_instr_offset;
+ priv_rsrc[1] = cluster_data_offset;
+
+ if (cluster_instr_offset || cluster_data_offset) {
+ num_priv =
+ cluster_instr_offset == cluster_data_offset ? 1 : 2;
+ }
+
+ top_core = bottom_cluster - 1;
+ } else if (top_cluster == bottom_node - 1) {
+ /* socket cache but no cluster cache */
+ top_core = bottom_node - 1;
+ }
+
cluster_offset = table_data->len - pptt_start;
build_processor_hierarchy_node(table_data,
(0 << 0) | /* Not a physical package */
(1 << 4), /* Identical Implementation */
- socket_offset, cluster_id, NULL, 0);
+ socket_offset, cluster_id,
+ priv_rsrc, num_priv);
}
} else {
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER)) {
+ error_setg(&error_fatal, "Not clusters found for the cache");
+ return;
+ }
+
cluster_offset = socket_offset;
+ top_core = bottom_node - 1; /* there is no cluster */
}
+ if (cpus->cpus[n].props.core_id != core_id) {
+ bottom_core = top_core;
+ num_priv = 0;
+
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CORE) &&
+ find_the_lowest_level_cache_defined_at_level(
+ ms,
+ &bottom_core,
+ CPU_TOPOLOGY_LEVEL_CORE))
+ {
+ build_caches(table_data, pptt_start,
+ num_caches, caches,
+ top_core, bottom_core,
+ &core_data_offset, &core_instr_offset);
+
+ priv_rsrc[0] = core_instr_offset;
+ priv_rsrc[1] = core_data_offset;
+
+ num_priv = core_instr_offset == core_data_offset ? 1 : 2;
+ }
+ }
+
+
if (ms->smp.threads == 1) {
build_processor_hierarchy_node(table_data,
(1 << 1) | /* ACPI Processor ID valid */
(1 << 3), /* Node is a Leaf */
- cluster_offset, n, NULL, 0);
+ cluster_offset, n,
+ priv_rsrc, num_priv);
} else {
if (cpus->cpus[n].props.core_id != core_id) {
assert(cpus->cpus[n].props.core_id > core_id);
@@ -2219,7 +2409,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
build_processor_hierarchy_node(table_data,
(0 << 0) | /* Not a physical package */
(1 << 4), /* Identical Implementation */
- cluster_offset, core_id, NULL, 0);
+ cluster_offset, core_id,
+ priv_rsrc, num_priv);
}
build_processor_hierarchy_node(table_data,
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 3ac8f8e17861..9c17d6b579af 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -902,6 +902,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
GArray *tables_blob = tables->table_data;
MachineState *ms = MACHINE(vms);
+ PPTTCPUCaches caches[CPU_MAX_CACHES]; /* Can select up to 16 */
+ unsigned int num_caches;
+
+ num_caches = virt_get_caches(vms, caches);
+
table_offsets = g_array_new(false, true /* clear */,
sizeof(uint32_t));
@@ -923,7 +928,8 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
if (!vmc->no_cpu_topology) {
acpi_add_table(table_offsets, tables_blob);
build_pptt(tables_blob, tables->linker, ms,
- vms->oem_id, vms->oem_table_id);
+ vms->oem_id, vms->oem_table_id,
+ num_caches, caches);
}
acpi_add_table(table_offsets, tables_blob);
diff --git a/hw/loongarch/virt-acpi-build.c b/hw/loongarch/virt-acpi-build.c
index fced6c445ac6..68ccab2dd214 100644
--- a/hw/loongarch/virt-acpi-build.c
+++ b/hw/loongarch/virt-acpi-build.c
@@ -552,7 +552,7 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_pptt(tables_blob, tables->linker, machine,
- lvms->oem_id, lvms->oem_table_id);
+ lvms->oem_id, lvms->oem_table_id, 0, NULL);
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index c18f68134246..e0fb51238204 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -3,6 +3,7 @@
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/bios-linker-loader.h"
+#include "hw/cpu/core.h"
#define ACPI_BUILD_APPNAME6 "BOCHS "
#define ACPI_BUILD_APPNAME8 "BXPC "
@@ -497,7 +498,8 @@ void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms,
const char *oem_id, const char *oem_table_id);
void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
- const char *oem_id, const char *oem_table_id);
+ const char *oem_id, const char *oem_table_id,
+ int num_caches, PPTTCPUCaches *caches);
void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
const char *oem_id, const char *oem_table_id);
diff --git a/include/hw/cpu/core.h b/include/hw/cpu/core.h
index a90b708b835b..f03496355d50 100644
--- a/include/hw/cpu/core.h
+++ b/include/hw/cpu/core.h
@@ -11,6 +11,7 @@
#include "hw/qdev-core.h"
#include "qom/object.h"
+#include "qapi/qapi-types-machine-common.h"
#define TYPE_CPU_CORE "cpu-core"
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v10 4/6] hw/acpi/aml-build.c: add cache hierarchy to pptt table
@ 2025-04-28 11:07 ` Alireza Sanaee via
0 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
Add cache topology to PPTT table. With this patch, both ACPI PPTT table
and device tree will represent the same cache topology given users
input.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
Co-developed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Jonathan Cameron <jonathan.cameron@huawei.com>
---
hw/acpi/aml-build.c | 201 ++++++++++++++++++++++++++++++++-
hw/arm/virt-acpi-build.c | 8 +-
hw/loongarch/virt-acpi-build.c | 2 +-
include/hw/acpi/aml-build.h | 4 +-
include/hw/cpu/core.h | 1 +
5 files changed, 208 insertions(+), 8 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 3010325ca423..53870765a351 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -2046,6 +2046,103 @@ void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms,
acpi_table_end(linker, &table);
}
+static void build_cache_nodes(GArray *tbl, PPTTCPUCaches *cache,
+ uint32_t next_offset)
+{
+ int val;
+
+ /* Type 1 - cache */
+ build_append_byte(tbl, 1);
+ /* Length */
+ build_append_byte(tbl, 28);
+ /* Reserved */
+ build_append_int_noprefix(tbl, 0, 2);
+ /* Flags - everything except possibly the ID */
+ build_append_int_noprefix(tbl, 0xff, 4);
+ /* Offset of next cache up */
+ build_append_int_noprefix(tbl, next_offset, 4);
+ build_append_int_noprefix(tbl, cache->size, 4);
+ build_append_int_noprefix(tbl, cache->sets, 4);
+ build_append_byte(tbl, cache->associativity);
+ val = 0x3;
+ switch (cache->type) {
+ case INSTRUCTION:
+ val |= (1 << 2);
+ break;
+ case DATA:
+ val |= (0 << 2); /* Data */
+ break;
+ case UNIFIED:
+ val |= (3 << 2); /* Unified */
+ break;
+ }
+ build_append_byte(tbl, val);
+ build_append_int_noprefix(tbl, cache->linesize, 2);
+}
+
+/*
+ * builds caches from the top level (`level_high` parameter) to the bottom
+ * level (`level_low` parameter). It searches for caches found in
+ * systems' registers, and fills up the table. Then it updates the
+ * `data_offset` and `instr_offset` parameters with the offset of the data
+ * and instruction caches of the lowest level, respectively.
+ */
+static bool build_caches(GArray *table_data, uint32_t pptt_start,
+ int num_caches, PPTTCPUCaches *caches,
+ uint8_t level_high, /* Inclusive */
+ uint8_t level_low, /* Inclusive */
+ uint32_t *data_offset,
+ uint32_t *instr_offset)
+{
+ uint32_t next_level_offset_data = 0, next_level_offset_instruction = 0;
+ uint32_t this_offset, next_offset = 0;
+ int c, level;
+ bool found_cache = false;
+
+ /* Walk caches from top to bottom */
+ for (level = level_high; level >= level_low; level--) {
+ for (c = 0; c < num_caches; c++) {
+ if (caches[c].level != level) {
+ continue;
+ }
+
+ /* Assume only unified above l1 for now */
+ this_offset = table_data->len - pptt_start;
+ switch (caches[c].type) {
+ case INSTRUCTION:
+ next_offset = next_level_offset_instruction;
+ break;
+ case DATA:
+ next_offset = next_level_offset_data;
+ break;
+ case UNIFIED:
+ /* Either is fine here */
+ next_offset = next_level_offset_instruction;
+ break;
+ }
+ build_cache_nodes(table_data, &caches[c], next_offset);
+ switch (caches[c].type) {
+ case INSTRUCTION:
+ next_level_offset_instruction = this_offset;
+ break;
+ case DATA:
+ next_level_offset_data = this_offset;
+ break;
+ case UNIFIED:
+ next_level_offset_instruction = this_offset;
+ next_level_offset_data = this_offset;
+ break;
+ }
+ *data_offset = next_level_offset_data;
+ *instr_offset = next_level_offset_instruction;
+
+ found_cache = true;
+ }
+ }
+
+ return found_cache;
+}
+
/*
* ACPI spec, Revision 6.3
* 5.2.29.1 Processor hierarchy node structure (Type 0)
@@ -2146,15 +2243,24 @@ void build_spcr(GArray *table_data, BIOSLinker *linker,
* 5.2.29 Processor Properties Topology Table (PPTT)
*/
void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
- const char *oem_id, const char *oem_table_id)
+ const char *oem_id, const char *oem_table_id,
+ int num_caches, PPTTCPUCaches *caches)
{
MachineClass *mc = MACHINE_GET_CLASS(ms);
CPUArchIdList *cpus = ms->possible_cpus;
+ uint32_t core_data_offset = 0, core_instr_offset = 0;
+ uint32_t cluster_instr_offset = 0, cluster_data_offset = 0;
+ uint32_t node_data_offset = 0, node_instr_offset = 0;
+ int top_node = 3, top_cluster = 3, top_core = 3;
+ int bottom_node = 3, bottom_cluster = 3, bottom_core = 3;
int64_t socket_id = -1, cluster_id = -1, core_id = -1;
uint32_t socket_offset = 0, cluster_offset = 0, core_offset = 0;
uint32_t pptt_start = table_data->len;
uint32_t root_offset;
int n;
+ uint32_t priv_rsrc[2];
+ uint32_t num_priv = 0;
+
AcpiTable table = { .sig = "PPTT", .rev = 2,
.oem_id = oem_id, .oem_table_id = oem_table_id };
@@ -2184,11 +2290,35 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
socket_id = cpus->cpus[n].props.socket_id;
cluster_id = -1;
core_id = -1;
+ bottom_node = top_node;
+ num_priv = 0;
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_SOCKET) &&
+ find_the_lowest_level_cache_defined_at_level(
+ ms,
+ &bottom_node,
+ CPU_TOPOLOGY_LEVEL_SOCKET))
+ {
+ build_caches(table_data, pptt_start,
+ num_caches, caches,
+ top_node, bottom_node,
+ &node_data_offset, &node_instr_offset);
+
+ priv_rsrc[0] = node_instr_offset;
+ priv_rsrc[1] = node_data_offset;
+
+ if (node_instr_offset || node_data_offset) {
+ num_priv = node_instr_offset == node_data_offset ? 1 : 2;
+ }
+
+ top_cluster = bottom_node - 1;
+ }
+
socket_offset = table_data->len - pptt_start;
build_processor_hierarchy_node(table_data,
(1 << 0) | /* Physical package */
(1 << 4), /* Identical Implementation */
- root_offset, socket_id, NULL, 0);
+ root_offset, socket_id,
+ priv_rsrc, num_priv);
}
if (mc->smp_props.clusters_supported && mc->smp_props.has_clusters) {
@@ -2196,21 +2326,81 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
assert(cpus->cpus[n].props.cluster_id > cluster_id);
cluster_id = cpus->cpus[n].props.cluster_id;
core_id = -1;
+ bottom_cluster = top_cluster;
+ num_priv = 0;
+
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER) &&
+ find_the_lowest_level_cache_defined_at_level(
+ ms,
+ &bottom_cluster,
+ CPU_TOPOLOGY_LEVEL_CLUSTER))
+ {
+
+ build_caches(table_data, pptt_start,
+ num_caches, caches, top_cluster,
+ bottom_cluster, &cluster_data_offset,
+ &cluster_instr_offset);
+
+ priv_rsrc[0] = cluster_instr_offset;
+ priv_rsrc[1] = cluster_data_offset;
+
+ if (cluster_instr_offset || cluster_data_offset) {
+ num_priv =
+ cluster_instr_offset == cluster_data_offset ? 1 : 2;
+ }
+
+ top_core = bottom_cluster - 1;
+ } else if (top_cluster == bottom_node - 1) {
+ /* socket cache but no cluster cache */
+ top_core = bottom_node - 1;
+ }
+
cluster_offset = table_data->len - pptt_start;
build_processor_hierarchy_node(table_data,
(0 << 0) | /* Not a physical package */
(1 << 4), /* Identical Implementation */
- socket_offset, cluster_id, NULL, 0);
+ socket_offset, cluster_id,
+ priv_rsrc, num_priv);
}
} else {
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER)) {
+ error_setg(&error_fatal, "Not clusters found for the cache");
+ return;
+ }
+
cluster_offset = socket_offset;
+ top_core = bottom_node - 1; /* there is no cluster */
}
+ if (cpus->cpus[n].props.core_id != core_id) {
+ bottom_core = top_core;
+ num_priv = 0;
+
+ if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CORE) &&
+ find_the_lowest_level_cache_defined_at_level(
+ ms,
+ &bottom_core,
+ CPU_TOPOLOGY_LEVEL_CORE))
+ {
+ build_caches(table_data, pptt_start,
+ num_caches, caches,
+ top_core, bottom_core,
+ &core_data_offset, &core_instr_offset);
+
+ priv_rsrc[0] = core_instr_offset;
+ priv_rsrc[1] = core_data_offset;
+
+ num_priv = core_instr_offset == core_data_offset ? 1 : 2;
+ }
+ }
+
+
if (ms->smp.threads == 1) {
build_processor_hierarchy_node(table_data,
(1 << 1) | /* ACPI Processor ID valid */
(1 << 3), /* Node is a Leaf */
- cluster_offset, n, NULL, 0);
+ cluster_offset, n,
+ priv_rsrc, num_priv);
} else {
if (cpus->cpus[n].props.core_id != core_id) {
assert(cpus->cpus[n].props.core_id > core_id);
@@ -2219,7 +2409,8 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
build_processor_hierarchy_node(table_data,
(0 << 0) | /* Not a physical package */
(1 << 4), /* Identical Implementation */
- cluster_offset, core_id, NULL, 0);
+ cluster_offset, core_id,
+ priv_rsrc, num_priv);
}
build_processor_hierarchy_node(table_data,
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 3ac8f8e17861..9c17d6b579af 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -902,6 +902,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
GArray *tables_blob = tables->table_data;
MachineState *ms = MACHINE(vms);
+ PPTTCPUCaches caches[CPU_MAX_CACHES]; /* Can select up to 16 */
+ unsigned int num_caches;
+
+ num_caches = virt_get_caches(vms, caches);
+
table_offsets = g_array_new(false, true /* clear */,
sizeof(uint32_t));
@@ -923,7 +928,8 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
if (!vmc->no_cpu_topology) {
acpi_add_table(table_offsets, tables_blob);
build_pptt(tables_blob, tables->linker, ms,
- vms->oem_id, vms->oem_table_id);
+ vms->oem_id, vms->oem_table_id,
+ num_caches, caches);
}
acpi_add_table(table_offsets, tables_blob);
diff --git a/hw/loongarch/virt-acpi-build.c b/hw/loongarch/virt-acpi-build.c
index fced6c445ac6..68ccab2dd214 100644
--- a/hw/loongarch/virt-acpi-build.c
+++ b/hw/loongarch/virt-acpi-build.c
@@ -552,7 +552,7 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_pptt(tables_blob, tables->linker, machine,
- lvms->oem_id, lvms->oem_table_id);
+ lvms->oem_id, lvms->oem_table_id, 0, NULL);
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index c18f68134246..e0fb51238204 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -3,6 +3,7 @@
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/bios-linker-loader.h"
+#include "hw/cpu/core.h"
#define ACPI_BUILD_APPNAME6 "BOCHS "
#define ACPI_BUILD_APPNAME8 "BXPC "
@@ -497,7 +498,8 @@ void build_slit(GArray *table_data, BIOSLinker *linker, MachineState *ms,
const char *oem_id, const char *oem_table_id);
void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms,
- const char *oem_id, const char *oem_table_id);
+ const char *oem_id, const char *oem_table_id,
+ int num_caches, PPTTCPUCaches *caches);
void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
const char *oem_id, const char *oem_table_id);
diff --git a/include/hw/cpu/core.h b/include/hw/cpu/core.h
index a90b708b835b..f03496355d50 100644
--- a/include/hw/cpu/core.h
+++ b/include/hw/cpu/core.h
@@ -11,6 +11,7 @@
#include "hw/qdev-core.h"
#include "qom/object.h"
+#include "qapi/qapi-types-machine-common.h"
#define TYPE_CPU_CORE "cpu-core"
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 5/6] tests/qtest/bios-table-test: testing new ARM ACPI PPTT tables
2025-04-28 11:07 [PATCH v10 0/6] Specifying cache topology on ARM Alireza Sanaee via
@ 2025-04-28 11:07 ` Alireza Sanaee via
2025-04-28 11:07 ` Alireza Sanaee via
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
Test new PPTT table with cache representation.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
tests/qtest/bios-tables-test.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 0a333ec43536..8218b39de7cb 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -1846,7 +1846,10 @@ static void test_acpi_aarch64_virt_tcg_acpi_hmat(void)
data.variant = ".acpihmatvirt";
- test_acpi_one(" -machine hmat=on"
+ test_acpi_one(" -machine hmat=on "
+ "-M virt,smp-cache.0.cache=l1i,smp-cache.0.topology=core,"
+ "smp-cache.1.cache=l1d,smp-cache.1.topology=core,"
+ "smp-cache.2.cache=l2,smp-cache.2.topology=core "
" -cpu cortex-a57"
" -smp 4,sockets=2"
" -m 384M"
@@ -2123,6 +2126,9 @@ static void test_acpi_aarch64_virt_tcg(void)
data.smbios_cpu_max_speed = 2900;
data.smbios_cpu_curr_speed = 2700;
test_acpi_one("-cpu cortex-a57 "
+ "-M virt,smp-cache.0.cache=l1i,smp-cache.0.topology=core,"
+ "smp-cache.1.cache=l1d,smp-cache.1.topology=core,"
+ "smp-cache.2.cache=l2,smp-cache.2.topology=core "
"-smbios type=4,max-speed=2900,current-speed=2700", &data);
free_test_data(&data);
}
@@ -2142,6 +2148,9 @@ static void test_acpi_aarch64_virt_tcg_topology(void)
};
test_acpi_one("-cpu cortex-a57 "
+ "-M virt,smp-cache.0.cache=l1i,smp-cache.0.topology=core,"
+ "smp-cache.1.cache=l1d,smp-cache.1.topology=core,"
+ "smp-cache.2.cache=l2,smp-cache.2.topology=core "
"-smp sockets=1,clusters=2,cores=2,threads=2", &data);
free_test_data(&data);
}
@@ -2227,6 +2236,9 @@ static void test_acpi_aarch64_virt_viot(void)
};
test_acpi_one("-cpu cortex-a57 "
+ "-M virt,smp-cache.0.cache=l1i,smp-cache.0.topology=core,"
+ "smp-cache.1.cache=l1d,smp-cache.1.topology=core,"
+ "smp-cache.2.cache=l2,smp-cache.2.topology=core "
"-device virtio-iommu-pci", &data);
free_test_data(&data);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v10 5/6] tests/qtest/bios-table-test: testing new ARM ACPI PPTT tables
@ 2025-04-28 11:07 ` Alireza Sanaee via
0 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
Test new PPTT table with cache representation.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
tests/qtest/bios-tables-test.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 0a333ec43536..8218b39de7cb 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -1846,7 +1846,10 @@ static void test_acpi_aarch64_virt_tcg_acpi_hmat(void)
data.variant = ".acpihmatvirt";
- test_acpi_one(" -machine hmat=on"
+ test_acpi_one(" -machine hmat=on "
+ "-M virt,smp-cache.0.cache=l1i,smp-cache.0.topology=core,"
+ "smp-cache.1.cache=l1d,smp-cache.1.topology=core,"
+ "smp-cache.2.cache=l2,smp-cache.2.topology=core "
" -cpu cortex-a57"
" -smp 4,sockets=2"
" -m 384M"
@@ -2123,6 +2126,9 @@ static void test_acpi_aarch64_virt_tcg(void)
data.smbios_cpu_max_speed = 2900;
data.smbios_cpu_curr_speed = 2700;
test_acpi_one("-cpu cortex-a57 "
+ "-M virt,smp-cache.0.cache=l1i,smp-cache.0.topology=core,"
+ "smp-cache.1.cache=l1d,smp-cache.1.topology=core,"
+ "smp-cache.2.cache=l2,smp-cache.2.topology=core "
"-smbios type=4,max-speed=2900,current-speed=2700", &data);
free_test_data(&data);
}
@@ -2142,6 +2148,9 @@ static void test_acpi_aarch64_virt_tcg_topology(void)
};
test_acpi_one("-cpu cortex-a57 "
+ "-M virt,smp-cache.0.cache=l1i,smp-cache.0.topology=core,"
+ "smp-cache.1.cache=l1d,smp-cache.1.topology=core,"
+ "smp-cache.2.cache=l2,smp-cache.2.topology=core "
"-smp sockets=1,clusters=2,cores=2,threads=2", &data);
free_test_data(&data);
}
@@ -2227,6 +2236,9 @@ static void test_acpi_aarch64_virt_viot(void)
};
test_acpi_one("-cpu cortex-a57 "
+ "-M virt,smp-cache.0.cache=l1i,smp-cache.0.topology=core,"
+ "smp-cache.1.cache=l1d,smp-cache.1.topology=core,"
+ "smp-cache.2.cache=l2,smp-cache.2.topology=core "
"-device virtio-iommu-pci", &data);
free_test_data(&data);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 6/6] Update the ACPI tables according to the acpi aml_build changes
2025-04-28 11:07 [PATCH v10 0/6] Specifying cache topology on ARM Alireza Sanaee via
@ 2025-04-28 11:07 ` Alireza Sanaee via
2025-04-28 11:07 ` Alireza Sanaee via
` (4 subsequent siblings)
5 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20200925 (64-bit version)
* Copyright (c) 2000 - 2020 Intel Corporation
*
- * Disassembly of tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt, Thu Apr 24 19:37:19 2025
+ * Disassembly of /tmp/aml-X03H52, Thu Apr 24 19:37:19 2025
*
* ACPI Data Table [PPTT]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[000h 0000 4] Signature : "PPTT" [Processor Properties Topology Table]
-[004h 0004 4] Table Length : 000000B0
+[004h 0004 4] Table Length : 000001F0
[008h 0008 1] Revision : 02
-[009h 0009 1] Checksum : 0D
+[009h 0009 1] Checksum : C6
[00Ah 0010 6] Oem ID : "BOCHS "
[010h 0016 8] Oem Table ID : "BXPC "
[018h 0024 4] Oem Revision : 00000001
[01Ch 0028 4] Asl Compiler ID : "BXPC"
[020h 0032 4] Asl Compiler Revision : 00000001
[024h 0036 1] Subtable Type : 00 [Processor Hierarchy Node]
[025h 0037 1] Length : 14
[026h 0038 2] Reserved : 0000
[028h 0040 4] Flags (decoded below) : 00000011
Physical package : 1
ACPI Processor ID valid : 0
Processor is a thread : 0
Node is a leaf : 0
Identical Implementation : 1
@@ -34,94 +34,72 @@
[030h 0048 4] ACPI Processor ID : 00000000
[034h 0052 4] Private Resource Number : 00000000
[038h 0056 1] Subtable Type : 00 [Processor Hierarchy Node]
[039h 0057 1] Length : 14
[03Ah 0058 2] Reserved : 0000
[03Ch 0060 4] Flags (decoded below) : 00000011
Physical package : 1
ACPI Processor ID valid : 0
Processor is a thread : 0
Node is a leaf : 0
Identical Implementation : 1
[040h 0064 4] Parent : 00000024
[044h 0068 4] ACPI Processor ID : 00000000
[048h 0072 4] Private Resource Number : 00000000
-[04Ch 0076 1] Subtable Type : 00 [Processor Hierarchy Node]
-[04Dh 0077 1] Length : 14
+[04Ch 0076 1] Subtable Type : 01 [Cache Type]
+[04Dh 0077 1] Length : 1C
[04Eh 0078 2] Reserved : 0000
-[050h 0080 4] Flags (decoded below) : 0000000A
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 0
- Node is a leaf : 1
- Identical Implementation : 0
-[054h 0084 4] Parent : 00000038
-[058h 0088 4] ACPI Processor ID : 00000000
-[05Ch 0092 4] Private Resource Number : 00000000
-
-[060h 0096 1] Subtable Type : 00 [Processor Hierarchy Node]
-[061h 0097 1] Length : 14
-[062h 0098 2] Reserved : 0000
-[064h 0100 4] Flags (decoded below) : 0000000A
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 0
- Node is a leaf : 1
- Identical Implementation : 0
-[068h 0104 4] Parent : 00000038
-[06Ch 0108 4] ACPI Processor ID : 00000001
-[070h 0112 4] Private Resource Number : 00000000
-
-[074h 0116 1] Subtable Type : 00 [Processor Hierarchy Node]
-[075h 0117 1] Length : 14
-[076h 0118 2] Reserved : 0000
-[078h 0120 4] Flags (decoded below) : 00000011
- Physical package : 1
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[07Ch 0124 4] Parent : 00000024
-[080h 0128 4] ACPI Processor ID : 00000001
-[084h 0132 4] Private Resource Number : 00000000
-
-[088h 0136 1] Subtable Type : 00 [Processor Hierarchy Node]
-[089h 0137 1] Length : 14
-[08Ah 0138 2] Reserved : 0000
-[08Ch 0140 4] Flags (decoded below) : 0000000A
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 0
- Node is a leaf : 1
- Identical Implementation : 0
-[090h 0144 4] Parent : 00000074
-[094h 0148 4] ACPI Processor ID : 00000002
-[098h 0152 4] Private Resource Number : 00000000
-
-[09Ch 0156 1] Subtable Type : 00 [Processor Hierarchy Node]
-[09Dh 0157 1] Length : 14
-[09Eh 0158 2] Reserved : 0000
-[0A0h 0160 4] Flags (decoded below) : 0000000A
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 0
- Node is a leaf : 1
- Identical Implementation : 0
-[0A4h 0164 4] Parent : 00000074
-[0A8h 0168 4] ACPI Processor ID : 00000003
-[0ACh 0172 4] Private Resource Number : 00000000
+[050h 0080 4] Flags (decoded below) : 000000FF
+ Size valid : 1
+ Number of Sets valid : 1
+ Associativity valid : 1
+ Allocation Type valid : 1
+ Cache Type valid : 1
+ Write Policy valid : 1
+ Line Size valid : 1
+[054h 0084 4] Next Level of Cache : 00000000
+[058h 0088 4] Size : 00200000
+[05Ch 0092 4] Number of Sets : 00000800
+[060h 0096 1] Associativity : 10
+[061h 0097 1] Attributes : 0F
+ Allocation Type : 3
+ Cache Type : 3
+ Write Policy : 0
+[062h 0098 2] Line Size : 0040
+
+Invalid subtable length
-Raw Table Data: Length 176 (0xB0)
+Raw Table Data: Length 496 (0x1F0)
- 0000: 50 50 54 54 B0 00 00 00 02 0D 42 4F 43 48 53 20 // PPTT......BOCHS
+ 0000: 50 50 54 54 F0 01 00 00 02 C6 42 4F 43 48 53 20 // PPTT......BOCHS
0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC
0020: 01 00 00 00 00 14 00 00 11 00 00 00 00 00 00 00 // ................
0030: 00 00 00 00 00 00 00 00 00 14 00 00 11 00 00 00 // ................
- 0040: 24 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // $...............
- 0050: 0A 00 00 00 38 00 00 00 00 00 00 00 00 00 00 00 // ....8...........
- 0060: 00 14 00 00 0A 00 00 00 38 00 00 00 01 00 00 00 // ........8.......
- 0070: 00 00 00 00 00 14 00 00 11 00 00 00 24 00 00 00 // ............$...
- 0080: 01 00 00 00 00 00 00 00 00 14 00 00 0A 00 00 00 // ................
- 0090: 74 00 00 00 02 00 00 00 00 00 00 00 00 14 00 00 // t...............
- 00A0: 0A 00 00 00 74 00 00 00 03 00 00 00 00 00 00 00 // ....t...........
+ 0040: 24 00 00 00 00 00 00 00 00 00 00 00 01 1C 00 00 // $...............
+ 0050: FF 00 00 00 00 00 00 00 00 00 20 00 00 08 00 00 // .......... .....
+ 0060: 10 0F 40 00 01 1C 00 00 FF 00 00 00 4C 00 00 00 // ..@.........L...
+ 0070: 00 80 00 00 80 00 00 00 04 03 40 00 01 1C 00 00 // ..........@.....
+ 0080: FF 00 00 00 4C 00 00 00 00 C0 00 00 00 01 00 00 // ....L...........
+ 0090: 03 07 40 00 00 1C 00 00 0A 00 00 00 38 00 00 00 // ..@.........8...
+ 00A0: 00 00 00 00 02 00 00 00 7C 00 00 00 64 00 00 00 // ........|...d...
+ 00B0: 01 1C 00 00 FF 00 00 00 00 00 00 00 00 00 20 00 // .............. .
+ 00C0: 00 08 00 00 10 0F 40 00 01 1C 00 00 FF 00 00 00 // ......@.........
+ 00D0: B0 00 00 00 00 80 00 00 80 00 00 00 04 03 40 00 // ..............@.
+ 00E0: 01 1C 00 00 FF 00 00 00 B0 00 00 00 00 C0 00 00 // ................
+ 00F0: 00 01 00 00 03 07 40 00 00 1C 00 00 0A 00 00 00 // ......@.........
+ 0100: 38 00 00 00 01 00 00 00 02 00 00 00 E0 00 00 00 // 8...............
+ 0110: C8 00 00 00 00 14 00 00 11 00 00 00 24 00 00 00 // ............$...
+ 0120: 01 00 00 00 00 00 00 00 01 1C 00 00 FF 00 00 00 // ................
+ 0130: 00 00 00 00 00 00 20 00 00 08 00 00 10 0F 40 00 // ...... .......@.
+ 0140: 01 1C 00 00 FF 00 00 00 28 01 00 00 00 80 00 00 // ........(.......
+ 0150: 80 00 00 00 04 03 40 00 01 1C 00 00 FF 00 00 00 // ......@.........
+ 0160: 28 01 00 00 00 C0 00 00 00 01 00 00 03 07 40 00 // (.............@.
+ 0170: 00 1C 00 00 0A 00 00 00 14 01 00 00 02 00 00 00 // ................
+ 0180: 02 00 00 00 58 01 00 00 40 01 00 00 01 1C 00 00 // ....X...@.......
+ 0190: FF 00 00 00 00 00 00 00 00 00 20 00 00 08 00 00 // .......... .....
+ 01A0: 10 0F 40 00 01 1C 00 00 FF 00 00 00 8C 01 00 00 // ..@.............
+ 01B0: 00 80 00 00 80 00 00 00 04 03 40 00 01 1C 00 00 // ..........@.....
+ 01C0: FF 00 00 00 8C 01 00 00 00 C0 00 00 00 01 00 00 // ................
+ 01D0: 03 07 40 00 00 1C 00 00 0A 00 00 00 14 01 00 00 // ..@.............
+ 01E0: 03 00 00 00 02 00 00 00 BC 01 00 00 A4 01 00 00 // ................
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20200925 (64-bit version)
* Copyright (c) 2000 - 2020 Intel Corporation
*
- * Disassembly of tests/data/acpi/aarch64/virt/PPTT.topology, Thu Apr 24 19:37:25 2025
+ * Disassembly of /tmp/aml-6P9K52, Thu Apr 24 19:37:25 2025
*
* ACPI Data Table [PPTT]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[000h 0000 4] Signature : "PPTT" [Processor Properties Topology Table]
-[004h 0004 4] Table Length : 00000164
+[004h 0004 4] Table Length : 0000027C
[008h 0008 1] Revision : 02
-[009h 0009 1] Checksum : 97
+[009h 0009 1] Checksum : C6
[00Ah 0010 6] Oem ID : "BOCHS "
[010h 0016 8] Oem Table ID : "BXPC "
[018h 0024 4] Oem Revision : 00000001
[01Ch 0028 4] Asl Compiler ID : "BXPC"
[020h 0032 4] Asl Compiler Revision : 00000001
[024h 0036 1] Subtable Type : 00 [Processor Hierarchy Node]
[025h 0037 1] Length : 14
[026h 0038 2] Reserved : 0000
[028h 0040 4] Flags (decoded below) : 00000011
Physical package : 1
ACPI Processor ID valid : 0
Processor is a thread : 0
Node is a leaf : 0
Identical Implementation : 1
@@ -34,223 +34,81 @@
[030h 0048 4] ACPI Processor ID : 00000000
[034h 0052 4] Private Resource Number : 00000000
[038h 0056 1] Subtable Type : 00 [Processor Hierarchy Node]
[039h 0057 1] Length : 14
[03Ah 0058 2] Reserved : 0000
[03Ch 0060 4] Flags (decoded below) : 00000011
Physical package : 1
ACPI Processor ID valid : 0
Processor is a thread : 0
Node is a leaf : 0
Identical Implementation : 1
[040h 0064 4] Parent : 00000024
[044h 0068 4] ACPI Processor ID : 00000000
[048h 0072 4] Private Resource Number : 00000000
-[04Ch 0076 1] Subtable Type : 00 [Processor Hierarchy Node]
-[04Dh 0077 1] Length : 14
+[04Ch 0076 1] Subtable Type : 01 [Cache Type]
+[04Dh 0077 1] Length : 1C
[04Eh 0078 2] Reserved : 0000
-[050h 0080 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[054h 0084 4] Parent : 00000038
-[058h 0088 4] ACPI Processor ID : 00000000
-[05Ch 0092 4] Private Resource Number : 00000000
-
-[060h 0096 1] Subtable Type : 00 [Processor Hierarchy Node]
-[061h 0097 1] Length : 14
-[062h 0098 2] Reserved : 0000
-[064h 0100 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[068h 0104 4] Parent : 0000004C
-[06Ch 0108 4] ACPI Processor ID : 00000000
-[070h 0112 4] Private Resource Number : 00000000
-
-[074h 0116 1] Subtable Type : 00 [Processor Hierarchy Node]
-[075h 0117 1] Length : 14
-[076h 0118 2] Reserved : 0000
-[078h 0120 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[07Ch 0124 4] Parent : 00000060
-[080h 0128 4] ACPI Processor ID : 00000000
-[084h 0132 4] Private Resource Number : 00000000
-
-[088h 0136 1] Subtable Type : 00 [Processor Hierarchy Node]
-[089h 0137 1] Length : 14
-[08Ah 0138 2] Reserved : 0000
-[08Ch 0140 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[090h 0144 4] Parent : 00000060
-[094h 0148 4] ACPI Processor ID : 00000001
-[098h 0152 4] Private Resource Number : 00000000
-
-[09Ch 0156 1] Subtable Type : 00 [Processor Hierarchy Node]
-[09Dh 0157 1] Length : 14
-[09Eh 0158 2] Reserved : 0000
-[0A0h 0160 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[0A4h 0164 4] Parent : 0000004C
-[0A8h 0168 4] ACPI Processor ID : 00000001
-[0ACh 0172 4] Private Resource Number : 00000000
-
-[0B0h 0176 1] Subtable Type : 00 [Processor Hierarchy Node]
-[0B1h 0177 1] Length : 14
-[0B2h 0178 2] Reserved : 0000
-[0B4h 0180 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[0B8h 0184 4] Parent : 0000009C
-[0BCh 0188 4] ACPI Processor ID : 00000002
-[0C0h 0192 4] Private Resource Number : 00000000
-
-[0C4h 0196 1] Subtable Type : 00 [Processor Hierarchy Node]
-[0C5h 0197 1] Length : 14
-[0C6h 0198 2] Reserved : 0000
-[0C8h 0200 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[0CCh 0204 4] Parent : 0000009C
-[0D0h 0208 4] ACPI Processor ID : 00000003
-[0D4h 0212 4] Private Resource Number : 00000000
-
-[0D8h 0216 1] Subtable Type : 00 [Processor Hierarchy Node]
-[0D9h 0217 1] Length : 14
-[0DAh 0218 2] Reserved : 0000
-[0DCh 0220 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[0E0h 0224 4] Parent : 00000038
-[0E4h 0228 4] ACPI Processor ID : 00000001
-[0E8h 0232 4] Private Resource Number : 00000000
-
-[0ECh 0236 1] Subtable Type : 00 [Processor Hierarchy Node]
-[0EDh 0237 1] Length : 14
-[0EEh 0238 2] Reserved : 0000
-[0F0h 0240 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[0F4h 0244 4] Parent : 000000D8
-[0F8h 0248 4] ACPI Processor ID : 00000000
-[0FCh 0252 4] Private Resource Number : 00000000
-
-[100h 0256 1] Subtable Type : 00 [Processor Hierarchy Node]
-[101h 0257 1] Length : 14
-[102h 0258 2] Reserved : 0000
-[104h 0260 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[108h 0264 4] Parent : 000000EC
-[10Ch 0268 4] ACPI Processor ID : 00000004
-[110h 0272 4] Private Resource Number : 00000000
-
-[114h 0276 1] Subtable Type : 00 [Processor Hierarchy Node]
-[115h 0277 1] Length : 14
-[116h 0278 2] Reserved : 0000
-[118h 0280 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[11Ch 0284 4] Parent : 000000EC
-[120h 0288 4] ACPI Processor ID : 00000005
-[124h 0292 4] Private Resource Number : 00000000
-
-[128h 0296 1] Subtable Type : 00 [Processor Hierarchy Node]
-[129h 0297 1] Length : 14
-[12Ah 0298 2] Reserved : 0000
-[12Ch 0300 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[130h 0304 4] Parent : 000000D8
-[134h 0308 4] ACPI Processor ID : 00000001
-[138h 0312 4] Private Resource Number : 00000000
-
-[13Ch 0316 1] Subtable Type : 00 [Processor Hierarchy Node]
-[13Dh 0317 1] Length : 14
-[13Eh 0318 2] Reserved : 0000
-[140h 0320 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[144h 0324 4] Parent : 00000128
-[148h 0328 4] ACPI Processor ID : 00000006
-[14Ch 0332 4] Private Resource Number : 00000000
+[050h 0080 4] Flags (decoded below) : 000000FF
+ Size valid : 1
+ Number of Sets valid : 1
+ Associativity valid : 1
+ Allocation Type valid : 1
+ Cache Type valid : 1
+ Write Policy valid : 1
+ Line Size valid : 1
+[054h 0084 4] Next Level of Cache : 00000000
+[058h 0088 4] Size : 00200000
+[05Ch 0092 4] Number of Sets : 00000800
+[060h 0096 1] Associativity : 10
+[061h 0097 1] Attributes : 0F
+ Allocation Type : 3
+ Cache Type : 3
+ Write Policy : 0
+[062h 0098 2] Line Size : 0040
-[150h 0336 1] Subtable Type : 00 [Processor Hierarchy Node]
-[151h 0337 1] Length : 14
-[152h 0338 2] Reserved : 0000
-[154h 0340 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[158h 0344 4] Parent : 00000128
-[15Ch 0348 4] ACPI Processor ID : 00000007
-[160h 0352 4] Private Resource Number : 00000000
+Invalid subtable length
-Raw Table Data: Length 356 (0x164)
+Raw Table Data: Length 636 (0x27C)
- 0000: 50 50 54 54 64 01 00 00 02 97 42 4F 43 48 53 20 // PPTTd.....BOCHS
+ 0000: 50 50 54 54 7C 02 00 00 02 C6 42 4F 43 48 53 20 // PPTT|.....BOCHS
0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC
0020: 01 00 00 00 00 14 00 00 11 00 00 00 00 00 00 00 // ................
0030: 00 00 00 00 00 00 00 00 00 14 00 00 11 00 00 00 // ................
- 0040: 24 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // $...............
- 0050: 10 00 00 00 38 00 00 00 00 00 00 00 00 00 00 00 // ....8...........
- 0060: 00 14 00 00 10 00 00 00 4C 00 00 00 00 00 00 00 // ........L.......
- 0070: 00 00 00 00 00 14 00 00 0E 00 00 00 60 00 00 00 // ............`...
- 0080: 00 00 00 00 00 00 00 00 00 14 00 00 0E 00 00 00 // ................
- 0090: 60 00 00 00 01 00 00 00 00 00 00 00 00 14 00 00 // `...............
- 00A0: 10 00 00 00 4C 00 00 00 01 00 00 00 00 00 00 00 // ....L...........
- 00B0: 00 14 00 00 0E 00 00 00 9C 00 00 00 02 00 00 00 // ................
- 00C0: 00 00 00 00 00 14 00 00 0E 00 00 00 9C 00 00 00 // ................
- 00D0: 03 00 00 00 00 00 00 00 00 14 00 00 10 00 00 00 // ................
- 00E0: 38 00 00 00 01 00 00 00 00 00 00 00 00 14 00 00 // 8...............
- 00F0: 10 00 00 00 D8 00 00 00 00 00 00 00 00 00 00 00 // ................
- 0100: 00 14 00 00 0E 00 00 00 EC 00 00 00 04 00 00 00 // ................
- 0110: 00 00 00 00 00 14 00 00 0E 00 00 00 EC 00 00 00 // ................
- 0120: 05 00 00 00 00 00 00 00 00 14 00 00 10 00 00 00 // ................
- 0130: D8 00 00 00 01 00 00 00 00 00 00 00 00 14 00 00 // ................
- 0140: 0E 00 00 00 28 01 00 00 06 00 00 00 00 00 00 00 // ....(...........
- 0150: 00 14 00 00 0E 00 00 00 28 01 00 00 07 00 00 00 // ........(.......
- 0160: 00 00 00 00 // ....
+ 0040: 24 00 00 00 00 00 00 00 00 00 00 00 01 1C 00 00 // $...............
+ 0050: FF 00 00 00 00 00 00 00 00 00 20 00 00 08 00 00 // .......... .....
+ 0060: 10 0F 40 00 00 18 00 00 10 00 00 00 38 00 00 00 // ..@.........8...
+ 0070: 00 00 00 00 01 00 00 00 4C 00 00 00 01 1C 00 00 // ........L.......
+ 0080: FF 00 00 00 00 00 00 00 00 80 00 00 80 00 00 00 // ................
+ 0090: 04 03 40 00 01 1C 00 00 FF 00 00 00 00 00 00 00 // ..@.............
+ 00A0: 00 C0 00 00 00 01 00 00 03 07 40 00 00 1C 00 00 // ..........@.....
+ 00B0: 10 00 00 00 64 00 00 00 00 00 00 00 02 00 00 00 // ....d...........
+ 00C0: 94 00 00 00 7C 00 00 00 00 14 00 00 0E 00 00 00 // ....|...........
+ 00D0: AC 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // ................
+ 00E0: 0E 00 00 00 AC 00 00 00 01 00 00 00 00 00 00 00 // ................
+ 00F0: 01 1C 00 00 FF 00 00 00 00 00 00 00 00 80 00 00 // ................
+ 0100: 80 00 00 00 04 03 40 00 01 1C 00 00 FF 00 00 00 // ......@.........
+ 0110: 00 00 00 00 00 C0 00 00 00 01 00 00 03 07 40 00 // ..............@.
+ 0120: 00 1C 00 00 10 00 00 00 64 00 00 00 01 00 00 00 // ........d.......
+ 0130: 02 00 00 00 08 01 00 00 F0 00 00 00 00 14 00 00 // ................
+ 0140: 0E 00 00 00 20 01 00 00 02 00 00 00 00 00 00 00 // .... ...........
+ 0150: 00 14 00 00 0E 00 00 00 20 01 00 00 03 00 00 00 // ........ .......
+ 0160: 00 00 00 00 01 1C 00 00 FF 00 00 00 00 00 00 00 // ................
+ 0170: 00 00 20 00 00 08 00 00 10 0F 40 00 00 18 00 00 // .. .......@.....
+ 0180: 10 00 00 00 38 00 00 00 01 00 00 00 01 00 00 00 // ....8...........
+ 0190: 64 01 00 00 01 1C 00 00 FF 00 00 00 00 00 00 00 // d...............
+ 01A0: 00 80 00 00 80 00 00 00 04 03 40 00 01 1C 00 00 // ..........@.....
+ 01B0: FF 00 00 00 00 00 00 00 00 C0 00 00 00 01 00 00 // ................
+ 01C0: 03 07 40 00 00 1C 00 00 10 00 00 00 7C 01 00 00 // ..@.........|...
+ 01D0: 00 00 00 00 02 00 00 00 AC 01 00 00 94 01 00 00 // ................
+ 01E0: 00 14 00 00 0E 00 00 00 C4 01 00 00 04 00 00 00 // ................
+ 01F0: 00 00 00 00 00 14 00 00 0E 00 00 00 C4 01 00 00 // ................
+ 0200: 05 00 00 00 00 00 00 00 01 1C 00 00 FF 00 00 00 // ................
+ 0210: 00 00 00 00 00 80 00 00 80 00 00 00 04 03 40 00 // ..............@.
+ 0220: 01 1C 00 00 FF 00 00 00 00 00 00 00 00 C0 00 00 // ................
+ 0230: 00 01 00 00 03 07 40 00 00 1C 00 00 10 00 00 00 // ......@.........
+ 0240: 7C 01 00 00 01 00 00 00 02 00 00 00 20 02 00 00 // |........... ...
+ 0250: 08 02 00 00 00 14 00 00 0E 00 00 00 38 02 00 00 // ............8...
+ 0260: 06 00 00 00 00 00 00 00 00 14 00 00 0E 00 00 00 // ................
+ 0270: 38 02 00 00 07 00 00 00 00 00 00 00 // 8...........
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
---
tests/data/acpi/aarch64/virt/PPTT | Bin 96 -> 176 bytes
tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt | Bin 176 -> 496 bytes
tests/data/acpi/aarch64/virt/PPTT.topology | Bin 356 -> 676 bytes
tests/qtest/bios-tables-test-allowed-diff.h | 3 ---
4 files changed, 3 deletions(-)
diff --git a/tests/data/acpi/aarch64/virt/PPTT b/tests/data/acpi/aarch64/virt/PPTT
index 15598a9b8a3cc0cdd50bc1f77c73ae0ba728a272..43b9b7047ad93eee1d2ac0a9b08d22d73bebdf54 100644
GIT binary patch
literal 176
zcmWFt2npH1z`($y;pFe^5v<@85#X!<1dKp25F11@h%hh+f@ov_6;nYHW0YZF_z&kR
zFfed1FbMEFFu=rpKynRW#K6LgCVl`Y2egct-GPAtXbu;UYXQU{zy!oKK%4@^02kX2
A0RR91
delta 38
kcmdnMn7|bf5E7EWz`($yK9S2wgh7OXfeXm90Ad&b0DQ6pGynhq
diff --git a/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt b/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt
index 7b613ddaf4b8cfa13821aa2e835d290077221897..fc318de992302251ad33b6e74c1632d281ff56e5 100644
GIT binary patch
literal 496
zcmah_F$%&!5S-)$#YTmc7FSsK1j~>#7J>m&<N-dzA`kExd4LbFxJrD6Pw)pia~L^I
zAVY@TojG>c6h&D+BOtzI`+R$_Sykkgpak`*NPvZEh>x}kv}g&uzOw};z<idX)pzo0
z|6yeQbVrY2W}E`tGv&A;g_t~%N3z|;mav_Si{!eS;dMu^CxepDc(C5d_Fmm4PZ-Kw
r>tWr^^}5r7-`f(-x=XCsr{qw^nQ!_syzc1H5C5Ms3}t0p**D}HPG2ek
literal 176
zcmWFt2npH1z`(%7>*Vk35v<@85#X!<1dKp25F11@h%hh+f@ov_6;nYI;{x(6aEO7;
b0?8riMHU0;EdgRCkQxvGs)LC!Lqr$=thxyS
diff --git a/tests/data/acpi/aarch64/virt/PPTT.topology b/tests/data/acpi/aarch64/virt/PPTT.topology
index 6b864f035c9f48845e9a3beb482c5171074864a5..cdbc482d467fc6987ab3ddf3ca38d987adfe484b 100644
GIT binary patch
literal 676
zcmaixy$!-J6ofB7{8SJm3JQu83_w9ai4uwwNJN5yk})VV00l!(Fa$-0U<`JEJL4de
zAmtRt?|sjHzBqZl-(P*eUnko%+r`NtPh-jhpjb1;z(}(z%VsqeF<&~&n*y(I9s_+K
z8m>_BqiThD5C%0~vPJ_zZw0WAdT%%+TE>Orq=a4uoNkIMIm~<md3EMzN!;-ARH0~k
zF}!5$j~Dfpmnnl#i9L70Slq~Afy1i1(l)8h-&qTbra!|=HTb=&lWi;?cg9!c*2{x&
s$kfPT9gEt$Ow_b!dNI6Yjs4yKCNDZ(+cLi93hcQ@#$BdH4(nO;2Hztu0RR91
literal 356
zcmWFt2nk7HWME*L?&R<65v<@85#X!<1VAAM5F11@h%hh+f@ov_6;nYI69Dopu!#Af
ziSYsX2{^>Sc7o)9c7V(S=|vU;>74__Oh60<Ky@%NW+X9~TafjF#BRXUfM}@RH$Wx}
cOdLs!6-f-H7uh_Jy&6CPHY9a0F?OgJ00?&w0RR91
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index e84d6c695520..dfb8523c8bf4 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,4 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/aarch64/virt/PPTT",
-"tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt",
-"tests/data/acpi/aarch64/virt/PPTT.topology",
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH v10 6/6] Update the ACPI tables according to the acpi aml_build changes
@ 2025-04-28 11:07 ` Alireza Sanaee via
0 siblings, 0 replies; 14+ messages in thread
From: Alireza Sanaee via @ 2025-04-28 11:07 UTC (permalink / raw)
To: qemu-devel
Cc: philmd, alireza.sanaee, anisinha, armbru, berrange, dapeng1.mi,
eric.auger, farman, gustavo.romero, imammedo, jiangkunkun,
jonathan.cameron, linuxarm, mst, mtosatti, peter.maydell,
qemu-arm, richard.henderson, shameerali.kolothum.thodi,
shannon.zhaosl, yangyicong, zhao1.liu
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20200925 (64-bit version)
* Copyright (c) 2000 - 2020 Intel Corporation
*
- * Disassembly of tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt, Thu Apr 24 19:37:19 2025
+ * Disassembly of /tmp/aml-X03H52, Thu Apr 24 19:37:19 2025
*
* ACPI Data Table [PPTT]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[000h 0000 4] Signature : "PPTT" [Processor Properties Topology Table]
-[004h 0004 4] Table Length : 000000B0
+[004h 0004 4] Table Length : 000001F0
[008h 0008 1] Revision : 02
-[009h 0009 1] Checksum : 0D
+[009h 0009 1] Checksum : C6
[00Ah 0010 6] Oem ID : "BOCHS "
[010h 0016 8] Oem Table ID : "BXPC "
[018h 0024 4] Oem Revision : 00000001
[01Ch 0028 4] Asl Compiler ID : "BXPC"
[020h 0032 4] Asl Compiler Revision : 00000001
[024h 0036 1] Subtable Type : 00 [Processor Hierarchy Node]
[025h 0037 1] Length : 14
[026h 0038 2] Reserved : 0000
[028h 0040 4] Flags (decoded below) : 00000011
Physical package : 1
ACPI Processor ID valid : 0
Processor is a thread : 0
Node is a leaf : 0
Identical Implementation : 1
@@ -34,94 +34,72 @@
[030h 0048 4] ACPI Processor ID : 00000000
[034h 0052 4] Private Resource Number : 00000000
[038h 0056 1] Subtable Type : 00 [Processor Hierarchy Node]
[039h 0057 1] Length : 14
[03Ah 0058 2] Reserved : 0000
[03Ch 0060 4] Flags (decoded below) : 00000011
Physical package : 1
ACPI Processor ID valid : 0
Processor is a thread : 0
Node is a leaf : 0
Identical Implementation : 1
[040h 0064 4] Parent : 00000024
[044h 0068 4] ACPI Processor ID : 00000000
[048h 0072 4] Private Resource Number : 00000000
-[04Ch 0076 1] Subtable Type : 00 [Processor Hierarchy Node]
-[04Dh 0077 1] Length : 14
+[04Ch 0076 1] Subtable Type : 01 [Cache Type]
+[04Dh 0077 1] Length : 1C
[04Eh 0078 2] Reserved : 0000
-[050h 0080 4] Flags (decoded below) : 0000000A
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 0
- Node is a leaf : 1
- Identical Implementation : 0
-[054h 0084 4] Parent : 00000038
-[058h 0088 4] ACPI Processor ID : 00000000
-[05Ch 0092 4] Private Resource Number : 00000000
-
-[060h 0096 1] Subtable Type : 00 [Processor Hierarchy Node]
-[061h 0097 1] Length : 14
-[062h 0098 2] Reserved : 0000
-[064h 0100 4] Flags (decoded below) : 0000000A
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 0
- Node is a leaf : 1
- Identical Implementation : 0
-[068h 0104 4] Parent : 00000038
-[06Ch 0108 4] ACPI Processor ID : 00000001
-[070h 0112 4] Private Resource Number : 00000000
-
-[074h 0116 1] Subtable Type : 00 [Processor Hierarchy Node]
-[075h 0117 1] Length : 14
-[076h 0118 2] Reserved : 0000
-[078h 0120 4] Flags (decoded below) : 00000011
- Physical package : 1
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[07Ch 0124 4] Parent : 00000024
-[080h 0128 4] ACPI Processor ID : 00000001
-[084h 0132 4] Private Resource Number : 00000000
-
-[088h 0136 1] Subtable Type : 00 [Processor Hierarchy Node]
-[089h 0137 1] Length : 14
-[08Ah 0138 2] Reserved : 0000
-[08Ch 0140 4] Flags (decoded below) : 0000000A
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 0
- Node is a leaf : 1
- Identical Implementation : 0
-[090h 0144 4] Parent : 00000074
-[094h 0148 4] ACPI Processor ID : 00000002
-[098h 0152 4] Private Resource Number : 00000000
-
-[09Ch 0156 1] Subtable Type : 00 [Processor Hierarchy Node]
-[09Dh 0157 1] Length : 14
-[09Eh 0158 2] Reserved : 0000
-[0A0h 0160 4] Flags (decoded below) : 0000000A
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 0
- Node is a leaf : 1
- Identical Implementation : 0
-[0A4h 0164 4] Parent : 00000074
-[0A8h 0168 4] ACPI Processor ID : 00000003
-[0ACh 0172 4] Private Resource Number : 00000000
+[050h 0080 4] Flags (decoded below) : 000000FF
+ Size valid : 1
+ Number of Sets valid : 1
+ Associativity valid : 1
+ Allocation Type valid : 1
+ Cache Type valid : 1
+ Write Policy valid : 1
+ Line Size valid : 1
+[054h 0084 4] Next Level of Cache : 00000000
+[058h 0088 4] Size : 00200000
+[05Ch 0092 4] Number of Sets : 00000800
+[060h 0096 1] Associativity : 10
+[061h 0097 1] Attributes : 0F
+ Allocation Type : 3
+ Cache Type : 3
+ Write Policy : 0
+[062h 0098 2] Line Size : 0040
+
+Invalid subtable length
-Raw Table Data: Length 176 (0xB0)
+Raw Table Data: Length 496 (0x1F0)
- 0000: 50 50 54 54 B0 00 00 00 02 0D 42 4F 43 48 53 20 // PPTT......BOCHS
+ 0000: 50 50 54 54 F0 01 00 00 02 C6 42 4F 43 48 53 20 // PPTT......BOCHS
0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC
0020: 01 00 00 00 00 14 00 00 11 00 00 00 00 00 00 00 // ................
0030: 00 00 00 00 00 00 00 00 00 14 00 00 11 00 00 00 // ................
- 0040: 24 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // $...............
- 0050: 0A 00 00 00 38 00 00 00 00 00 00 00 00 00 00 00 // ....8...........
- 0060: 00 14 00 00 0A 00 00 00 38 00 00 00 01 00 00 00 // ........8.......
- 0070: 00 00 00 00 00 14 00 00 11 00 00 00 24 00 00 00 // ............$...
- 0080: 01 00 00 00 00 00 00 00 00 14 00 00 0A 00 00 00 // ................
- 0090: 74 00 00 00 02 00 00 00 00 00 00 00 00 14 00 00 // t...............
- 00A0: 0A 00 00 00 74 00 00 00 03 00 00 00 00 00 00 00 // ....t...........
+ 0040: 24 00 00 00 00 00 00 00 00 00 00 00 01 1C 00 00 // $...............
+ 0050: FF 00 00 00 00 00 00 00 00 00 20 00 00 08 00 00 // .......... .....
+ 0060: 10 0F 40 00 01 1C 00 00 FF 00 00 00 4C 00 00 00 // ..@.........L...
+ 0070: 00 80 00 00 80 00 00 00 04 03 40 00 01 1C 00 00 // ..........@.....
+ 0080: FF 00 00 00 4C 00 00 00 00 C0 00 00 00 01 00 00 // ....L...........
+ 0090: 03 07 40 00 00 1C 00 00 0A 00 00 00 38 00 00 00 // ..@.........8...
+ 00A0: 00 00 00 00 02 00 00 00 7C 00 00 00 64 00 00 00 // ........|...d...
+ 00B0: 01 1C 00 00 FF 00 00 00 00 00 00 00 00 00 20 00 // .............. .
+ 00C0: 00 08 00 00 10 0F 40 00 01 1C 00 00 FF 00 00 00 // ......@.........
+ 00D0: B0 00 00 00 00 80 00 00 80 00 00 00 04 03 40 00 // ..............@.
+ 00E0: 01 1C 00 00 FF 00 00 00 B0 00 00 00 00 C0 00 00 // ................
+ 00F0: 00 01 00 00 03 07 40 00 00 1C 00 00 0A 00 00 00 // ......@.........
+ 0100: 38 00 00 00 01 00 00 00 02 00 00 00 E0 00 00 00 // 8...............
+ 0110: C8 00 00 00 00 14 00 00 11 00 00 00 24 00 00 00 // ............$...
+ 0120: 01 00 00 00 00 00 00 00 01 1C 00 00 FF 00 00 00 // ................
+ 0130: 00 00 00 00 00 00 20 00 00 08 00 00 10 0F 40 00 // ...... .......@.
+ 0140: 01 1C 00 00 FF 00 00 00 28 01 00 00 00 80 00 00 // ........(.......
+ 0150: 80 00 00 00 04 03 40 00 01 1C 00 00 FF 00 00 00 // ......@.........
+ 0160: 28 01 00 00 00 C0 00 00 00 01 00 00 03 07 40 00 // (.............@.
+ 0170: 00 1C 00 00 0A 00 00 00 14 01 00 00 02 00 00 00 // ................
+ 0180: 02 00 00 00 58 01 00 00 40 01 00 00 01 1C 00 00 // ....X...@.......
+ 0190: FF 00 00 00 00 00 00 00 00 00 20 00 00 08 00 00 // .......... .....
+ 01A0: 10 0F 40 00 01 1C 00 00 FF 00 00 00 8C 01 00 00 // ..@.............
+ 01B0: 00 80 00 00 80 00 00 00 04 03 40 00 01 1C 00 00 // ..........@.....
+ 01C0: FF 00 00 00 8C 01 00 00 00 C0 00 00 00 01 00 00 // ................
+ 01D0: 03 07 40 00 00 1C 00 00 0A 00 00 00 14 01 00 00 // ..@.............
+ 01E0: 03 00 00 00 02 00 00 00 BC 01 00 00 A4 01 00 00 // ................
/*
* Intel ACPI Component Architecture
* AML/ASL+ Disassembler version 20200925 (64-bit version)
* Copyright (c) 2000 - 2020 Intel Corporation
*
- * Disassembly of tests/data/acpi/aarch64/virt/PPTT.topology, Thu Apr 24 19:37:25 2025
+ * Disassembly of /tmp/aml-6P9K52, Thu Apr 24 19:37:25 2025
*
* ACPI Data Table [PPTT]
*
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
*/
[000h 0000 4] Signature : "PPTT" [Processor Properties Topology Table]
-[004h 0004 4] Table Length : 00000164
+[004h 0004 4] Table Length : 0000027C
[008h 0008 1] Revision : 02
-[009h 0009 1] Checksum : 97
+[009h 0009 1] Checksum : C6
[00Ah 0010 6] Oem ID : "BOCHS "
[010h 0016 8] Oem Table ID : "BXPC "
[018h 0024 4] Oem Revision : 00000001
[01Ch 0028 4] Asl Compiler ID : "BXPC"
[020h 0032 4] Asl Compiler Revision : 00000001
[024h 0036 1] Subtable Type : 00 [Processor Hierarchy Node]
[025h 0037 1] Length : 14
[026h 0038 2] Reserved : 0000
[028h 0040 4] Flags (decoded below) : 00000011
Physical package : 1
ACPI Processor ID valid : 0
Processor is a thread : 0
Node is a leaf : 0
Identical Implementation : 1
@@ -34,223 +34,81 @@
[030h 0048 4] ACPI Processor ID : 00000000
[034h 0052 4] Private Resource Number : 00000000
[038h 0056 1] Subtable Type : 00 [Processor Hierarchy Node]
[039h 0057 1] Length : 14
[03Ah 0058 2] Reserved : 0000
[03Ch 0060 4] Flags (decoded below) : 00000011
Physical package : 1
ACPI Processor ID valid : 0
Processor is a thread : 0
Node is a leaf : 0
Identical Implementation : 1
[040h 0064 4] Parent : 00000024
[044h 0068 4] ACPI Processor ID : 00000000
[048h 0072 4] Private Resource Number : 00000000
-[04Ch 0076 1] Subtable Type : 00 [Processor Hierarchy Node]
-[04Dh 0077 1] Length : 14
+[04Ch 0076 1] Subtable Type : 01 [Cache Type]
+[04Dh 0077 1] Length : 1C
[04Eh 0078 2] Reserved : 0000
-[050h 0080 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[054h 0084 4] Parent : 00000038
-[058h 0088 4] ACPI Processor ID : 00000000
-[05Ch 0092 4] Private Resource Number : 00000000
-
-[060h 0096 1] Subtable Type : 00 [Processor Hierarchy Node]
-[061h 0097 1] Length : 14
-[062h 0098 2] Reserved : 0000
-[064h 0100 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[068h 0104 4] Parent : 0000004C
-[06Ch 0108 4] ACPI Processor ID : 00000000
-[070h 0112 4] Private Resource Number : 00000000
-
-[074h 0116 1] Subtable Type : 00 [Processor Hierarchy Node]
-[075h 0117 1] Length : 14
-[076h 0118 2] Reserved : 0000
-[078h 0120 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[07Ch 0124 4] Parent : 00000060
-[080h 0128 4] ACPI Processor ID : 00000000
-[084h 0132 4] Private Resource Number : 00000000
-
-[088h 0136 1] Subtable Type : 00 [Processor Hierarchy Node]
-[089h 0137 1] Length : 14
-[08Ah 0138 2] Reserved : 0000
-[08Ch 0140 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[090h 0144 4] Parent : 00000060
-[094h 0148 4] ACPI Processor ID : 00000001
-[098h 0152 4] Private Resource Number : 00000000
-
-[09Ch 0156 1] Subtable Type : 00 [Processor Hierarchy Node]
-[09Dh 0157 1] Length : 14
-[09Eh 0158 2] Reserved : 0000
-[0A0h 0160 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[0A4h 0164 4] Parent : 0000004C
-[0A8h 0168 4] ACPI Processor ID : 00000001
-[0ACh 0172 4] Private Resource Number : 00000000
-
-[0B0h 0176 1] Subtable Type : 00 [Processor Hierarchy Node]
-[0B1h 0177 1] Length : 14
-[0B2h 0178 2] Reserved : 0000
-[0B4h 0180 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[0B8h 0184 4] Parent : 0000009C
-[0BCh 0188 4] ACPI Processor ID : 00000002
-[0C0h 0192 4] Private Resource Number : 00000000
-
-[0C4h 0196 1] Subtable Type : 00 [Processor Hierarchy Node]
-[0C5h 0197 1] Length : 14
-[0C6h 0198 2] Reserved : 0000
-[0C8h 0200 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[0CCh 0204 4] Parent : 0000009C
-[0D0h 0208 4] ACPI Processor ID : 00000003
-[0D4h 0212 4] Private Resource Number : 00000000
-
-[0D8h 0216 1] Subtable Type : 00 [Processor Hierarchy Node]
-[0D9h 0217 1] Length : 14
-[0DAh 0218 2] Reserved : 0000
-[0DCh 0220 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[0E0h 0224 4] Parent : 00000038
-[0E4h 0228 4] ACPI Processor ID : 00000001
-[0E8h 0232 4] Private Resource Number : 00000000
-
-[0ECh 0236 1] Subtable Type : 00 [Processor Hierarchy Node]
-[0EDh 0237 1] Length : 14
-[0EEh 0238 2] Reserved : 0000
-[0F0h 0240 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[0F4h 0244 4] Parent : 000000D8
-[0F8h 0248 4] ACPI Processor ID : 00000000
-[0FCh 0252 4] Private Resource Number : 00000000
-
-[100h 0256 1] Subtable Type : 00 [Processor Hierarchy Node]
-[101h 0257 1] Length : 14
-[102h 0258 2] Reserved : 0000
-[104h 0260 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[108h 0264 4] Parent : 000000EC
-[10Ch 0268 4] ACPI Processor ID : 00000004
-[110h 0272 4] Private Resource Number : 00000000
-
-[114h 0276 1] Subtable Type : 00 [Processor Hierarchy Node]
-[115h 0277 1] Length : 14
-[116h 0278 2] Reserved : 0000
-[118h 0280 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[11Ch 0284 4] Parent : 000000EC
-[120h 0288 4] ACPI Processor ID : 00000005
-[124h 0292 4] Private Resource Number : 00000000
-
-[128h 0296 1] Subtable Type : 00 [Processor Hierarchy Node]
-[129h 0297 1] Length : 14
-[12Ah 0298 2] Reserved : 0000
-[12Ch 0300 4] Flags (decoded below) : 00000010
- Physical package : 0
- ACPI Processor ID valid : 0
- Processor is a thread : 0
- Node is a leaf : 0
- Identical Implementation : 1
-[130h 0304 4] Parent : 000000D8
-[134h 0308 4] ACPI Processor ID : 00000001
-[138h 0312 4] Private Resource Number : 00000000
-
-[13Ch 0316 1] Subtable Type : 00 [Processor Hierarchy Node]
-[13Dh 0317 1] Length : 14
-[13Eh 0318 2] Reserved : 0000
-[140h 0320 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[144h 0324 4] Parent : 00000128
-[148h 0328 4] ACPI Processor ID : 00000006
-[14Ch 0332 4] Private Resource Number : 00000000
+[050h 0080 4] Flags (decoded below) : 000000FF
+ Size valid : 1
+ Number of Sets valid : 1
+ Associativity valid : 1
+ Allocation Type valid : 1
+ Cache Type valid : 1
+ Write Policy valid : 1
+ Line Size valid : 1
+[054h 0084 4] Next Level of Cache : 00000000
+[058h 0088 4] Size : 00200000
+[05Ch 0092 4] Number of Sets : 00000800
+[060h 0096 1] Associativity : 10
+[061h 0097 1] Attributes : 0F
+ Allocation Type : 3
+ Cache Type : 3
+ Write Policy : 0
+[062h 0098 2] Line Size : 0040
-[150h 0336 1] Subtable Type : 00 [Processor Hierarchy Node]
-[151h 0337 1] Length : 14
-[152h 0338 2] Reserved : 0000
-[154h 0340 4] Flags (decoded below) : 0000000E
- Physical package : 0
- ACPI Processor ID valid : 1
- Processor is a thread : 1
- Node is a leaf : 1
- Identical Implementation : 0
-[158h 0344 4] Parent : 00000128
-[15Ch 0348 4] ACPI Processor ID : 00000007
-[160h 0352 4] Private Resource Number : 00000000
+Invalid subtable length
-Raw Table Data: Length 356 (0x164)
+Raw Table Data: Length 636 (0x27C)
- 0000: 50 50 54 54 64 01 00 00 02 97 42 4F 43 48 53 20 // PPTTd.....BOCHS
+ 0000: 50 50 54 54 7C 02 00 00 02 C6 42 4F 43 48 53 20 // PPTT|.....BOCHS
0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC
0020: 01 00 00 00 00 14 00 00 11 00 00 00 00 00 00 00 // ................
0030: 00 00 00 00 00 00 00 00 00 14 00 00 11 00 00 00 // ................
- 0040: 24 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // $...............
- 0050: 10 00 00 00 38 00 00 00 00 00 00 00 00 00 00 00 // ....8...........
- 0060: 00 14 00 00 10 00 00 00 4C 00 00 00 00 00 00 00 // ........L.......
- 0070: 00 00 00 00 00 14 00 00 0E 00 00 00 60 00 00 00 // ............`...
- 0080: 00 00 00 00 00 00 00 00 00 14 00 00 0E 00 00 00 // ................
- 0090: 60 00 00 00 01 00 00 00 00 00 00 00 00 14 00 00 // `...............
- 00A0: 10 00 00 00 4C 00 00 00 01 00 00 00 00 00 00 00 // ....L...........
- 00B0: 00 14 00 00 0E 00 00 00 9C 00 00 00 02 00 00 00 // ................
- 00C0: 00 00 00 00 00 14 00 00 0E 00 00 00 9C 00 00 00 // ................
- 00D0: 03 00 00 00 00 00 00 00 00 14 00 00 10 00 00 00 // ................
- 00E0: 38 00 00 00 01 00 00 00 00 00 00 00 00 14 00 00 // 8...............
- 00F0: 10 00 00 00 D8 00 00 00 00 00 00 00 00 00 00 00 // ................
- 0100: 00 14 00 00 0E 00 00 00 EC 00 00 00 04 00 00 00 // ................
- 0110: 00 00 00 00 00 14 00 00 0E 00 00 00 EC 00 00 00 // ................
- 0120: 05 00 00 00 00 00 00 00 00 14 00 00 10 00 00 00 // ................
- 0130: D8 00 00 00 01 00 00 00 00 00 00 00 00 14 00 00 // ................
- 0140: 0E 00 00 00 28 01 00 00 06 00 00 00 00 00 00 00 // ....(...........
- 0150: 00 14 00 00 0E 00 00 00 28 01 00 00 07 00 00 00 // ........(.......
- 0160: 00 00 00 00 // ....
+ 0040: 24 00 00 00 00 00 00 00 00 00 00 00 01 1C 00 00 // $...............
+ 0050: FF 00 00 00 00 00 00 00 00 00 20 00 00 08 00 00 // .......... .....
+ 0060: 10 0F 40 00 00 18 00 00 10 00 00 00 38 00 00 00 // ..@.........8...
+ 0070: 00 00 00 00 01 00 00 00 4C 00 00 00 01 1C 00 00 // ........L.......
+ 0080: FF 00 00 00 00 00 00 00 00 80 00 00 80 00 00 00 // ................
+ 0090: 04 03 40 00 01 1C 00 00 FF 00 00 00 00 00 00 00 // ..@.............
+ 00A0: 00 C0 00 00 00 01 00 00 03 07 40 00 00 1C 00 00 // ..........@.....
+ 00B0: 10 00 00 00 64 00 00 00 00 00 00 00 02 00 00 00 // ....d...........
+ 00C0: 94 00 00 00 7C 00 00 00 00 14 00 00 0E 00 00 00 // ....|...........
+ 00D0: AC 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 // ................
+ 00E0: 0E 00 00 00 AC 00 00 00 01 00 00 00 00 00 00 00 // ................
+ 00F0: 01 1C 00 00 FF 00 00 00 00 00 00 00 00 80 00 00 // ................
+ 0100: 80 00 00 00 04 03 40 00 01 1C 00 00 FF 00 00 00 // ......@.........
+ 0110: 00 00 00 00 00 C0 00 00 00 01 00 00 03 07 40 00 // ..............@.
+ 0120: 00 1C 00 00 10 00 00 00 64 00 00 00 01 00 00 00 // ........d.......
+ 0130: 02 00 00 00 08 01 00 00 F0 00 00 00 00 14 00 00 // ................
+ 0140: 0E 00 00 00 20 01 00 00 02 00 00 00 00 00 00 00 // .... ...........
+ 0150: 00 14 00 00 0E 00 00 00 20 01 00 00 03 00 00 00 // ........ .......
+ 0160: 00 00 00 00 01 1C 00 00 FF 00 00 00 00 00 00 00 // ................
+ 0170: 00 00 20 00 00 08 00 00 10 0F 40 00 00 18 00 00 // .. .......@.....
+ 0180: 10 00 00 00 38 00 00 00 01 00 00 00 01 00 00 00 // ....8...........
+ 0190: 64 01 00 00 01 1C 00 00 FF 00 00 00 00 00 00 00 // d...............
+ 01A0: 00 80 00 00 80 00 00 00 04 03 40 00 01 1C 00 00 // ..........@.....
+ 01B0: FF 00 00 00 00 00 00 00 00 C0 00 00 00 01 00 00 // ................
+ 01C0: 03 07 40 00 00 1C 00 00 10 00 00 00 7C 01 00 00 // ..@.........|...
+ 01D0: 00 00 00 00 02 00 00 00 AC 01 00 00 94 01 00 00 // ................
+ 01E0: 00 14 00 00 0E 00 00 00 C4 01 00 00 04 00 00 00 // ................
+ 01F0: 00 00 00 00 00 14 00 00 0E 00 00 00 C4 01 00 00 // ................
+ 0200: 05 00 00 00 00 00 00 00 01 1C 00 00 FF 00 00 00 // ................
+ 0210: 00 00 00 00 00 80 00 00 80 00 00 00 04 03 40 00 // ..............@.
+ 0220: 01 1C 00 00 FF 00 00 00 00 00 00 00 00 C0 00 00 // ................
+ 0230: 00 01 00 00 03 07 40 00 00 1C 00 00 10 00 00 00 // ......@.........
+ 0240: 7C 01 00 00 01 00 00 00 02 00 00 00 20 02 00 00 // |........... ...
+ 0250: 08 02 00 00 00 14 00 00 0E 00 00 00 38 02 00 00 // ............8...
+ 0260: 06 00 00 00 00 00 00 00 00 14 00 00 0E 00 00 00 // ................
+ 0270: 38 02 00 00 07 00 00 00 00 00 00 00 // 8...........
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
---
tests/data/acpi/aarch64/virt/PPTT | Bin 96 -> 176 bytes
tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt | Bin 176 -> 496 bytes
tests/data/acpi/aarch64/virt/PPTT.topology | Bin 356 -> 676 bytes
tests/qtest/bios-tables-test-allowed-diff.h | 3 ---
4 files changed, 3 deletions(-)
diff --git a/tests/data/acpi/aarch64/virt/PPTT b/tests/data/acpi/aarch64/virt/PPTT
index 15598a9b8a3cc0cdd50bc1f77c73ae0ba728a272..43b9b7047ad93eee1d2ac0a9b08d22d73bebdf54 100644
GIT binary patch
literal 176
zcmWFt2npH1z`($y;pFe^5v<@85#X!<1dKp25F11@h%hh+f@ov_6;nYHW0YZF_z&kR
zFfed1FbMEFFu=rpKynRW#K6LgCVl`Y2egct-GPAtXbu;UYXQU{zy!oKK%4@^02kX2
A0RR91
delta 38
kcmdnMn7|bf5E7EWz`($yK9S2wgh7OXfeXm90Ad&b0DQ6pGynhq
diff --git a/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt b/tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt
index 7b613ddaf4b8cfa13821aa2e835d290077221897..fc318de992302251ad33b6e74c1632d281ff56e5 100644
GIT binary patch
literal 496
zcmah_F$%&!5S-)$#YTmc7FSsK1j~>#7J>m&<N-dzA`kExd4LbFxJrD6Pw)pia~L^I
zAVY@TojG>c6h&D+BOtzI`+R$_Sykkgpak`*NPvZEh>x}kv}g&uzOw};z<idX)pzo0
z|6yeQbVrY2W}E`tGv&A;g_t~%N3z|;mav_Si{!eS;dMu^CxepDc(C5d_Fmm4PZ-Kw
r>tWr^^}5r7-`f(-x=XCsr{qw^nQ!_syzc1H5C5Ms3}t0p**D}HPG2ek
literal 176
zcmWFt2npH1z`(%7>*Vk35v<@85#X!<1dKp25F11@h%hh+f@ov_6;nYI;{x(6aEO7;
b0?8riMHU0;EdgRCkQxvGs)LC!Lqr$=thxyS
diff --git a/tests/data/acpi/aarch64/virt/PPTT.topology b/tests/data/acpi/aarch64/virt/PPTT.topology
index 6b864f035c9f48845e9a3beb482c5171074864a5..cdbc482d467fc6987ab3ddf3ca38d987adfe484b 100644
GIT binary patch
literal 676
zcmaixy$!-J6ofB7{8SJm3JQu83_w9ai4uwwNJN5yk})VV00l!(Fa$-0U<`JEJL4de
zAmtRt?|sjHzBqZl-(P*eUnko%+r`NtPh-jhpjb1;z(}(z%VsqeF<&~&n*y(I9s_+K
z8m>_BqiThD5C%0~vPJ_zZw0WAdT%%+TE>Orq=a4uoNkIMIm~<md3EMzN!;-ARH0~k
zF}!5$j~Dfpmnnl#i9L70Slq~Afy1i1(l)8h-&qTbra!|=HTb=&lWi;?cg9!c*2{x&
s$kfPT9gEt$Ow_b!dNI6Yjs4yKCNDZ(+cLi93hcQ@#$BdH4(nO;2Hztu0RR91
literal 356
zcmWFt2nk7HWME*L?&R<65v<@85#X!<1VAAM5F11@h%hh+f@ov_6;nYI69Dopu!#Af
ziSYsX2{^>Sc7o)9c7V(S=|vU;>74__Oh60<Ky@%NW+X9~TafjF#BRXUfM}@RH$Wx}
cOdLs!6-f-H7uh_Jy&6CPHY9a0F?OgJ00?&w0RR91
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index e84d6c695520..dfb8523c8bf4 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,4 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/aarch64/virt/PPTT",
-"tests/data/acpi/aarch64/virt/PPTT.acpihmatvirt",
-"tests/data/acpi/aarch64/virt/PPTT.topology",
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread