diff --git a/1179-hw-core-machine-smp-Deprecate-unsupported-parameter-.patch b/1179-hw-core-machine-smp-Deprecate-unsupported-parameter-.patch new file mode 100644 index 0000000000000000000000000000000000000000..851264ad3be76fd5fa849016e1671afce5c45f25 --- /dev/null +++ b/1179-hw-core-machine-smp-Deprecate-unsupported-parameter-.patch @@ -0,0 +1,154 @@ +From 971cf97e6c9f6778fa055ff2efe474b01ff0c2c5 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Sat, 9 Mar 2024 00:01:37 +0800 +Subject: [PATCH 01/83] hw/core/machine-smp: Deprecate unsupported + "parameter=1" SMP configurations +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 54c4ea8f3ae614054079395842128a856a73dbf9 upstream. + +Currently, it was allowed for users to specify the unsupported +topology parameter as "1". For example, x86 PC machine doesn't +support drawer/book/cluster topology levels, but user could specify +"-smp drawers=1,books=1,clusters=1". + +This is meaningless and confusing, so that the support for this kind of +configurations is marked deprecated since 9.0. And report warning +message for such case like: + +qemu-system-x86_64: warning: Deprecated CPU topology (considered invalid): + Unsupported clusters parameter mustn't be specified as 1 +qemu-system-x86_64: warning: Deprecated CPU topology (considered invalid): + Unsupported books parameter mustn't be specified as 1 +qemu-system-x86_64: warning: Deprecated CPU topology (considered invalid): + Unsupported drawers parameter mustn't be specified as 1 + +Users have to ensure that all the topology members described with -smp +are supported by the target machine. + +Intel-SIG: commit 54c4ea8f3ae6 hw/core/machine-smp: Deprecate unsupported "parameter=1" SMP configurations. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Thomas Huth +Message-ID: <20240308160148.3130837-3-zhao1.liu@linux.intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + docs/about/deprecated.rst | 14 +++++++++ + hw/core/machine-smp.c | 63 +++++++++++++++++++++++++++++---------- + 2 files changed, 61 insertions(+), 16 deletions(-) + +diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst +index 2e150402465..f90a3da10ef 100644 +--- a/docs/about/deprecated.rst ++++ b/docs/about/deprecated.rst +@@ -102,6 +102,20 @@ The ``-singlestep`` option has been given a name that better reflects + what it actually does. For both linux-user and bsd-user, use the + new ``-one-insn-per-tb`` option instead. + ++``-smp`` (Unsupported "parameter=1" SMP configurations) (since 9.0) ++''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ++ ++Specified CPU topology parameters must be supported by the machine. ++ ++In the SMP configuration, users should provide the CPU topology parameters that ++are supported by the target machine. ++ ++However, historically it was allowed for users to specify the unsupported ++topology parameter as "1", which is meaningless. So support for this kind of ++configurations (e.g. -smp drawers=1,books=1,clusters=1 for x86 PC machine) is ++marked deprecated since 9.0, users have to ensure that all the topology members ++described with -smp are supported by the target machine. ++ + QEMU Machine Protocol (QMP) commands + ------------------------------------ + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 25019c91ee3..88cc4d9666d 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -111,30 +111,61 @@ void machine_parse_smp_config(MachineState *ms, + + /* + * If not supported by the machine, a topology parameter must be +- * omitted or specified equal to 1. ++ * omitted. + */ +- if (!mc->smp_props.dies_supported && dies > 1) { +- error_setg(errp, "dies not supported by this machine's CPU topology"); +- return; +- } +- if (!mc->smp_props.clusters_supported && clusters > 1) { +- error_setg(errp, "clusters not supported by this machine's CPU topology"); +- return; ++ if (!mc->smp_props.clusters_supported && config->has_clusters) { ++ if (config->clusters > 1) { ++ error_setg(errp, "clusters not supported by this " ++ "machine's CPU topology"); ++ return; ++ } else { ++ /* Here clusters only equals 1 since we've checked zero case. */ ++ warn_report("Deprecated CPU topology (considered invalid): " ++ "Unsupported clusters parameter mustn't be " ++ "specified as 1"); ++ } + } ++ clusters = clusters > 0 ? clusters : 1; + ++ if (!mc->smp_props.dies_supported && config->has_dies) { ++ if (config->dies > 1) { ++ error_setg(errp, "dies not supported by this " ++ "machine's CPU topology"); ++ return; ++ } else { ++ /* Here dies only equals 1 since we've checked zero case. */ ++ warn_report("Deprecated CPU topology (considered invalid): " ++ "Unsupported dies parameter mustn't be " ++ "specified as 1"); ++ } ++ } + dies = dies > 0 ? dies : 1; +- clusters = clusters > 0 ? clusters : 1; + +- if (!mc->smp_props.books_supported && books > 1) { +- error_setg(errp, "books not supported by this machine's CPU topology"); +- return; ++ if (!mc->smp_props.books_supported && config->has_books) { ++ if (config->books > 1) { ++ error_setg(errp, "books not supported by this " ++ "machine's CPU topology"); ++ return; ++ } else { ++ /* Here books only equals 1 since we've checked zero case. */ ++ warn_report("Deprecated CPU topology (considered invalid): " ++ "Unsupported books parameter mustn't be " ++ "specified as 1"); ++ } + } + books = books > 0 ? books : 1; + +- if (!mc->smp_props.drawers_supported && drawers > 1) { +- error_setg(errp, +- "drawers not supported by this machine's CPU topology"); +- return; ++ if (!mc->smp_props.drawers_supported && config->has_drawers) { ++ if (config->drawers > 1) { ++ error_setg(errp, "drawers not supported by this " ++ "machine's CPU topology"); ++ return; ++ } else { ++ /* Here drawers only equals 1 since we've checked zero case. */ ++ warn_report("Deprecated CPU topology (considered invalid): " ++ "Unsupported drawers parameter mustn't be " ++ "specified as 1"); ++ } + } + drawers = drawers > 0 ? drawers : 1; + +-- +2.47.3 + diff --git a/1180-hw-core-machine-smp-Calculate-total-CPUs-once-in-mac.patch b/1180-hw-core-machine-smp-Calculate-total-CPUs-once-in-mac.patch new file mode 100644 index 0000000000000000000000000000000000000000..75e9a604e08c8433073da6bf42663a7c5ab80104 --- /dev/null +++ b/1180-hw-core-machine-smp-Calculate-total-CPUs-once-in-mac.patch @@ -0,0 +1,69 @@ +From 9d962afd04294b0df8ad8887d4b8f7c3d0183942 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Sat, 9 Mar 2024 00:01:38 +0800 +Subject: [PATCH 02/83] hw/core/machine-smp: Calculate total CPUs once in + machine_parse_smp_config() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 4503dcf77b9006b56dba01a407bffbb9a37ea38e upstream. + +In machine_parse_smp_config(), the number of total CPUs is calculated +by: + + drawers * books * sockets * dies * clusters * cores * threads + +To avoid missing the future new topology level, use a local variable to +cache the calculation result so that total CPUs are only calculated +once. + +Intel-SIG: commit 4503dcf77b90 hw/core/machine-smp: Calculate total CPUs once in machine_parse_smp_config(). +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20240308160148.3130837-4-zhao1.liu@linux.intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 88cc4d9666d..ffae4e75759 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -91,6 +91,7 @@ void machine_parse_smp_config(MachineState *ms, + unsigned cores = config->has_cores ? config->cores : 0; + unsigned threads = config->has_threads ? config->threads : 0; + unsigned maxcpus = config->has_maxcpus ? config->maxcpus : 0; ++ unsigned total_cpus; + + /* + * Specified CPU topology parameters must be greater than zero, +@@ -210,8 +211,8 @@ void machine_parse_smp_config(MachineState *ms, + } + } + +- maxcpus = maxcpus > 0 ? maxcpus : drawers * books * sockets * dies * +- clusters * cores * threads; ++ total_cpus = drawers * books * sockets * dies * clusters * cores * threads; ++ maxcpus = maxcpus > 0 ? maxcpus : total_cpus; + cpus = cpus > 0 ? cpus : maxcpus; + + ms->smp.cpus = cpus; +@@ -227,8 +228,7 @@ void machine_parse_smp_config(MachineState *ms, + mc->smp_props.has_clusters = config->has_clusters; + + /* sanity-check of the computed topology */ +- if (drawers * books * sockets * dies * clusters * cores * threads != +- maxcpus) { ++ if (total_cpus != maxcpus) { + g_autofree char *topo_msg = cpu_hierarchy_to_string(ms); + error_setg(errp, "Invalid CPU topology: " + "product of the hierarchy must match maxcpus: " +-- +2.47.3 + diff --git a/1181-hw-core-machine-Introduce-the-module-as-a-CPU-topolo.patch b/1181-hw-core-machine-Introduce-the-module-as-a-CPU-topolo.patch new file mode 100644 index 0000000000000000000000000000000000000000..712037b4b32aa5ba4f04cdeaa0835134c29e517b --- /dev/null +++ b/1181-hw-core-machine-Introduce-the-module-as-a-CPU-topolo.patch @@ -0,0 +1,130 @@ +From 51e6d693b2793c129ff553d7eed3b5b6eac6b245 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:09 +0800 +Subject: [PATCH 03/83] hw/core/machine: Introduce the module as a CPU topology + level +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit dcba73b4453b7ed74d2ae24c5c8b273431c4484c upstream. + +In x86, module is the topology level above core, which contains a set +of cores that share certain resources (in current products, the resource +usually includes L2 cache, as well as module scoped features and MSRs). + +Though smp.clusters could also share the L2 cache resource [1], there +are following reasons that drive us to introduce the new smp.modules: + + * As the CPU topology abstraction in device tree [2], cluster supports + nesting (though currently QEMU hasn't support that). In contrast, + (x86) module does not support nesting. + + * Due to nesting, there is great flexibility in sharing resources + on cluster, rather than narrowing cluster down to sharing L2 (and + L3 tags) as the lowest topology level that contains cores. + + * Flexible nesting of cluster allows it to correspond to any level + between the x86 package and core. + + * In Linux kernel, x86's cluster only represents the L2 cache domain + but QEMU's smp.clusters is the CPU topology level. Linux kernel will + also expose module level topology information in sysfs for x86. To + avoid cluster ambiguity and keep a consistent CPU topology naming + style with the Linux kernel, we introduce module level for x86. + +The module is, in existing hardware practice, the lowest layer that +contains the core, while the cluster is able to have a higher +topological scope than the module due to its nesting. + +Therefore, place the module between the cluster and the core: + + drawer/book/socket/die/cluster/module/core/thread + +With the above topological hierarchy order, introduce module level +support in MachineState and MachineClass. + +[1]: https://lore.kernel.org/qemu-devel/c3d68005-54e0-b8fe-8dc1-5989fe3c7e69@huawei.com/ +[2]: https://www.kernel.org/doc/Documentation/devicetree/bindings/cpu/cpu-topology.txt + +Intel-SIG: commit dcba73b4453b hw/core/machine: Introduce the module as a CPU topology level. +CPU new topology backporting + +Suggested-by: Xiaoyao Li +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-2-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 2 +- + hw/core/machine.c | 1 + + include/hw/boards.h | 4 ++++ + 3 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index ffae4e75759..ce19e0e63a9 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -265,7 +265,7 @@ void machine_parse_smp_config(MachineState *ms, + + unsigned int machine_topo_get_cores_per_socket(const MachineState *ms) + { +- return ms->smp.cores * ms->smp.clusters * ms->smp.dies; ++ return ms->smp.cores * ms->smp.modules * ms->smp.clusters * ms->smp.dies; + } + + unsigned int machine_topo_get_threads_per_socket(const MachineState *ms) +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 0c173981412..71b54c37020 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -1145,6 +1145,7 @@ static void machine_initfn(Object *obj) + ms->smp.sockets = 1; + ms->smp.dies = 1; + ms->smp.clusters = 1; ++ ms->smp.modules = 1; + ms->smp.cores = 1; + ms->smp.threads = 1; + +diff --git a/include/hw/boards.h b/include/hw/boards.h +index 8ac8cad2a22..642aa5532e2 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -137,6 +137,7 @@ typedef struct { + * provided SMP configuration + * @books_supported - whether books are supported by the machine + * @drawers_supported - whether drawers are supported by the machine ++ * @modules_supported - whether modules are supported by the machine + */ + typedef struct { + bool prefer_sockets; +@@ -145,6 +146,7 @@ typedef struct { + bool has_clusters; + bool books_supported; + bool drawers_supported; ++ bool modules_supported; + } SMPCompatProps; + + /** +@@ -332,6 +334,7 @@ typedef struct DeviceMemoryState { + * @sockets: the number of sockets in one book + * @dies: the number of dies in one socket + * @clusters: the number of clusters in one die ++ * @modules: the number of modules in one cluster + * @cores: the number of cores in one cluster + * @threads: the number of threads in one core + * @max_cpus: the maximum number of logical processors on the machine +@@ -343,6 +346,7 @@ typedef struct CpuTopology { + unsigned int sockets; + unsigned int dies; + unsigned int clusters; ++ unsigned int modules; + unsigned int cores; + unsigned int threads; + unsigned int max_cpus; +-- +2.47.3 + diff --git a/1182-hw-core-Introduce-module-id-as-the-topology-subindex.patch b/1182-hw-core-Introduce-module-id-as-the-topology-subindex.patch new file mode 100644 index 0000000000000000000000000000000000000000..8eeea790428eaf373997913ce638160fb849cf7e --- /dev/null +++ b/1182-hw-core-Introduce-module-id-as-the-topology-subindex.patch @@ -0,0 +1,70 @@ +From 912ef76d24095c1418fb2fe4ca2a494eb72c7215 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:11 +0800 +Subject: [PATCH 04/83] hw/core: Introduce module-id as the topology subindex +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 989bb312b021d66927db8e5f443503d63722b38d upstream. + +Add module-id in CpuInstanceProperties, to locate the CPU with module +level. + +Intel-SIG: commit 989bb312b021 hw/core: Introduce module-id as the topology subindex. +CPU new topology backporting + +Suggested-by: Xiaoyao Li +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Acked-by: Markus Armbruster +Message-ID: <20240424154929.1487382-4-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-hmp-cmds.c | 4 ++++ + qapi/machine.json | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c +index a6ff6a48758..8701f00cc7c 100644 +--- a/hw/core/machine-hmp-cmds.c ++++ b/hw/core/machine-hmp-cmds.c +@@ -87,6 +87,10 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict) + monitor_printf(mon, " cluster-id: \"%" PRIu64 "\"\n", + c->cluster_id); + } ++ if (c->has_module_id) { ++ monitor_printf(mon, " module-id: \"%" PRIu64 "\"\n", ++ c->module_id); ++ } + if (c->has_core_id) { + monitor_printf(mon, " core-id: \"%" PRIu64 "\"\n", c->core_id); + } +diff --git a/qapi/machine.json b/qapi/machine.json +index b6d634b30d5..7af137a0c27 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -931,6 +931,9 @@ + # @cluster-id: cluster number within the parent container the CPU + # belongs to (since 7.1) + # ++# @module-id: module number within the parent container the CPU belongs ++# to (since 9.1) ++# + # @core-id: core number within the parent container the CPU + # belongs to + # +@@ -949,6 +952,7 @@ + '*socket-id': 'int', + '*die-id': 'int', + '*cluster-id': 'int', ++ '*module-id': 'int', + '*core-id': 'int', + '*thread-id': 'int' + } +-- +2.47.3 + diff --git a/1183-hw-core-machine-Support-modules-in-smp.patch b/1183-hw-core-machine-Support-modules-in-smp.patch new file mode 100644 index 0000000000000000000000000000000000000000..d6c70dd1145362894f2aae74bd3ef902f0de1b7a --- /dev/null +++ b/1183-hw-core-machine-Support-modules-in-smp.patch @@ -0,0 +1,188 @@ +From 262c616d429f06ca8c0f765d3a14b1d079c1394c Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:10 +0800 +Subject: [PATCH 05/83] hw/core/machine: Support modules in -smp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 8ec0a46347987c74464fe67c42030d074fe8c0f0 upstream. + +Add "modules" parameter parsing support in -smp. + +Intel-SIG: commit 8ec0a4634798 hw/core/machine: Support modules in -smp. +CPU new topology backporting + +Suggested-by: Xiaoyao Li +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Acked-by: Markus Armbruster +Message-ID: <20240424154929.1487382-3-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 39 +++++++++++++++++++++++++++++++++------ + hw/core/machine.c | 1 + + qapi/machine.json | 3 +++ + system/vl.c | 3 +++ + 4 files changed, 40 insertions(+), 6 deletions(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index ce19e0e63a9..cfb4beb0baa 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -51,6 +51,10 @@ static char *cpu_hierarchy_to_string(MachineState *ms) + g_string_append_printf(s, " * clusters (%u)", ms->smp.clusters); + } + ++ if (mc->smp_props.modules_supported) { ++ g_string_append_printf(s, " * modules (%u)", ms->smp.modules); ++ } ++ + g_string_append_printf(s, " * cores (%u)", ms->smp.cores); + g_string_append_printf(s, " * threads (%u)", ms->smp.threads); + +@@ -88,6 +92,7 @@ void machine_parse_smp_config(MachineState *ms, + unsigned sockets = config->has_sockets ? config->sockets : 0; + unsigned dies = config->has_dies ? config->dies : 0; + unsigned clusters = config->has_clusters ? config->clusters : 0; ++ unsigned modules = config->has_modules ? config->modules : 0; + unsigned cores = config->has_cores ? config->cores : 0; + unsigned threads = config->has_threads ? config->threads : 0; + unsigned maxcpus = config->has_maxcpus ? config->maxcpus : 0; +@@ -103,6 +108,7 @@ void machine_parse_smp_config(MachineState *ms, + (config->has_sockets && config->sockets == 0) || + (config->has_dies && config->dies == 0) || + (config->has_clusters && config->clusters == 0) || ++ (config->has_modules && config->modules == 0) || + (config->has_cores && config->cores == 0) || + (config->has_threads && config->threads == 0) || + (config->has_maxcpus && config->maxcpus == 0)) { +@@ -114,6 +120,20 @@ void machine_parse_smp_config(MachineState *ms, + * If not supported by the machine, a topology parameter must be + * omitted. + */ ++ if (!mc->smp_props.modules_supported && config->has_modules) { ++ if (config->modules > 1) { ++ error_setg(errp, "modules not supported by this " ++ "machine's CPU topology"); ++ return; ++ } else { ++ /* Here modules only equals 1 since we've checked zero case. */ ++ warn_report("Deprecated CPU topology (considered invalid): " ++ "Unsupported modules parameter mustn't be " ++ "specified as 1"); ++ } ++ } ++ modules = modules > 0 ? modules : 1; ++ + if (!mc->smp_props.clusters_supported && config->has_clusters) { + if (config->clusters > 1) { + error_setg(errp, "clusters not supported by this " +@@ -184,11 +204,13 @@ void machine_parse_smp_config(MachineState *ms, + cores = cores > 0 ? cores : 1; + threads = threads > 0 ? threads : 1; + sockets = maxcpus / +- (drawers * books * dies * clusters * cores * threads); ++ (drawers * books * dies * clusters * ++ modules * cores * threads); + } else if (cores == 0) { + threads = threads > 0 ? threads : 1; + cores = maxcpus / +- (drawers * books * sockets * dies * clusters * threads); ++ (drawers * books * sockets * dies * ++ clusters * modules * threads); + } + } else { + /* prefer cores over sockets since 6.2 */ +@@ -196,22 +218,26 @@ void machine_parse_smp_config(MachineState *ms, + sockets = sockets > 0 ? sockets : 1; + threads = threads > 0 ? threads : 1; + cores = maxcpus / +- (drawers * books * sockets * dies * clusters * threads); ++ (drawers * books * sockets * dies * ++ clusters * modules * threads); + } else if (sockets == 0) { + threads = threads > 0 ? threads : 1; + sockets = maxcpus / +- (drawers * books * dies * clusters * cores * threads); ++ (drawers * books * dies * clusters * ++ modules * cores * threads); + } + } + + /* try to calculate omitted threads at last */ + if (threads == 0) { + threads = maxcpus / +- (drawers * books * sockets * dies * clusters * cores); ++ (drawers * books * sockets * dies * ++ clusters * modules * cores); + } + } + +- total_cpus = drawers * books * sockets * dies * clusters * cores * threads; ++ total_cpus = drawers * books * sockets * dies * ++ clusters * modules * cores * threads; + maxcpus = maxcpus > 0 ? maxcpus : total_cpus; + cpus = cpus > 0 ? cpus : maxcpus; + +@@ -221,6 +247,7 @@ void machine_parse_smp_config(MachineState *ms, + ms->smp.sockets = sockets; + ms->smp.dies = dies; + ms->smp.clusters = clusters; ++ ms->smp.modules = modules; + ms->smp.cores = cores; + ms->smp.threads = threads; + ms->smp.max_cpus = maxcpus; +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 71b54c37020..7f2e1423885 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -869,6 +869,7 @@ static void machine_get_smp(Object *obj, Visitor *v, const char *name, + .has_sockets = true, .sockets = ms->smp.sockets, + .has_dies = true, .dies = ms->smp.dies, + .has_clusters = true, .clusters = ms->smp.clusters, ++ .has_modules = true, .modules = ms->smp.modules, + .has_cores = true, .cores = ms->smp.cores, + .has_threads = true, .threads = ms->smp.threads, + .has_maxcpus = true, .maxcpus = ms->smp.max_cpus, +diff --git a/qapi/machine.json b/qapi/machine.json +index 7af137a0c27..10d76717c0e 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -1630,6 +1630,8 @@ + # + # @clusters: number of clusters per parent container (since 7.0) + # ++# @modules: number of modules per parent container (since 9.1) ++# + # @cores: number of cores per parent container + # + # @threads: number of threads per core +@@ -1643,6 +1645,7 @@ + '*sockets': 'int', + '*dies': 'int', + '*clusters': 'int', ++ '*modules': 'int', + '*cores': 'int', + '*threads': 'int', + '*maxcpus': 'int' } } +diff --git a/system/vl.c b/system/vl.c +index 338558d9b6f..f09d6c786ec 100644 +--- a/system/vl.c ++++ b/system/vl.c +@@ -759,6 +759,9 @@ static QemuOptsList qemu_smp_opts = { + }, { + .name = "clusters", + .type = QEMU_OPT_NUMBER, ++ }, { ++ .name = "modules", ++ .type = QEMU_OPT_NUMBER, + }, { + .name = "cores", + .type = QEMU_OPT_NUMBER, +-- +2.47.3 + diff --git a/1184-hw-core-Support-module-id-in-numa-configuration.patch b/1184-hw-core-Support-module-id-in-numa-configuration.patch new file mode 100644 index 0000000000000000000000000000000000000000..288f37eb7d71cb69e8350f662b2458f17368bc4e --- /dev/null +++ b/1184-hw-core-Support-module-id-in-numa-configuration.patch @@ -0,0 +1,75 @@ +From ab4c39e346e9ddf676d204527a3b54ae93ba7d45 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:12 +0800 +Subject: [PATCH 06/83] hw/core: Support module-id in numa configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 098de99aad1aa911b4950b47b55d2e2bcc4f9c0c upstream. + +Module is a level above the core, thereby supporting numa +configuration on the module level can bring user more numa flexibility. + +This is the natural further support for module level. + +Add module level support in numa configuration. + +Intel-SIG: commit 098de99aad1a hw/core: Support module-id in numa configuration. +CPU new topology backporting + +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-5-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 7f2e1423885..1d1e9ce0f03 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -788,6 +788,11 @@ void machine_set_cpu_numa_node(MachineState *machine, + return; + } + ++ if (props->has_module_id && !slot->props.has_module_id) { ++ error_setg(errp, "module-id is not supported"); ++ return; ++ } ++ + if (props->has_cluster_id && !slot->props.has_cluster_id) { + error_setg(errp, "cluster-id is not supported"); + return; +@@ -812,6 +817,11 @@ void machine_set_cpu_numa_node(MachineState *machine, + continue; + } + ++ if (props->has_module_id && ++ props->module_id != slot->props.module_id) { ++ continue; ++ } ++ + if (props->has_cluster_id && + props->cluster_id != slot->props.cluster_id) { + continue; +@@ -1209,6 +1219,12 @@ static char *cpu_slot_to_string(const CPUArchId *cpu) + } + g_string_append_printf(s, "cluster-id: %"PRId64, cpu->props.cluster_id); + } ++ if (cpu->props.has_module_id) { ++ if (s->len) { ++ g_string_append_printf(s, ", "); ++ } ++ g_string_append_printf(s, "module-id: %"PRId64, cpu->props.module_id); ++ } + if (cpu->props.has_core_id) { + if (s->len) { + g_string_append_printf(s, ", "); +-- +2.47.3 + diff --git a/1185-hw-i386-split-x86.c-in-multiple-parts.patch b/1185-hw-i386-split-x86.c-in-multiple-parts.patch new file mode 100644 index 0000000000000000000000000000000000000000..32c9296320148a69bafe3ead505de8dd064e83d9 --- /dev/null +++ b/1185-hw-i386-split-x86.c-in-multiple-parts.patch @@ -0,0 +1,2300 @@ +From 017b694d513f81dc84dbfcaa68e85146be94783b Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 9 May 2024 19:00:41 +0200 +Subject: [PATCH 07/83] hw/i386: split x86.c in multiple parts + +commit b061f0598b9231f7992aff4fcdf3f336f9747d11 upstream. + +Keep the basic X86MachineState definition in x86.c. Move out functions that +are only needed by other files: x86-common.c for the pc and microvm machines, +x86-cpu.c for those used by accelerator code. + +Intel-SIG: commit b061f0598b92 hw/i386: split x86.c in multiple parts. +CPU new topology backporting + +Signed-off-by: Paolo Bonzini +Reviewed-by: Zhao Liu +Message-ID: <20240509170044.190795-11-pbonzini@redhat.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/meson.build | 4 +- + hw/i386/x86-common.c | 1011 +++++++++++++++++++++++++++++++++++++++ + hw/i386/x86-cpu.c | 97 ++++ + hw/i386/x86.c | 1056 +---------------------------------------- + include/hw/i386/x86.h | 4 +- + 5 files changed, 1117 insertions(+), 1055 deletions(-) + create mode 100644 hw/i386/x86-common.c + create mode 100644 hw/i386/x86-cpu.c + +diff --git a/hw/i386/meson.build b/hw/i386/meson.build +index 369c6bf823b..1341361edaa 100644 +--- a/hw/i386/meson.build ++++ b/hw/i386/meson.build +@@ -5,13 +5,14 @@ i386_ss.add(files( + 'e820_memory_layout.c', + 'multiboot.c', + 'x86.c', ++ 'x86-cpu.c', + )) + + i386_ss.add(when: 'CONFIG_X86_IOMMU', if_true: files('x86-iommu.c'), + if_false: files('x86-iommu-stub.c')) + i386_ss.add(when: 'CONFIG_AMD_IOMMU', if_true: files('amd_iommu.c')) + i386_ss.add(when: 'CONFIG_I440FX', if_true: files('pc_piix.c')) +-i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('microvm.c', 'acpi-microvm.c', 'microvm-dt.c')) ++i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('x86-common.c', 'microvm.c', 'acpi-microvm.c', 'microvm-dt.c')) + i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c')) + i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c')) + i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c')) +@@ -21,6 +22,7 @@ i386_ss.add(when: 'CONFIG_SGX', if_true: files('sgx-epc.c','sgx.c'), + + i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c')) + i386_ss.add(when: 'CONFIG_PC', if_true: files( ++ 'x86-common.c', + 'pc.c', + 'pc_sysfw.c', + 'acpi-build.c', +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +new file mode 100644 +index 00000000000..d4f561102c2 +--- /dev/null ++++ b/hw/i386/x86-common.c +@@ -0,0 +1,1011 @@ ++/* ++ * Copyright (c) 2003-2004 Fabrice Bellard ++ * Copyright (c) 2019, 2024 Red Hat, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++#include "qemu/osdep.h" ++#include "qemu/error-report.h" ++#include "qemu/cutils.h" ++#include "qemu/units.h" ++#include "qemu/datadir.h" ++#include "qapi/error.h" ++#include "sysemu/numa.h" ++#include "sysemu/sysemu.h" ++#include "sysemu/xen.h" ++#include "trace.h" ++ ++#include "hw/i386/x86.h" ++#include "target/i386/cpu.h" ++#include "hw/rtc/mc146818rtc.h" ++#include "target/i386/sev.h" ++ ++#include "hw/acpi/cpu_hotplug.h" ++#include "hw/irq.h" ++#include "hw/loader.h" ++#include "multiboot.h" ++#include "elf.h" ++#include "standard-headers/asm-x86/bootparam.h" ++#include CONFIG_DEVICES ++#include "kvm/kvm_i386.h" ++ ++#ifdef CONFIG_XEN_EMU ++#include "hw/xen/xen.h" ++#include "hw/i386/kvm/xen_evtchn.h" ++#endif ++ ++/* Physical Address of PVH entry point read from kernel ELF NOTE */ ++static size_t pvh_start_addr; ++ ++void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp) ++{ ++ Object *cpu = object_new(MACHINE(x86ms)->cpu_type); ++ ++ if (!object_property_set_uint(cpu, "apic-id", apic_id, errp)) { ++ goto out; ++ } ++ qdev_realize(DEVICE(cpu), NULL, errp); ++ ++out: ++ object_unref(cpu); ++} ++ ++void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) ++{ ++ int i; ++ const CPUArchIdList *possible_cpus; ++ MachineState *ms = MACHINE(x86ms); ++ MachineClass *mc = MACHINE_GET_CLASS(x86ms); ++ ++ x86_cpu_set_default_version(default_cpu_version); ++ ++ /* ++ * Calculates the limit to CPU APIC ID values ++ * ++ * Limit for the APIC ID value, so that all ++ * CPU APIC IDs are < x86ms->apic_id_limit. ++ * ++ * This is used for FW_CFG_MAX_CPUS. See comments on fw_cfg_arch_create(). ++ */ ++ x86ms->apic_id_limit = x86_cpu_apic_id_from_index(x86ms, ++ ms->smp.max_cpus - 1) + 1; ++ ++ /* ++ * Can we support APIC ID 255 or higher? With KVM, that requires ++ * both in-kernel lapic and X2APIC userspace API. ++ * ++ * kvm_enabled() must go first to ensure that kvm_* references are ++ * not emitted for the linker to consume (kvm_enabled() is ++ * a literal `0` in configurations where kvm_* aren't defined) ++ */ ++ if (kvm_enabled() && x86ms->apic_id_limit > 255 && ++ (!kvm_irqchip_in_kernel() || !kvm_enable_x2apic())) { ++ error_report("current -smp configuration requires kernel " ++ "irqchip and X2APIC API support."); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (kvm_enabled()) { ++ kvm_set_max_apic_id(x86ms->apic_id_limit); ++ } ++ ++ possible_cpus = mc->possible_cpu_arch_ids(ms); ++ for (i = 0; i < ms->smp.cpus; i++) { ++ x86_cpu_new(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal); ++ } ++} ++ ++void x86_rtc_set_cpus_count(ISADevice *s, uint16_t cpus_count) ++{ ++ MC146818RtcState *rtc = MC146818_RTC(s); ++ ++ if (cpus_count > 0xff) { ++ /* ++ * If the number of CPUs can't be represented in 8 bits, the ++ * BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just ++ * to make old BIOSes fail more predictably. ++ */ ++ mc146818rtc_set_cmos_data(rtc, 0x5f, 0); ++ } else { ++ mc146818rtc_set_cmos_data(rtc, 0x5f, cpus_count - 1); ++ } ++} ++ ++static int x86_apic_cmp(const void *a, const void *b) ++{ ++ CPUArchId *apic_a = (CPUArchId *)a; ++ CPUArchId *apic_b = (CPUArchId *)b; ++ ++ return apic_a->arch_id - apic_b->arch_id; ++} ++ ++/* ++ * returns pointer to CPUArchId descriptor that matches CPU's apic_id ++ * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no ++ * entry corresponding to CPU's apic_id returns NULL. ++ */ ++CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx) ++{ ++ CPUArchId apic_id, *found_cpu; ++ ++ apic_id.arch_id = id; ++ found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus, ++ ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus), ++ x86_apic_cmp); ++ if (found_cpu && idx) { ++ *idx = found_cpu - ms->possible_cpus->cpus; ++ } ++ return found_cpu; ++} ++ ++void x86_cpu_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ CPUArchId *found_cpu; ++ Error *local_err = NULL; ++ X86CPU *cpu = X86_CPU(dev); ++ X86MachineState *x86ms = X86_MACHINE(hotplug_dev); ++ ++ if (x86ms->acpi_dev) { ++ hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err); ++ if (local_err) { ++ goto out; ++ } ++ } ++ ++ /* increment the number of CPUs */ ++ x86ms->boot_cpus++; ++ if (x86ms->rtc) { ++ x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); ++ } ++ if (x86ms->fw_cfg) { ++ fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); ++ } ++ ++ found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL); ++ found_cpu->cpu = OBJECT(dev); ++out: ++ error_propagate(errp, local_err); ++} ++ ++void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ int idx = -1; ++ X86CPU *cpu = X86_CPU(dev); ++ X86MachineState *x86ms = X86_MACHINE(hotplug_dev); ++ ++ if (!x86ms->acpi_dev) { ++ error_setg(errp, "CPU hot unplug not supported without ACPI"); ++ return; ++ } ++ ++ x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); ++ assert(idx != -1); ++ if (idx == 0) { ++ error_setg(errp, "Boot CPU is unpluggable"); ++ return; ++ } ++ ++ hotplug_handler_unplug_request(x86ms->acpi_dev, dev, ++ errp); ++} ++ ++void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ CPUArchId *found_cpu; ++ Error *local_err = NULL; ++ X86CPU *cpu = X86_CPU(dev); ++ X86MachineState *x86ms = X86_MACHINE(hotplug_dev); ++ ++ hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err); ++ if (local_err) { ++ goto out; ++ } ++ ++ found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL); ++ found_cpu->cpu = NULL; ++ qdev_unrealize(dev); ++ ++ /* decrement the number of CPUs */ ++ x86ms->boot_cpus--; ++ /* Update the number of CPUs in CMOS */ ++ x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); ++ fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); ++ out: ++ error_propagate(errp, local_err); ++} ++ ++void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, ++ DeviceState *dev, Error **errp) ++{ ++ int idx; ++ CPUState *cs; ++ CPUArchId *cpu_slot; ++ X86CPUTopoIDs topo_ids; ++ X86CPU *cpu = X86_CPU(dev); ++ CPUX86State *env = &cpu->env; ++ MachineState *ms = MACHINE(hotplug_dev); ++ X86MachineState *x86ms = X86_MACHINE(hotplug_dev); ++ unsigned int smp_cores = ms->smp.cores; ++ unsigned int smp_threads = ms->smp.threads; ++ X86CPUTopoInfo topo_info; ++ ++ if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { ++ error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", ++ ms->cpu_type); ++ return; ++ } ++ ++ if (x86ms->acpi_dev) { ++ Error *local_err = NULL; ++ ++ hotplug_handler_pre_plug(HOTPLUG_HANDLER(x86ms->acpi_dev), dev, ++ &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ return; ++ } ++ } ++ ++ init_topo_info(&topo_info, x86ms); ++ ++ env->nr_dies = ms->smp.dies; ++ ++ /* ++ * If APIC ID is not set, ++ * set it based on socket/die/core/thread properties. ++ */ ++ if (cpu->apic_id == UNASSIGNED_APIC_ID) { ++ int max_socket = (ms->smp.max_cpus - 1) / ++ smp_threads / smp_cores / ms->smp.dies; ++ ++ /* ++ * die-id was optional in QEMU 4.0 and older, so keep it optional ++ * if there's only one die per socket. ++ */ ++ if (cpu->die_id < 0 && ms->smp.dies == 1) { ++ cpu->die_id = 0; ++ } ++ ++ if (cpu->socket_id < 0) { ++ error_setg(errp, "CPU socket-id is not set"); ++ return; ++ } else if (cpu->socket_id > max_socket) { ++ error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", ++ cpu->socket_id, max_socket); ++ return; ++ } ++ if (cpu->die_id < 0) { ++ error_setg(errp, "CPU die-id is not set"); ++ return; ++ } else if (cpu->die_id > ms->smp.dies - 1) { ++ error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u", ++ cpu->die_id, ms->smp.dies - 1); ++ return; ++ } ++ if (cpu->core_id < 0) { ++ error_setg(errp, "CPU core-id is not set"); ++ return; ++ } else if (cpu->core_id > (smp_cores - 1)) { ++ error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", ++ cpu->core_id, smp_cores - 1); ++ return; ++ } ++ if (cpu->thread_id < 0) { ++ error_setg(errp, "CPU thread-id is not set"); ++ return; ++ } else if (cpu->thread_id > (smp_threads - 1)) { ++ error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", ++ cpu->thread_id, smp_threads - 1); ++ return; ++ } ++ ++ topo_ids.pkg_id = cpu->socket_id; ++ topo_ids.die_id = cpu->die_id; ++ topo_ids.core_id = cpu->core_id; ++ topo_ids.smt_id = cpu->thread_id; ++ cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids); ++ } ++ ++ cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); ++ if (!cpu_slot) { ++ x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); ++ error_setg(errp, ++ "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with" ++ " APIC ID %" PRIu32 ", valid index range 0:%d", ++ topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id, ++ cpu->apic_id, ms->possible_cpus->len - 1); ++ return; ++ } ++ ++ if (cpu_slot->cpu) { ++ error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists", ++ idx, cpu->apic_id); ++ return; ++ } ++ ++ /* if 'address' properties socket-id/core-id/thread-id are not set, set them ++ * so that machine_query_hotpluggable_cpus would show correct values ++ */ ++ /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn() ++ * once -smp refactoring is complete and there will be CPU private ++ * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */ ++ x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); ++ if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) { ++ error_setg(errp, "property socket-id: %u doesn't match set apic-id:" ++ " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id, ++ topo_ids.pkg_id); ++ return; ++ } ++ cpu->socket_id = topo_ids.pkg_id; ++ ++ if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) { ++ error_setg(errp, "property die-id: %u doesn't match set apic-id:" ++ " 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id); ++ return; ++ } ++ cpu->die_id = topo_ids.die_id; ++ ++ if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) { ++ error_setg(errp, "property core-id: %u doesn't match set apic-id:" ++ " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id, ++ topo_ids.core_id); ++ return; ++ } ++ cpu->core_id = topo_ids.core_id; ++ ++ if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) { ++ error_setg(errp, "property thread-id: %u doesn't match set apic-id:" ++ " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id, ++ topo_ids.smt_id); ++ return; ++ } ++ cpu->thread_id = topo_ids.smt_id; ++ ++ /* ++ * kvm_enabled() must go first to ensure that kvm_* references are ++ * not emitted for the linker to consume (kvm_enabled() is ++ * a literal `0` in configurations where kvm_* aren't defined) ++ */ ++ if (kvm_enabled() && hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) && ++ !kvm_hv_vpindex_settable()) { ++ error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX"); ++ return; ++ } ++ ++ cs = CPU(cpu); ++ cs->cpu_index = idx; ++ ++ numa_cpu_pre_plug(cpu_slot, dev, errp); ++} ++ ++static long get_file_size(FILE *f) ++{ ++ long where, size; ++ ++ /* XXX: on Unix systems, using fstat() probably makes more sense */ ++ ++ where = ftell(f); ++ fseek(f, 0, SEEK_END); ++ size = ftell(f); ++ fseek(f, where, SEEK_SET); ++ ++ return size; ++} ++ ++void gsi_handler(void *opaque, int n, int level) ++{ ++ GSIState *s = opaque; ++ ++ trace_x86_gsi_interrupt(n, level); ++ switch (n) { ++ case 0 ... ISA_NUM_IRQS - 1: ++ if (s->i8259_irq[n]) { ++ /* Under KVM, Kernel will forward to both PIC and IOAPIC */ ++ qemu_set_irq(s->i8259_irq[n], level); ++ } ++ /* fall through */ ++ case ISA_NUM_IRQS ... IOAPIC_NUM_PINS - 1: ++#ifdef CONFIG_XEN_EMU ++ /* ++ * Xen delivers the GSI to the Legacy PIC (not that Legacy PIC ++ * routing actually works properly under Xen). And then to ++ * *either* the PIRQ handling or the I/OAPIC depending on ++ * whether the former wants it. ++ */ ++ if (xen_mode == XEN_EMULATE && xen_evtchn_set_gsi(n, level)) { ++ break; ++ } ++#endif ++ qemu_set_irq(s->ioapic_irq[n], level); ++ break; ++ case IO_APIC_SECONDARY_IRQBASE ++ ... IO_APIC_SECONDARY_IRQBASE + IOAPIC_NUM_PINS - 1: ++ qemu_set_irq(s->ioapic2_irq[n - IO_APIC_SECONDARY_IRQBASE], level); ++ break; ++ } ++} ++ ++void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) ++{ ++ DeviceState *dev; ++ SysBusDevice *d; ++ unsigned int i; ++ ++ assert(parent_name); ++ if (kvm_ioapic_in_kernel()) { ++ dev = qdev_new(TYPE_KVM_IOAPIC); ++ } else { ++ dev = qdev_new(TYPE_IOAPIC); ++ } ++ object_property_add_child(object_resolve_path(parent_name, NULL), ++ "ioapic", OBJECT(dev)); ++ d = SYS_BUS_DEVICE(dev); ++ sysbus_realize_and_unref(d, &error_fatal); ++ sysbus_mmio_map(d, 0, IO_APIC_DEFAULT_ADDRESS); ++ ++ for (i = 0; i < IOAPIC_NUM_PINS; i++) { ++ gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i); ++ } ++} ++ ++DeviceState *ioapic_init_secondary(GSIState *gsi_state) ++{ ++ DeviceState *dev; ++ SysBusDevice *d; ++ unsigned int i; ++ ++ dev = qdev_new(TYPE_IOAPIC); ++ d = SYS_BUS_DEVICE(dev); ++ sysbus_realize_and_unref(d, &error_fatal); ++ sysbus_mmio_map(d, 0, IO_APIC_SECONDARY_ADDRESS); ++ ++ for (i = 0; i < IOAPIC_NUM_PINS; i++) { ++ gsi_state->ioapic2_irq[i] = qdev_get_gpio_in(dev, i); ++ } ++ return dev; ++} ++ ++struct setup_data { ++ uint64_t next; ++ uint32_t type; ++ uint32_t len; ++ uint8_t data[]; ++} __attribute__((packed)); ++ ++ ++/* ++ * The entry point into the kernel for PVH boot is different from ++ * the native entry point. The PVH entry is defined by the x86/HVM ++ * direct boot ABI and is available in an ELFNOTE in the kernel binary. ++ * ++ * This function is passed to load_elf() when it is called from ++ * load_elfboot() which then additionally checks for an ELF Note of ++ * type XEN_ELFNOTE_PHYS32_ENTRY and passes it to this function to ++ * parse the PVH entry address from the ELF Note. ++ * ++ * Due to trickery in elf_opts.h, load_elf() is actually available as ++ * load_elf32() or load_elf64() and this routine needs to be able ++ * to deal with being called as 32 or 64 bit. ++ * ++ * The address of the PVH entry point is saved to the 'pvh_start_addr' ++ * global variable. (although the entry point is 32-bit, the kernel ++ * binary can be either 32-bit or 64-bit). ++ */ ++static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64) ++{ ++ size_t *elf_note_data_addr; ++ ++ /* Check if ELF Note header passed in is valid */ ++ if (arg1 == NULL) { ++ return 0; ++ } ++ ++ if (is64) { ++ struct elf64_note *nhdr64 = (struct elf64_note *)arg1; ++ uint64_t nhdr_size64 = sizeof(struct elf64_note); ++ uint64_t phdr_align = *(uint64_t *)arg2; ++ uint64_t nhdr_namesz = nhdr64->n_namesz; ++ ++ elf_note_data_addr = ++ ((void *)nhdr64) + nhdr_size64 + ++ QEMU_ALIGN_UP(nhdr_namesz, phdr_align); ++ ++ pvh_start_addr = *elf_note_data_addr; ++ } else { ++ struct elf32_note *nhdr32 = (struct elf32_note *)arg1; ++ uint32_t nhdr_size32 = sizeof(struct elf32_note); ++ uint32_t phdr_align = *(uint32_t *)arg2; ++ uint32_t nhdr_namesz = nhdr32->n_namesz; ++ ++ elf_note_data_addr = ++ ((void *)nhdr32) + nhdr_size32 + ++ QEMU_ALIGN_UP(nhdr_namesz, phdr_align); ++ ++ pvh_start_addr = *(uint32_t *)elf_note_data_addr; ++ } ++ ++ return pvh_start_addr; ++} ++ ++static bool load_elfboot(const char *kernel_filename, ++ int kernel_file_size, ++ uint8_t *header, ++ size_t pvh_xen_start_addr, ++ FWCfgState *fw_cfg) ++{ ++ uint32_t flags = 0; ++ uint32_t mh_load_addr = 0; ++ uint32_t elf_kernel_size = 0; ++ uint64_t elf_entry; ++ uint64_t elf_low, elf_high; ++ int kernel_size; ++ ++ if (ldl_p(header) != 0x464c457f) { ++ return false; /* no elfboot */ ++ } ++ ++ bool elf_is64 = header[EI_CLASS] == ELFCLASS64; ++ flags = elf_is64 ? ++ ((Elf64_Ehdr *)header)->e_flags : ((Elf32_Ehdr *)header)->e_flags; ++ ++ if (flags & 0x00010004) { /* LOAD_ELF_HEADER_HAS_ADDR */ ++ error_report("elfboot unsupported flags = %x", flags); ++ exit(1); ++ } ++ ++ uint64_t elf_note_type = XEN_ELFNOTE_PHYS32_ENTRY; ++ kernel_size = load_elf(kernel_filename, read_pvh_start_addr, ++ NULL, &elf_note_type, &elf_entry, ++ &elf_low, &elf_high, NULL, 0, I386_ELF_MACHINE, ++ 0, 0); ++ ++ if (kernel_size < 0) { ++ error_report("Error while loading elf kernel"); ++ exit(1); ++ } ++ mh_load_addr = elf_low; ++ elf_kernel_size = elf_high - elf_low; ++ ++ if (pvh_start_addr == 0) { ++ error_report("Error loading uncompressed kernel without PVH ELF Note"); ++ exit(1); ++ } ++ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, pvh_start_addr); ++ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr); ++ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, elf_kernel_size); ++ ++ return true; ++} ++ ++void x86_load_linux(X86MachineState *x86ms, ++ FWCfgState *fw_cfg, ++ int acpi_data_size, ++ bool pvh_enabled) ++{ ++ bool linuxboot_dma_enabled = X86_MACHINE_GET_CLASS(x86ms)->fwcfg_dma_enabled; ++ uint16_t protocol; ++ int setup_size, kernel_size, cmdline_size; ++ int dtb_size, setup_data_offset; ++ uint32_t initrd_max; ++ uint8_t header[8192], *setup, *kernel; ++ hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; ++ FILE *f; ++ char *vmode; ++ MachineState *machine = MACHINE(x86ms); ++ struct setup_data *setup_data; ++ const char *kernel_filename = machine->kernel_filename; ++ const char *initrd_filename = machine->initrd_filename; ++ const char *dtb_filename = machine->dtb; ++ const char *kernel_cmdline = machine->kernel_cmdline; ++ SevKernelLoaderContext sev_load_ctx = {}; ++ ++ /* Align to 16 bytes as a paranoia measure */ ++ cmdline_size = (strlen(kernel_cmdline) + 16) & ~15; ++ ++ /* load the kernel header */ ++ f = fopen(kernel_filename, "rb"); ++ if (!f) { ++ fprintf(stderr, "qemu: could not open kernel file '%s': %s\n", ++ kernel_filename, strerror(errno)); ++ exit(1); ++ } ++ ++ kernel_size = get_file_size(f); ++ if (!kernel_size || ++ fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) != ++ MIN(ARRAY_SIZE(header), kernel_size)) { ++ fprintf(stderr, "qemu: could not load kernel '%s': %s\n", ++ kernel_filename, strerror(errno)); ++ exit(1); ++ } ++ ++ /* kernel protocol version */ ++ if (ldl_p(header + 0x202) == 0x53726448) { ++ protocol = lduw_p(header + 0x206); ++ } else { ++ /* ++ * This could be a multiboot kernel. If it is, let's stop treating it ++ * like a Linux kernel. ++ * Note: some multiboot images could be in the ELF format (the same of ++ * PVH), so we try multiboot first since we check the multiboot magic ++ * header before to load it. ++ */ ++ if (load_multiboot(x86ms, fw_cfg, f, kernel_filename, initrd_filename, ++ kernel_cmdline, kernel_size, header)) { ++ return; ++ } ++ /* ++ * Check if the file is an uncompressed kernel file (ELF) and load it, ++ * saving the PVH entry point used by the x86/HVM direct boot ABI. ++ * If load_elfboot() is successful, populate the fw_cfg info. ++ */ ++ if (pvh_enabled && ++ load_elfboot(kernel_filename, kernel_size, ++ header, pvh_start_addr, fw_cfg)) { ++ fclose(f); ++ ++ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ++ strlen(kernel_cmdline) + 1); ++ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); ++ ++ fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, sizeof(header)); ++ fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, ++ header, sizeof(header)); ++ ++ /* load initrd */ ++ if (initrd_filename) { ++ GMappedFile *mapped_file; ++ gsize initrd_size; ++ gchar *initrd_data; ++ GError *gerr = NULL; ++ ++ mapped_file = g_mapped_file_new(initrd_filename, false, &gerr); ++ if (!mapped_file) { ++ fprintf(stderr, "qemu: error reading initrd %s: %s\n", ++ initrd_filename, gerr->message); ++ exit(1); ++ } ++ x86ms->initrd_mapped_file = mapped_file; ++ ++ initrd_data = g_mapped_file_get_contents(mapped_file); ++ initrd_size = g_mapped_file_get_length(mapped_file); ++ initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1; ++ if (initrd_size >= initrd_max) { ++ fprintf(stderr, "qemu: initrd is too large, cannot support." ++ "(max: %"PRIu32", need %"PRId64")\n", ++ initrd_max, (uint64_t)initrd_size); ++ exit(1); ++ } ++ ++ initrd_addr = (initrd_max - initrd_size) & ~4095; ++ ++ fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); ++ fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); ++ fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, ++ initrd_size); ++ } ++ ++ option_rom[nb_option_roms].bootindex = 0; ++ option_rom[nb_option_roms].name = "pvh.bin"; ++ nb_option_roms++; ++ ++ return; ++ } ++ protocol = 0; ++ } ++ ++ if (protocol < 0x200 || !(header[0x211] & 0x01)) { ++ /* Low kernel */ ++ real_addr = 0x90000; ++ cmdline_addr = 0x9a000 - cmdline_size; ++ prot_addr = 0x10000; ++ } else if (protocol < 0x202) { ++ /* High but ancient kernel */ ++ real_addr = 0x90000; ++ cmdline_addr = 0x9a000 - cmdline_size; ++ prot_addr = 0x100000; ++ } else { ++ /* High and recent kernel */ ++ real_addr = 0x10000; ++ cmdline_addr = 0x20000; ++ prot_addr = 0x100000; ++ } ++ ++ /* highest address for loading the initrd */ ++ if (protocol >= 0x20c && ++ lduw_p(header + 0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) { ++ /* ++ * Linux has supported initrd up to 4 GB for a very long time (2007, ++ * long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013), ++ * though it only sets initrd_max to 2 GB to "work around bootloader ++ * bugs". Luckily, QEMU firmware(which does something like bootloader) ++ * has supported this. ++ * ++ * It's believed that if XLF_CAN_BE_LOADED_ABOVE_4G is set, initrd can ++ * be loaded into any address. ++ * ++ * In addition, initrd_max is uint32_t simply because QEMU doesn't ++ * support the 64-bit boot protocol (specifically the ext_ramdisk_image ++ * field). ++ * ++ * Therefore here just limit initrd_max to UINT32_MAX simply as well. ++ */ ++ initrd_max = UINT32_MAX; ++ } else if (protocol >= 0x203) { ++ initrd_max = ldl_p(header + 0x22c); ++ } else { ++ initrd_max = 0x37ffffff; ++ } ++ ++ if (initrd_max >= x86ms->below_4g_mem_size - acpi_data_size) { ++ initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1; ++ } ++ ++ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); ++ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); ++ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); ++ sev_load_ctx.cmdline_data = (char *)kernel_cmdline; ++ sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1; ++ ++ if (protocol >= 0x202) { ++ stl_p(header + 0x228, cmdline_addr); ++ } else { ++ stw_p(header + 0x20, 0xA33F); ++ stw_p(header + 0x22, cmdline_addr - real_addr); ++ } ++ ++ /* handle vga= parameter */ ++ vmode = strstr(kernel_cmdline, "vga="); ++ if (vmode) { ++ unsigned int video_mode; ++ const char *end; ++ int ret; ++ /* skip "vga=" */ ++ vmode += 4; ++ if (!strncmp(vmode, "normal", 6)) { ++ video_mode = 0xffff; ++ } else if (!strncmp(vmode, "ext", 3)) { ++ video_mode = 0xfffe; ++ } else if (!strncmp(vmode, "ask", 3)) { ++ video_mode = 0xfffd; ++ } else { ++ ret = qemu_strtoui(vmode, &end, 0, &video_mode); ++ if (ret != 0 || (*end && *end != ' ')) { ++ fprintf(stderr, "qemu: invalid 'vga=' kernel parameter.\n"); ++ exit(1); ++ } ++ } ++ stw_p(header + 0x1fa, video_mode); ++ } ++ ++ /* loader type */ ++ /* ++ * High nybble = B reserved for QEMU; low nybble is revision number. ++ * If this code is substantially changed, you may want to consider ++ * incrementing the revision. ++ */ ++ if (protocol >= 0x200) { ++ header[0x210] = 0xB0; ++ } ++ /* heap */ ++ if (protocol >= 0x201) { ++ header[0x211] |= 0x80; /* CAN_USE_HEAP */ ++ stw_p(header + 0x224, cmdline_addr - real_addr - 0x200); ++ } ++ ++ /* load initrd */ ++ if (initrd_filename) { ++ GMappedFile *mapped_file; ++ gsize initrd_size; ++ gchar *initrd_data; ++ GError *gerr = NULL; ++ ++ if (protocol < 0x200) { ++ fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n"); ++ exit(1); ++ } ++ ++ mapped_file = g_mapped_file_new(initrd_filename, false, &gerr); ++ if (!mapped_file) { ++ fprintf(stderr, "qemu: error reading initrd %s: %s\n", ++ initrd_filename, gerr->message); ++ exit(1); ++ } ++ x86ms->initrd_mapped_file = mapped_file; ++ ++ initrd_data = g_mapped_file_get_contents(mapped_file); ++ initrd_size = g_mapped_file_get_length(mapped_file); ++ if (initrd_size >= initrd_max) { ++ fprintf(stderr, "qemu: initrd is too large, cannot support." ++ "(max: %"PRIu32", need %"PRId64")\n", ++ initrd_max, (uint64_t)initrd_size); ++ exit(1); ++ } ++ ++ initrd_addr = (initrd_max - initrd_size) & ~4095; ++ ++ fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); ++ fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); ++ fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size); ++ sev_load_ctx.initrd_data = initrd_data; ++ sev_load_ctx.initrd_size = initrd_size; ++ ++ stl_p(header + 0x218, initrd_addr); ++ stl_p(header + 0x21c, initrd_size); ++ } ++ ++ /* load kernel and setup */ ++ setup_size = header[0x1f1]; ++ if (setup_size == 0) { ++ setup_size = 4; ++ } ++ setup_size = (setup_size + 1) * 512; ++ if (setup_size > kernel_size) { ++ fprintf(stderr, "qemu: invalid kernel header\n"); ++ exit(1); ++ } ++ kernel_size -= setup_size; ++ ++ setup = g_malloc(setup_size); ++ kernel = g_malloc(kernel_size); ++ fseek(f, 0, SEEK_SET); ++ if (fread(setup, 1, setup_size, f) != setup_size) { ++ fprintf(stderr, "fread() failed\n"); ++ exit(1); ++ } ++ if (fread(kernel, 1, kernel_size, f) != kernel_size) { ++ fprintf(stderr, "fread() failed\n"); ++ exit(1); ++ } ++ fclose(f); ++ ++ /* append dtb to kernel */ ++ if (dtb_filename) { ++ if (protocol < 0x209) { ++ fprintf(stderr, "qemu: Linux kernel too old to load a dtb\n"); ++ exit(1); ++ } ++ ++ dtb_size = get_image_size(dtb_filename); ++ if (dtb_size <= 0) { ++ fprintf(stderr, "qemu: error reading dtb %s: %s\n", ++ dtb_filename, strerror(errno)); ++ exit(1); ++ } ++ ++ setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); ++ kernel_size = setup_data_offset + sizeof(struct setup_data) + dtb_size; ++ kernel = g_realloc(kernel, kernel_size); ++ ++ stq_p(header + 0x250, prot_addr + setup_data_offset); ++ ++ setup_data = (struct setup_data *)(kernel + setup_data_offset); ++ setup_data->next = 0; ++ setup_data->type = cpu_to_le32(SETUP_DTB); ++ setup_data->len = cpu_to_le32(dtb_size); ++ ++ load_image_size(dtb_filename, setup_data->data, dtb_size); ++ } ++ ++ /* ++ * If we're starting an encrypted VM, it will be OVMF based, which uses the ++ * efi stub for booting and doesn't require any values to be placed in the ++ * kernel header. We therefore don't update the header so the hash of the ++ * kernel on the other side of the fw_cfg interface matches the hash of the ++ * file the user passed in. ++ */ ++ if (!sev_enabled()) { ++ memcpy(setup, header, MIN(sizeof(header), setup_size)); ++ } ++ ++ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); ++ fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); ++ fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); ++ sev_load_ctx.kernel_data = (char *)kernel; ++ sev_load_ctx.kernel_size = kernel_size; ++ ++ fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr); ++ fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size); ++ fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size); ++ sev_load_ctx.setup_data = (char *)setup; ++ sev_load_ctx.setup_size = setup_size; ++ ++ if (sev_enabled()) { ++ sev_add_kernel_loader_hashes(&sev_load_ctx, &error_fatal); ++ } ++ ++ option_rom[nb_option_roms].bootindex = 0; ++ option_rom[nb_option_roms].name = "linuxboot.bin"; ++ if (linuxboot_dma_enabled && fw_cfg_dma_enabled(fw_cfg)) { ++ option_rom[nb_option_roms].name = "linuxboot_dma.bin"; ++ } ++ nb_option_roms++; ++} ++ ++void x86_bios_rom_init(MachineState *ms, const char *default_firmware, ++ MemoryRegion *rom_memory, bool isapc_ram_fw) ++{ ++ const char *bios_name; ++ char *filename; ++ MemoryRegion *bios, *isa_bios; ++ int bios_size, isa_bios_size; ++ ssize_t ret; ++ ++ /* BIOS load */ ++ bios_name = ms->firmware ?: default_firmware; ++ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); ++ if (filename) { ++ bios_size = get_image_size(filename); ++ } else { ++ bios_size = -1; ++ } ++ if (bios_size <= 0 || ++ (bios_size % 65536) != 0) { ++ goto bios_error; ++ } ++ bios = g_malloc(sizeof(*bios)); ++ memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal); ++ if (sev_enabled()) { ++ /* ++ * The concept of a "reset" simply doesn't exist for ++ * confidential computing guests, we have to destroy and ++ * re-launch them instead. So there is no need to register ++ * the firmware as rom to properly re-initialize on reset. ++ * Just go for a straight file load instead. ++ */ ++ void *ptr = memory_region_get_ram_ptr(bios); ++ load_image_size(filename, ptr, bios_size); ++ x86_firmware_configure(ptr, bios_size); ++ } else { ++ if (!isapc_ram_fw) { ++ memory_region_set_readonly(bios, true); ++ } ++ ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); ++ if (ret != 0) { ++ goto bios_error; ++ } ++ } ++ g_free(filename); ++ ++ /* map the last 128KB of the BIOS in ISA space */ ++ isa_bios_size = MIN(bios_size, 128 * KiB); ++ isa_bios = g_malloc(sizeof(*isa_bios)); ++ memory_region_init_alias(isa_bios, NULL, "isa-bios", bios, ++ bios_size - isa_bios_size, isa_bios_size); ++ memory_region_add_subregion_overlap(rom_memory, ++ 0x100000 - isa_bios_size, ++ isa_bios, ++ 1); ++ if (!isapc_ram_fw) { ++ memory_region_set_readonly(isa_bios, true); ++ } ++ ++ /* map all the bios at the top of memory */ ++ memory_region_add_subregion(rom_memory, ++ (uint32_t)(-bios_size), ++ bios); ++ return; ++ ++bios_error: ++ fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name); ++ exit(1); ++} +diff --git a/hw/i386/x86-cpu.c b/hw/i386/x86-cpu.c +new file mode 100644 +index 00000000000..9ef43f34c6e +--- /dev/null ++++ b/hw/i386/x86-cpu.c +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) 2003-2004 Fabrice Bellard ++ * Copyright (c) 2019, 2024 Red Hat, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++#include "qemu/osdep.h" ++#include "sysemu/whpx.h" ++#include "sysemu/cpu-timers.h" ++#include "trace.h" ++ ++#include "hw/i386/x86.h" ++#include "target/i386/cpu.h" ++#include "hw/intc/i8259.h" ++#include "hw/irq.h" ++#include "sysemu/kvm.h" ++ ++/* TSC handling */ ++uint64_t cpu_get_tsc(CPUX86State *env) ++{ ++ return cpus_get_elapsed_ticks(); ++} ++ ++/* IRQ handling */ ++static void pic_irq_request(void *opaque, int irq, int level) ++{ ++ CPUState *cs = first_cpu; ++ X86CPU *cpu = X86_CPU(cs); ++ ++ trace_x86_pic_interrupt(irq, level); ++ if (cpu->apic_state && !kvm_irqchip_in_kernel() && ++ !whpx_apic_in_platform()) { ++ CPU_FOREACH(cs) { ++ cpu = X86_CPU(cs); ++ if (apic_accept_pic_intr(cpu->apic_state)) { ++ apic_deliver_pic_intr(cpu->apic_state, level); ++ } ++ } ++ } else { ++ if (level) { ++ cpu_interrupt(cs, CPU_INTERRUPT_HARD); ++ } else { ++ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); ++ } ++ } ++} ++ ++qemu_irq x86_allocate_cpu_irq(void) ++{ ++ return qemu_allocate_irq(pic_irq_request, NULL, 0); ++} ++ ++int cpu_get_pic_interrupt(CPUX86State *env) ++{ ++ X86CPU *cpu = env_archcpu(env); ++ int intno; ++ ++ if (!kvm_irqchip_in_kernel() && !whpx_apic_in_platform()) { ++ intno = apic_get_interrupt(cpu->apic_state); ++ if (intno >= 0) { ++ return intno; ++ } ++ /* read the irq from the PIC */ ++ if (!apic_accept_pic_intr(cpu->apic_state)) { ++ return -1; ++ } ++ } ++ ++ intno = pic_read_irq(isa_pic); ++ return intno; ++} ++ ++DeviceState *cpu_get_current_apic(void) ++{ ++ if (current_cpu) { ++ X86CPU *cpu = X86_CPU(current_cpu); ++ return cpu->apic_state; ++ } else { ++ return NULL; ++ } ++} +diff --git a/hw/i386/x86.c b/hw/i386/x86.c +index 2b6291ad8d5..b9635c9ba42 100644 +--- a/hw/i386/x86.c ++++ b/hw/i386/x86.c +@@ -22,52 +22,25 @@ + */ + #include "qemu/osdep.h" + #include "qemu/error-report.h" +-#include "qemu/option.h" +-#include "qemu/cutils.h" + #include "qemu/units.h" +-#include "qemu/datadir.h" + #include "qapi/error.h" + #include "qapi/qapi-visit-common.h" +-#include "qapi/clone-visitor.h" + #include "qapi/qapi-visit-machine.h" + #include "qapi/visitor.h" + #include "sysemu/qtest.h" +-#include "sysemu/whpx.h" + #include "sysemu/numa.h" +-#include "sysemu/replay.h" +-#include "sysemu/sysemu.h" +-#include "sysemu/cpu-timers.h" +-#include "sysemu/xen.h" + #include "trace.h" + ++#include "hw/acpi/aml-build.h" + #include "hw/i386/x86.h" +-#include "target/i386/cpu.h" + #include "hw/i386/topology.h" +-#include "hw/i386/fw_cfg.h" +-#include "hw/intc/i8259.h" +-#include "hw/rtc/mc146818rtc.h" +-#include "target/i386/sev.h" + +-#include "hw/acpi/cpu_hotplug.h" +-#include "hw/irq.h" + #include "hw/nmi.h" +-#include "hw/loader.h" +-#include "multiboot.h" +-#include "elf.h" +-#include "standard-headers/asm-x86/bootparam.h" +-#include CONFIG_DEVICES + #include "kvm/kvm_i386.h" + +-#ifdef CONFIG_XEN_EMU +-#include "hw/xen/xen.h" +-#include "hw/i386/kvm/xen_evtchn.h" +-#endif + +-/* Physical Address of PVH entry point read from kernel ELF NOTE */ +-static size_t pvh_start_addr; +- +-static void init_topo_info(X86CPUTopoInfo *topo_info, +- const X86MachineState *x86ms) ++void init_topo_info(X86CPUTopoInfo *topo_info, ++ const X86MachineState *x86ms) + { + MachineState *ms = MACHINE(x86ms); + +@@ -94,351 +67,6 @@ uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms, + return x86_apicid_from_cpu_idx(&topo_info, cpu_index); + } + +- +-void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp) +-{ +- Object *cpu = object_new(MACHINE(x86ms)->cpu_type); +- +- if (!object_property_set_uint(cpu, "apic-id", apic_id, errp)) { +- goto out; +- } +- qdev_realize(DEVICE(cpu), NULL, errp); +- +-out: +- object_unref(cpu); +-} +- +-void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) +-{ +- int i; +- const CPUArchIdList *possible_cpus; +- MachineState *ms = MACHINE(x86ms); +- MachineClass *mc = MACHINE_GET_CLASS(x86ms); +- +- x86_cpu_set_default_version(default_cpu_version); +- +- /* +- * Calculates the limit to CPU APIC ID values +- * +- * Limit for the APIC ID value, so that all +- * CPU APIC IDs are < x86ms->apic_id_limit. +- * +- * This is used for FW_CFG_MAX_CPUS. See comments on fw_cfg_arch_create(). +- */ +- x86ms->apic_id_limit = x86_cpu_apic_id_from_index(x86ms, +- ms->smp.max_cpus - 1) + 1; +- +- /* +- * Can we support APIC ID 255 or higher? With KVM, that requires +- * both in-kernel lapic and X2APIC userspace API. +- * +- * kvm_enabled() must go first to ensure that kvm_* references are +- * not emitted for the linker to consume (kvm_enabled() is +- * a literal `0` in configurations where kvm_* aren't defined) +- */ +- if (kvm_enabled() && x86ms->apic_id_limit > 255 && +- (!kvm_irqchip_in_kernel() || !kvm_enable_x2apic())) { +- error_report("current -smp configuration requires kernel " +- "irqchip and X2APIC API support."); +- exit(EXIT_FAILURE); +- } +- +- if (kvm_enabled()) { +- kvm_set_max_apic_id(x86ms->apic_id_limit); +- } +- +- possible_cpus = mc->possible_cpu_arch_ids(ms); +- for (i = 0; i < ms->smp.cpus; i++) { +- x86_cpu_new(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal); +- } +-} +- +-void x86_rtc_set_cpus_count(ISADevice *s, uint16_t cpus_count) +-{ +- MC146818RtcState *rtc = MC146818_RTC(s); +- +- if (cpus_count > 0xff) { +- /* +- * If the number of CPUs can't be represented in 8 bits, the +- * BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just +- * to make old BIOSes fail more predictably. +- */ +- mc146818rtc_set_cmos_data(rtc, 0x5f, 0); +- } else { +- mc146818rtc_set_cmos_data(rtc, 0x5f, cpus_count - 1); +- } +-} +- +-static int x86_apic_cmp(const void *a, const void *b) +-{ +- CPUArchId *apic_a = (CPUArchId *)a; +- CPUArchId *apic_b = (CPUArchId *)b; +- +- return apic_a->arch_id - apic_b->arch_id; +-} +- +-/* +- * returns pointer to CPUArchId descriptor that matches CPU's apic_id +- * in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no +- * entry corresponding to CPU's apic_id returns NULL. +- */ +-CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx) +-{ +- CPUArchId apic_id, *found_cpu; +- +- apic_id.arch_id = id; +- found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus, +- ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus), +- x86_apic_cmp); +- if (found_cpu && idx) { +- *idx = found_cpu - ms->possible_cpus->cpus; +- } +- return found_cpu; +-} +- +-void x86_cpu_plug(HotplugHandler *hotplug_dev, +- DeviceState *dev, Error **errp) +-{ +- CPUArchId *found_cpu; +- Error *local_err = NULL; +- X86CPU *cpu = X86_CPU(dev); +- X86MachineState *x86ms = X86_MACHINE(hotplug_dev); +- +- if (x86ms->acpi_dev) { +- hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err); +- if (local_err) { +- goto out; +- } +- } +- +- /* increment the number of CPUs */ +- x86ms->boot_cpus++; +- if (x86ms->rtc) { +- x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); +- } +- if (x86ms->fw_cfg) { +- fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); +- } +- +- found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL); +- found_cpu->cpu = OBJECT(dev); +-out: +- error_propagate(errp, local_err); +-} +- +-void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, +- DeviceState *dev, Error **errp) +-{ +- int idx = -1; +- X86CPU *cpu = X86_CPU(dev); +- X86MachineState *x86ms = X86_MACHINE(hotplug_dev); +- +- if (!x86ms->acpi_dev) { +- error_setg(errp, "CPU hot unplug not supported without ACPI"); +- return; +- } +- +- x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); +- assert(idx != -1); +- if (idx == 0) { +- error_setg(errp, "Boot CPU is unpluggable"); +- return; +- } +- +- hotplug_handler_unplug_request(x86ms->acpi_dev, dev, +- errp); +-} +- +-void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev, +- DeviceState *dev, Error **errp) +-{ +- CPUArchId *found_cpu; +- Error *local_err = NULL; +- X86CPU *cpu = X86_CPU(dev); +- X86MachineState *x86ms = X86_MACHINE(hotplug_dev); +- +- hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err); +- if (local_err) { +- goto out; +- } +- +- found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL); +- found_cpu->cpu = NULL; +- qdev_unrealize(dev); +- +- /* decrement the number of CPUs */ +- x86ms->boot_cpus--; +- /* Update the number of CPUs in CMOS */ +- x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); +- fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); +- out: +- error_propagate(errp, local_err); +-} +- +-void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, +- DeviceState *dev, Error **errp) +-{ +- int idx; +- CPUState *cs; +- CPUArchId *cpu_slot; +- X86CPUTopoIDs topo_ids; +- X86CPU *cpu = X86_CPU(dev); +- CPUX86State *env = &cpu->env; +- MachineState *ms = MACHINE(hotplug_dev); +- X86MachineState *x86ms = X86_MACHINE(hotplug_dev); +- unsigned int smp_cores = ms->smp.cores; +- unsigned int smp_threads = ms->smp.threads; +- X86CPUTopoInfo topo_info; +- +- if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { +- error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", +- ms->cpu_type); +- return; +- } +- +- if (x86ms->acpi_dev) { +- Error *local_err = NULL; +- +- hotplug_handler_pre_plug(HOTPLUG_HANDLER(x86ms->acpi_dev), dev, +- &local_err); +- if (local_err) { +- error_propagate(errp, local_err); +- return; +- } +- } +- +- init_topo_info(&topo_info, x86ms); +- +- env->nr_dies = ms->smp.dies; +- +- /* +- * If APIC ID is not set, +- * set it based on socket/die/core/thread properties. +- */ +- if (cpu->apic_id == UNASSIGNED_APIC_ID) { +- int max_socket = (ms->smp.max_cpus - 1) / +- smp_threads / smp_cores / ms->smp.dies; +- +- /* +- * die-id was optional in QEMU 4.0 and older, so keep it optional +- * if there's only one die per socket. +- */ +- if (cpu->die_id < 0 && ms->smp.dies == 1) { +- cpu->die_id = 0; +- } +- +- if (cpu->socket_id < 0) { +- error_setg(errp, "CPU socket-id is not set"); +- return; +- } else if (cpu->socket_id > max_socket) { +- error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", +- cpu->socket_id, max_socket); +- return; +- } +- if (cpu->die_id < 0) { +- error_setg(errp, "CPU die-id is not set"); +- return; +- } else if (cpu->die_id > ms->smp.dies - 1) { +- error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u", +- cpu->die_id, ms->smp.dies - 1); +- return; +- } +- if (cpu->core_id < 0) { +- error_setg(errp, "CPU core-id is not set"); +- return; +- } else if (cpu->core_id > (smp_cores - 1)) { +- error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", +- cpu->core_id, smp_cores - 1); +- return; +- } +- if (cpu->thread_id < 0) { +- error_setg(errp, "CPU thread-id is not set"); +- return; +- } else if (cpu->thread_id > (smp_threads - 1)) { +- error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", +- cpu->thread_id, smp_threads - 1); +- return; +- } +- +- topo_ids.pkg_id = cpu->socket_id; +- topo_ids.die_id = cpu->die_id; +- topo_ids.core_id = cpu->core_id; +- topo_ids.smt_id = cpu->thread_id; +- cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids); +- } +- +- cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); +- if (!cpu_slot) { +- x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); +- error_setg(errp, +- "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with" +- " APIC ID %" PRIu32 ", valid index range 0:%d", +- topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id, +- cpu->apic_id, ms->possible_cpus->len - 1); +- return; +- } +- +- if (cpu_slot->cpu) { +- error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists", +- idx, cpu->apic_id); +- return; +- } +- +- /* if 'address' properties socket-id/core-id/thread-id are not set, set them +- * so that machine_query_hotpluggable_cpus would show correct values +- */ +- /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn() +- * once -smp refactoring is complete and there will be CPU private +- * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */ +- x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); +- if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) { +- error_setg(errp, "property socket-id: %u doesn't match set apic-id:" +- " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id, +- topo_ids.pkg_id); +- return; +- } +- cpu->socket_id = topo_ids.pkg_id; +- +- if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) { +- error_setg(errp, "property die-id: %u doesn't match set apic-id:" +- " 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id); +- return; +- } +- cpu->die_id = topo_ids.die_id; +- +- if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) { +- error_setg(errp, "property core-id: %u doesn't match set apic-id:" +- " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id, +- topo_ids.core_id); +- return; +- } +- cpu->core_id = topo_ids.core_id; +- +- if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) { +- error_setg(errp, "property thread-id: %u doesn't match set apic-id:" +- " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id, +- topo_ids.smt_id); +- return; +- } +- cpu->thread_id = topo_ids.smt_id; +- +- /* +- * kvm_enabled() must go first to ensure that kvm_* references are +- * not emitted for the linker to consume (kvm_enabled() is +- * a literal `0` in configurations where kvm_* aren't defined) +- */ +- if (kvm_enabled() && hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) && +- !kvm_hv_vpindex_settable()) { +- error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX"); +- return; +- } +- +- cs = CPU(cpu); +- cs->cpu_index = idx; +- +- numa_cpu_pre_plug(cpu_slot, dev, errp); +-} +- + CpuInstanceProperties + x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index) + { +@@ -524,684 +152,6 @@ static void x86_nmi(NMIState *n, int cpu_index, Error **errp) + } + } + +-static long get_file_size(FILE *f) +-{ +- long where, size; +- +- /* XXX: on Unix systems, using fstat() probably makes more sense */ +- +- where = ftell(f); +- fseek(f, 0, SEEK_END); +- size = ftell(f); +- fseek(f, where, SEEK_SET); +- +- return size; +-} +- +-/* TSC handling */ +-uint64_t cpu_get_tsc(CPUX86State *env) +-{ +- return cpus_get_elapsed_ticks(); +-} +- +-/* IRQ handling */ +-static void pic_irq_request(void *opaque, int irq, int level) +-{ +- CPUState *cs = first_cpu; +- X86CPU *cpu = X86_CPU(cs); +- +- trace_x86_pic_interrupt(irq, level); +- if (cpu->apic_state && !kvm_irqchip_in_kernel() && +- !whpx_apic_in_platform()) { +- CPU_FOREACH(cs) { +- cpu = X86_CPU(cs); +- if (apic_accept_pic_intr(cpu->apic_state)) { +- apic_deliver_pic_intr(cpu->apic_state, level); +- } +- } +- } else { +- if (level) { +- cpu_interrupt(cs, CPU_INTERRUPT_HARD); +- } else { +- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); +- } +- } +-} +- +-qemu_irq x86_allocate_cpu_irq(void) +-{ +- return qemu_allocate_irq(pic_irq_request, NULL, 0); +-} +- +-int cpu_get_pic_interrupt(CPUX86State *env) +-{ +- X86CPU *cpu = env_archcpu(env); +- int intno; +- +- if (!kvm_irqchip_in_kernel() && !whpx_apic_in_platform()) { +- intno = apic_get_interrupt(cpu->apic_state); +- if (intno >= 0) { +- return intno; +- } +- /* read the irq from the PIC */ +- if (!apic_accept_pic_intr(cpu->apic_state)) { +- return -1; +- } +- } +- +- intno = pic_read_irq(isa_pic); +- return intno; +-} +- +-DeviceState *cpu_get_current_apic(void) +-{ +- if (current_cpu) { +- X86CPU *cpu = X86_CPU(current_cpu); +- return cpu->apic_state; +- } else { +- return NULL; +- } +-} +- +-void gsi_handler(void *opaque, int n, int level) +-{ +- GSIState *s = opaque; +- +- trace_x86_gsi_interrupt(n, level); +- switch (n) { +- case 0 ... ISA_NUM_IRQS - 1: +- if (s->i8259_irq[n]) { +- /* Under KVM, Kernel will forward to both PIC and IOAPIC */ +- qemu_set_irq(s->i8259_irq[n], level); +- } +- /* fall through */ +- case ISA_NUM_IRQS ... IOAPIC_NUM_PINS - 1: +-#ifdef CONFIG_XEN_EMU +- /* +- * Xen delivers the GSI to the Legacy PIC (not that Legacy PIC +- * routing actually works properly under Xen). And then to +- * *either* the PIRQ handling or the I/OAPIC depending on +- * whether the former wants it. +- */ +- if (xen_mode == XEN_EMULATE && xen_evtchn_set_gsi(n, level)) { +- break; +- } +-#endif +- qemu_set_irq(s->ioapic_irq[n], level); +- break; +- case IO_APIC_SECONDARY_IRQBASE +- ... IO_APIC_SECONDARY_IRQBASE + IOAPIC_NUM_PINS - 1: +- qemu_set_irq(s->ioapic2_irq[n - IO_APIC_SECONDARY_IRQBASE], level); +- break; +- } +-} +- +-void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) +-{ +- DeviceState *dev; +- SysBusDevice *d; +- unsigned int i; +- +- assert(parent_name); +- if (kvm_ioapic_in_kernel()) { +- dev = qdev_new(TYPE_KVM_IOAPIC); +- } else { +- dev = qdev_new(TYPE_IOAPIC); +- } +- object_property_add_child(object_resolve_path(parent_name, NULL), +- "ioapic", OBJECT(dev)); +- d = SYS_BUS_DEVICE(dev); +- sysbus_realize_and_unref(d, &error_fatal); +- sysbus_mmio_map(d, 0, IO_APIC_DEFAULT_ADDRESS); +- +- for (i = 0; i < IOAPIC_NUM_PINS; i++) { +- gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i); +- } +-} +- +-DeviceState *ioapic_init_secondary(GSIState *gsi_state) +-{ +- DeviceState *dev; +- SysBusDevice *d; +- unsigned int i; +- +- dev = qdev_new(TYPE_IOAPIC); +- d = SYS_BUS_DEVICE(dev); +- sysbus_realize_and_unref(d, &error_fatal); +- sysbus_mmio_map(d, 0, IO_APIC_SECONDARY_ADDRESS); +- +- for (i = 0; i < IOAPIC_NUM_PINS; i++) { +- gsi_state->ioapic2_irq[i] = qdev_get_gpio_in(dev, i); +- } +- return dev; +-} +- +-struct setup_data { +- uint64_t next; +- uint32_t type; +- uint32_t len; +- uint8_t data[]; +-} __attribute__((packed)); +- +- +-/* +- * The entry point into the kernel for PVH boot is different from +- * the native entry point. The PVH entry is defined by the x86/HVM +- * direct boot ABI and is available in an ELFNOTE in the kernel binary. +- * +- * This function is passed to load_elf() when it is called from +- * load_elfboot() which then additionally checks for an ELF Note of +- * type XEN_ELFNOTE_PHYS32_ENTRY and passes it to this function to +- * parse the PVH entry address from the ELF Note. +- * +- * Due to trickery in elf_opts.h, load_elf() is actually available as +- * load_elf32() or load_elf64() and this routine needs to be able +- * to deal with being called as 32 or 64 bit. +- * +- * The address of the PVH entry point is saved to the 'pvh_start_addr' +- * global variable. (although the entry point is 32-bit, the kernel +- * binary can be either 32-bit or 64-bit). +- */ +-static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64) +-{ +- size_t *elf_note_data_addr; +- +- /* Check if ELF Note header passed in is valid */ +- if (arg1 == NULL) { +- return 0; +- } +- +- if (is64) { +- struct elf64_note *nhdr64 = (struct elf64_note *)arg1; +- uint64_t nhdr_size64 = sizeof(struct elf64_note); +- uint64_t phdr_align = *(uint64_t *)arg2; +- uint64_t nhdr_namesz = nhdr64->n_namesz; +- +- elf_note_data_addr = +- ((void *)nhdr64) + nhdr_size64 + +- QEMU_ALIGN_UP(nhdr_namesz, phdr_align); +- +- pvh_start_addr = *elf_note_data_addr; +- } else { +- struct elf32_note *nhdr32 = (struct elf32_note *)arg1; +- uint32_t nhdr_size32 = sizeof(struct elf32_note); +- uint32_t phdr_align = *(uint32_t *)arg2; +- uint32_t nhdr_namesz = nhdr32->n_namesz; +- +- elf_note_data_addr = +- ((void *)nhdr32) + nhdr_size32 + +- QEMU_ALIGN_UP(nhdr_namesz, phdr_align); +- +- pvh_start_addr = *(uint32_t *)elf_note_data_addr; +- } +- +- return pvh_start_addr; +-} +- +-static bool load_elfboot(const char *kernel_filename, +- int kernel_file_size, +- uint8_t *header, +- size_t pvh_xen_start_addr, +- FWCfgState *fw_cfg) +-{ +- uint32_t flags = 0; +- uint32_t mh_load_addr = 0; +- uint32_t elf_kernel_size = 0; +- uint64_t elf_entry; +- uint64_t elf_low, elf_high; +- int kernel_size; +- +- if (ldl_p(header) != 0x464c457f) { +- return false; /* no elfboot */ +- } +- +- bool elf_is64 = header[EI_CLASS] == ELFCLASS64; +- flags = elf_is64 ? +- ((Elf64_Ehdr *)header)->e_flags : ((Elf32_Ehdr *)header)->e_flags; +- +- if (flags & 0x00010004) { /* LOAD_ELF_HEADER_HAS_ADDR */ +- error_report("elfboot unsupported flags = %x", flags); +- exit(1); +- } +- +- uint64_t elf_note_type = XEN_ELFNOTE_PHYS32_ENTRY; +- kernel_size = load_elf(kernel_filename, read_pvh_start_addr, +- NULL, &elf_note_type, &elf_entry, +- &elf_low, &elf_high, NULL, 0, I386_ELF_MACHINE, +- 0, 0); +- +- if (kernel_size < 0) { +- error_report("Error while loading elf kernel"); +- exit(1); +- } +- mh_load_addr = elf_low; +- elf_kernel_size = elf_high - elf_low; +- +- if (pvh_start_addr == 0) { +- error_report("Error loading uncompressed kernel without PVH ELF Note"); +- exit(1); +- } +- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, pvh_start_addr); +- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr); +- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, elf_kernel_size); +- +- return true; +-} +- +-void x86_load_linux(X86MachineState *x86ms, +- FWCfgState *fw_cfg, +- int acpi_data_size, +- bool pvh_enabled) +-{ +- bool linuxboot_dma_enabled = X86_MACHINE_GET_CLASS(x86ms)->fwcfg_dma_enabled; +- uint16_t protocol; +- int setup_size, kernel_size, cmdline_size; +- int dtb_size, setup_data_offset; +- uint32_t initrd_max; +- uint8_t header[8192], *setup, *kernel; +- hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; +- FILE *f; +- char *vmode; +- MachineState *machine = MACHINE(x86ms); +- struct setup_data *setup_data; +- const char *kernel_filename = machine->kernel_filename; +- const char *initrd_filename = machine->initrd_filename; +- const char *dtb_filename = machine->dtb; +- const char *kernel_cmdline = machine->kernel_cmdline; +- SevKernelLoaderContext sev_load_ctx = {}; +- +- /* Align to 16 bytes as a paranoia measure */ +- cmdline_size = (strlen(kernel_cmdline) + 16) & ~15; +- +- /* load the kernel header */ +- f = fopen(kernel_filename, "rb"); +- if (!f) { +- fprintf(stderr, "qemu: could not open kernel file '%s': %s\n", +- kernel_filename, strerror(errno)); +- exit(1); +- } +- +- kernel_size = get_file_size(f); +- if (!kernel_size || +- fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) != +- MIN(ARRAY_SIZE(header), kernel_size)) { +- fprintf(stderr, "qemu: could not load kernel '%s': %s\n", +- kernel_filename, strerror(errno)); +- exit(1); +- } +- +- /* kernel protocol version */ +- if (ldl_p(header + 0x202) == 0x53726448) { +- protocol = lduw_p(header + 0x206); +- } else { +- /* +- * This could be a multiboot kernel. If it is, let's stop treating it +- * like a Linux kernel. +- * Note: some multiboot images could be in the ELF format (the same of +- * PVH), so we try multiboot first since we check the multiboot magic +- * header before to load it. +- */ +- if (load_multiboot(x86ms, fw_cfg, f, kernel_filename, initrd_filename, +- kernel_cmdline, kernel_size, header)) { +- return; +- } +- /* +- * Check if the file is an uncompressed kernel file (ELF) and load it, +- * saving the PVH entry point used by the x86/HVM direct boot ABI. +- * If load_elfboot() is successful, populate the fw_cfg info. +- */ +- if (pvh_enabled && +- load_elfboot(kernel_filename, kernel_size, +- header, pvh_start_addr, fw_cfg)) { +- fclose(f); +- +- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, +- strlen(kernel_cmdline) + 1); +- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); +- +- fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, sizeof(header)); +- fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, +- header, sizeof(header)); +- +- /* load initrd */ +- if (initrd_filename) { +- GMappedFile *mapped_file; +- gsize initrd_size; +- gchar *initrd_data; +- GError *gerr = NULL; +- +- mapped_file = g_mapped_file_new(initrd_filename, false, &gerr); +- if (!mapped_file) { +- fprintf(stderr, "qemu: error reading initrd %s: %s\n", +- initrd_filename, gerr->message); +- exit(1); +- } +- x86ms->initrd_mapped_file = mapped_file; +- +- initrd_data = g_mapped_file_get_contents(mapped_file); +- initrd_size = g_mapped_file_get_length(mapped_file); +- initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1; +- if (initrd_size >= initrd_max) { +- fprintf(stderr, "qemu: initrd is too large, cannot support." +- "(max: %"PRIu32", need %"PRId64")\n", +- initrd_max, (uint64_t)initrd_size); +- exit(1); +- } +- +- initrd_addr = (initrd_max - initrd_size) & ~4095; +- +- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); +- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); +- fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, +- initrd_size); +- } +- +- option_rom[nb_option_roms].bootindex = 0; +- option_rom[nb_option_roms].name = "pvh.bin"; +- nb_option_roms++; +- +- return; +- } +- protocol = 0; +- } +- +- if (protocol < 0x200 || !(header[0x211] & 0x01)) { +- /* Low kernel */ +- real_addr = 0x90000; +- cmdline_addr = 0x9a000 - cmdline_size; +- prot_addr = 0x10000; +- } else if (protocol < 0x202) { +- /* High but ancient kernel */ +- real_addr = 0x90000; +- cmdline_addr = 0x9a000 - cmdline_size; +- prot_addr = 0x100000; +- } else { +- /* High and recent kernel */ +- real_addr = 0x10000; +- cmdline_addr = 0x20000; +- prot_addr = 0x100000; +- } +- +- /* highest address for loading the initrd */ +- if (protocol >= 0x20c && +- lduw_p(header + 0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) { +- /* +- * Linux has supported initrd up to 4 GB for a very long time (2007, +- * long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013), +- * though it only sets initrd_max to 2 GB to "work around bootloader +- * bugs". Luckily, QEMU firmware(which does something like bootloader) +- * has supported this. +- * +- * It's believed that if XLF_CAN_BE_LOADED_ABOVE_4G is set, initrd can +- * be loaded into any address. +- * +- * In addition, initrd_max is uint32_t simply because QEMU doesn't +- * support the 64-bit boot protocol (specifically the ext_ramdisk_image +- * field). +- * +- * Therefore here just limit initrd_max to UINT32_MAX simply as well. +- */ +- initrd_max = UINT32_MAX; +- } else if (protocol >= 0x203) { +- initrd_max = ldl_p(header + 0x22c); +- } else { +- initrd_max = 0x37ffffff; +- } +- +- if (initrd_max >= x86ms->below_4g_mem_size - acpi_data_size) { +- initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1; +- } +- +- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); +- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); +- fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); +- sev_load_ctx.cmdline_data = (char *)kernel_cmdline; +- sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1; +- +- if (protocol >= 0x202) { +- stl_p(header + 0x228, cmdline_addr); +- } else { +- stw_p(header + 0x20, 0xA33F); +- stw_p(header + 0x22, cmdline_addr - real_addr); +- } +- +- /* handle vga= parameter */ +- vmode = strstr(kernel_cmdline, "vga="); +- if (vmode) { +- unsigned int video_mode; +- const char *end; +- int ret; +- /* skip "vga=" */ +- vmode += 4; +- if (!strncmp(vmode, "normal", 6)) { +- video_mode = 0xffff; +- } else if (!strncmp(vmode, "ext", 3)) { +- video_mode = 0xfffe; +- } else if (!strncmp(vmode, "ask", 3)) { +- video_mode = 0xfffd; +- } else { +- ret = qemu_strtoui(vmode, &end, 0, &video_mode); +- if (ret != 0 || (*end && *end != ' ')) { +- fprintf(stderr, "qemu: invalid 'vga=' kernel parameter.\n"); +- exit(1); +- } +- } +- stw_p(header + 0x1fa, video_mode); +- } +- +- /* loader type */ +- /* +- * High nybble = B reserved for QEMU; low nybble is revision number. +- * If this code is substantially changed, you may want to consider +- * incrementing the revision. +- */ +- if (protocol >= 0x200) { +- header[0x210] = 0xB0; +- } +- /* heap */ +- if (protocol >= 0x201) { +- header[0x211] |= 0x80; /* CAN_USE_HEAP */ +- stw_p(header + 0x224, cmdline_addr - real_addr - 0x200); +- } +- +- /* load initrd */ +- if (initrd_filename) { +- GMappedFile *mapped_file; +- gsize initrd_size; +- gchar *initrd_data; +- GError *gerr = NULL; +- +- if (protocol < 0x200) { +- fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n"); +- exit(1); +- } +- +- mapped_file = g_mapped_file_new(initrd_filename, false, &gerr); +- if (!mapped_file) { +- fprintf(stderr, "qemu: error reading initrd %s: %s\n", +- initrd_filename, gerr->message); +- exit(1); +- } +- x86ms->initrd_mapped_file = mapped_file; +- +- initrd_data = g_mapped_file_get_contents(mapped_file); +- initrd_size = g_mapped_file_get_length(mapped_file); +- if (initrd_size >= initrd_max) { +- fprintf(stderr, "qemu: initrd is too large, cannot support." +- "(max: %"PRIu32", need %"PRId64")\n", +- initrd_max, (uint64_t)initrd_size); +- exit(1); +- } +- +- initrd_addr = (initrd_max - initrd_size) & ~4095; +- +- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); +- fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); +- fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size); +- sev_load_ctx.initrd_data = initrd_data; +- sev_load_ctx.initrd_size = initrd_size; +- +- stl_p(header + 0x218, initrd_addr); +- stl_p(header + 0x21c, initrd_size); +- } +- +- /* load kernel and setup */ +- setup_size = header[0x1f1]; +- if (setup_size == 0) { +- setup_size = 4; +- } +- setup_size = (setup_size + 1) * 512; +- if (setup_size > kernel_size) { +- fprintf(stderr, "qemu: invalid kernel header\n"); +- exit(1); +- } +- kernel_size -= setup_size; +- +- setup = g_malloc(setup_size); +- kernel = g_malloc(kernel_size); +- fseek(f, 0, SEEK_SET); +- if (fread(setup, 1, setup_size, f) != setup_size) { +- fprintf(stderr, "fread() failed\n"); +- exit(1); +- } +- if (fread(kernel, 1, kernel_size, f) != kernel_size) { +- fprintf(stderr, "fread() failed\n"); +- exit(1); +- } +- fclose(f); +- +- /* append dtb to kernel */ +- if (dtb_filename) { +- if (protocol < 0x209) { +- fprintf(stderr, "qemu: Linux kernel too old to load a dtb\n"); +- exit(1); +- } +- +- dtb_size = get_image_size(dtb_filename); +- if (dtb_size <= 0) { +- fprintf(stderr, "qemu: error reading dtb %s: %s\n", +- dtb_filename, strerror(errno)); +- exit(1); +- } +- +- setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); +- kernel_size = setup_data_offset + sizeof(struct setup_data) + dtb_size; +- kernel = g_realloc(kernel, kernel_size); +- +- stq_p(header + 0x250, prot_addr + setup_data_offset); +- +- setup_data = (struct setup_data *)(kernel + setup_data_offset); +- setup_data->next = 0; +- setup_data->type = cpu_to_le32(SETUP_DTB); +- setup_data->len = cpu_to_le32(dtb_size); +- +- load_image_size(dtb_filename, setup_data->data, dtb_size); +- } +- +- /* +- * If we're starting an encrypted VM, it will be OVMF based, which uses the +- * efi stub for booting and doesn't require any values to be placed in the +- * kernel header. We therefore don't update the header so the hash of the +- * kernel on the other side of the fw_cfg interface matches the hash of the +- * file the user passed in. +- */ +- if (!sev_enabled()) { +- memcpy(setup, header, MIN(sizeof(header), setup_size)); +- } +- +- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); +- fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); +- fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); +- sev_load_ctx.kernel_data = (char *)kernel; +- sev_load_ctx.kernel_size = kernel_size; +- +- fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr); +- fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size); +- fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size); +- sev_load_ctx.setup_data = (char *)setup; +- sev_load_ctx.setup_size = setup_size; +- +- if (sev_enabled()) { +- sev_add_kernel_loader_hashes(&sev_load_ctx, &error_fatal); +- } +- +- option_rom[nb_option_roms].bootindex = 0; +- option_rom[nb_option_roms].name = "linuxboot.bin"; +- if (linuxboot_dma_enabled && fw_cfg_dma_enabled(fw_cfg)) { +- option_rom[nb_option_roms].name = "linuxboot_dma.bin"; +- } +- nb_option_roms++; +-} +- +-void x86_bios_rom_init(MachineState *ms, const char *default_firmware, +- MemoryRegion *rom_memory, bool isapc_ram_fw) +-{ +- const char *bios_name; +- char *filename; +- MemoryRegion *bios, *isa_bios; +- int bios_size, isa_bios_size; +- ssize_t ret; +- +- /* BIOS load */ +- bios_name = ms->firmware ?: default_firmware; +- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); +- if (filename) { +- bios_size = get_image_size(filename); +- } else { +- bios_size = -1; +- } +- if (bios_size <= 0 || +- (bios_size % 65536) != 0) { +- goto bios_error; +- } +- bios = g_malloc(sizeof(*bios)); +- memory_region_init_ram(bios, NULL, "pc.bios", bios_size, &error_fatal); +- if (sev_enabled()) { +- /* +- * The concept of a "reset" simply doesn't exist for +- * confidential computing guests, we have to destroy and +- * re-launch them instead. So there is no need to register +- * the firmware as rom to properly re-initialize on reset. +- * Just go for a straight file load instead. +- */ +- void *ptr = memory_region_get_ram_ptr(bios); +- load_image_size(filename, ptr, bios_size); +- x86_firmware_configure(ptr, bios_size); +- } else { +- if (!isapc_ram_fw) { +- memory_region_set_readonly(bios, true); +- } +- ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); +- if (ret != 0) { +- goto bios_error; +- } +- } +- g_free(filename); +- +- /* map the last 128KB of the BIOS in ISA space */ +- isa_bios_size = MIN(bios_size, 128 * KiB); +- isa_bios = g_malloc(sizeof(*isa_bios)); +- memory_region_init_alias(isa_bios, NULL, "isa-bios", bios, +- bios_size - isa_bios_size, isa_bios_size); +- memory_region_add_subregion_overlap(rom_memory, +- 0x100000 - isa_bios_size, +- isa_bios, +- 1); +- if (!isapc_ram_fw) { +- memory_region_set_readonly(isa_bios, true); +- } +- +- /* map all the bios at the top of memory */ +- memory_region_add_subregion(rom_memory, +- (uint32_t)(-bios_size), +- bios); +- return; +- +-bios_error: +- fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name); +- exit(1); +-} +- + bool x86_machine_is_smm_enabled(const X86MachineState *x86ms) + { + bool smm_available = false; +diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h +index da19ae15463..cb0baf24d92 100644 +--- a/include/hw/i386/x86.h ++++ b/include/hw/i386/x86.h +@@ -20,6 +20,7 @@ + #include "exec/hwaddr.h" + + #include "hw/boards.h" ++#include "hw/i386/topology.h" + #include "hw/intc/ioapic.h" + #include "hw/isa/isa.h" + #include "qom/object.h" +@@ -95,7 +96,8 @@ struct X86MachineState { + #define TYPE_X86_MACHINE MACHINE_TYPE_NAME("x86") + OBJECT_DECLARE_TYPE(X86MachineState, X86MachineClass, X86_MACHINE) + +-uint32_t x86_cpu_apic_id_from_index(X86MachineState *pcms, ++void init_topo_info(X86CPUTopoInfo *topo_info, const X86MachineState *x86ms); ++uint32_t x86_cpu_apic_id_from_index(X86MachineState *x86ms, + unsigned int cpu_index); + + void x86_cpu_new(X86MachineState *pcms, int64_t apic_id, Error **errp); +-- +2.47.3 + diff --git a/1186-i386-cpu-Fix-i-d-cache-topology-to-core-level-for-In.patch b/1186-i386-cpu-Fix-i-d-cache-topology-to-core-level-for-In.patch new file mode 100644 index 0000000000000000000000000000000000000000..de449d3f6e294884d6e572f04fc2ecd356389d81 --- /dev/null +++ b/1186-i386-cpu-Fix-i-d-cache-topology-to-core-level-for-In.patch @@ -0,0 +1,86 @@ +From 65189bd5b8c9959bfa6faf2a00e7124a2077183e Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:13 +0800 +Subject: [PATCH 08/83] i386/cpu: Fix i/d-cache topology to core level for + Intel CPU + +commit 12f6b8280fa3a89db853bef8373ddc949dbfde6b upstream. + +For i-cache and d-cache, current QEMU hardcodes the maximum IDs for CPUs +sharing cache (CPUID.04H.00H:EAX[bits 25:14] and CPUID.04H.01H:EAX[bits +25:14]) to 0, and this means i-cache and d-cache are shared in the SMT +level. + +This is correct if there's single thread per core, but is wrong for the +hyper threading case (one core contains multiple threads) since the +i-cache and d-cache are shared in the core level other than SMT level. + +For AMD CPU, commit 8f4202fb1080 ("i386: Populate AMD Processor Cache +Information for cpuid 0x8000001D") has already introduced i/d cache +topology as core level by default. + +Therefore, in order to be compatible with both multi-threaded and +single-threaded situations, we should set i-cache and d-cache be shared +at the core level by default. + +This fix changes the default i/d cache topology from per-thread to +per-core. Potentially, this change in L1 cache topology may affect the +performance of the VM if the user does not specifically specify the +topology or bind the vCPU. However, the way to achieve optimal +performance should be to create a reasonable topology and set the +appropriate vCPU affinity without relying on QEMU's default topology +structure. + +Fixes: 7e3482f82480 ("i386: Helpers to encode cache information consistently") +Intel-SIG: commit 12f6b8280fa3 i386/cpu: Fix i/d-cache topology to core level for Intel CPU. +CPU new topology backporting + +Suggested-by: Robert Hoo +Signed-off-by: Zhao Liu +Reviewed-by: Xiaoyao Li +Tested-by: Babu Moger +Tested-by: Yongwei Ma +Acked-by: Michael S. Tsirkin +Message-ID: <20240424154929.1487382-6-zhao1.liu@intel.com> +[Add compat property. - Paolo] +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index fac81358534..c2c99086e95 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6717,15 +6717,16 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *eax = *ebx = *ecx = *edx = 0; + } else { + *eax = 0; ++ int apic_ids_sharing_l1 = cpu->l1_cache_per_core ? cs->nr_threads : 1; + switch (count) { + case 0: /* L1 dcache info */ + encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache, +- 1, cs->nr_cores, ++ apic_ids_sharing_l1, cs->nr_cores, + eax, ebx, ecx, edx); + break; + case 1: /* L1 icache info */ + encode_cache_cpuid4(env->cache_info_cpuid4.l1i_cache, +- 1, cs->nr_cores, ++ apic_ids_sharing_l1, cs->nr_cores, + eax, ebx, ecx, edx); + break; + case 2: /* L2 cache info */ +@@ -8630,6 +8631,7 @@ static Property x86_cpu_properties[] = { + false), + DEFINE_PROP_BOOL("x-intel-pt-auto-level", X86CPU, intel_pt_auto_level, + true), ++ DEFINE_PROP_BOOL("x-l1-cache-per-thread", X86CPU, l1_cache_per_core, true), + DEFINE_PROP_END_OF_LIST() + }; + +-- +2.47.3 + diff --git a/1187-i386-cpu-Use-APIC-ID-info-to-encode-cache-topo-in-CP.patch b/1187-i386-cpu-Use-APIC-ID-info-to-encode-cache-topo-in-CP.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d23bc5ea8c174d335436315ada156c17372aadb --- /dev/null +++ b/1187-i386-cpu-Use-APIC-ID-info-to-encode-cache-topo-in-CP.patch @@ -0,0 +1,169 @@ +From 2adf32620b04bf48bfeb189b40988aa5c0b4ec41 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:14 +0800 +Subject: [PATCH 09/83] i386/cpu: Use APIC ID info to encode cache topo in + CPUID[4] + +commit 88dd4ca06c8392155289e5462cd26af3762a1b04 upstream. + +Refer to the fixes of cache_info_passthrough ([1], [2]) and SDM, the +CPUID.04H:EAX[bits 25:14] and CPUID.04H:EAX[bits 31:26] should use the +nearest power-of-2 integer. + +The nearest power-of-2 integer can be calculated by pow2ceil() or by +using APIC ID offset/width (like L3 topology using 1 << die_offset [3]). + +But in fact, CPUID.04H:EAX[bits 25:14] and CPUID.04H:EAX[bits 31:26] +are associated with APIC ID. For example, in linux kernel, the field +"num_threads_sharing" (Bits 25 - 14) is parsed with APIC ID. And for +another example, on Alder Lake P, the CPUID.04H:EAX[bits 31:26] is not +matched with actual core numbers and it's calculated by: +"(1 << (pkg_offset - core_offset)) - 1". + +Therefore the topology information of APIC ID should be preferred to +calculate nearest power-of-2 integer for CPUID.04H:EAX[bits 25:14] and +CPUID.04H:EAX[bits 31:26]: +1. d/i cache is shared in a core, 1 << core_offset should be used + instead of "cs->nr_threads" in encode_cache_cpuid4() for + CPUID.04H.00H:EAX[bits 25:14] and CPUID.04H.01H:EAX[bits 25:14]. +2. L2 cache is supposed to be shared in a core as for now, thereby + 1 << core_offset should also be used instead of "cs->nr_threads" in + encode_cache_cpuid4() for CPUID.04H.02H:EAX[bits 25:14]. +3. Similarly, the value for CPUID.04H:EAX[bits 31:26] should also be + calculated with the bit width between the package and SMT levels in + the APIC ID (1 << (pkg_offset - core_offset) - 1). + +In addition, use APIC ID bits calculations to replace "pow2ceil()" for +cache_info_passthrough case. + +[1]: efb3934adf9e ("x86: cpu: make sure number of addressable IDs for processor cores meets the spec") +[2]: d7caf13b5fcf ("x86: cpu: fixup number of addressable IDs for logical processors sharing cache") +[3]: d65af288a84d ("i386: Update new x86_apicid parsing rules with die_offset support") + +Fixes: 7e3482f82480 ("i386: Helpers to encode cache information consistently") +Intel-SIG: commit 88dd4ca06c83 i386/cpu: Use APIC ID info to encode cache topo in CPUID[4]. +CPU new topology backporting + +Suggested-by: Robert Hoo +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-7-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 50 +++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 40 insertions(+), 10 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index c2c99086e95..65f77c8db8e 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6613,7 +6613,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + { + X86CPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); +- uint32_t die_offset; + uint32_t limit; + uint32_t signature[3]; + X86CPUTopoInfo topo_info; +@@ -6693,7 +6692,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (cpuid2_cache_descriptor(env->cache_info_cpuid2.l1i_cache) << 8) | + (cpuid2_cache_descriptor(env->cache_info_cpuid2.l2_cache)); + break; +- case 4: ++ case 4: { ++ /* ++ * CPUID.04H:EAX[bits 25:14]: Maximum number of addressable IDs for ++ * logical processors sharing this cache. ++ */ ++ int addressable_threads_width; ++ /* ++ * CPUID.04H:EAX[bits 31:26]: Maximum number of addressable IDs for ++ * processor cores in the physical package. ++ */ ++ int addressable_cores_width; ++ + /* cache info: needed for Core compatibility */ + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); +@@ -6705,40 +6715,59 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14); + int vcpus_per_socket = cs->nr_cores * cs->nr_threads; + if (cs->nr_cores > 1) { ++ addressable_cores_width = apicid_pkg_offset(&topo_info) - ++ apicid_core_offset(&topo_info); ++ + *eax &= ~0xFC000000; +- *eax |= (pow2ceil(cs->nr_cores) - 1) << 26; ++ *eax |= ((1 << addressable_cores_width) - 1) << 26; + } + if (host_vcpus_per_cache > vcpus_per_socket) { ++ /* Share the cache at package level. */ ++ addressable_threads_width = apicid_pkg_offset(&topo_info); ++ + *eax &= ~0x3FFC000; +- *eax |= (pow2ceil(vcpus_per_socket) - 1) << 14; ++ *eax |= ((1 << addressable_threads_width) - 1) << 14; + } + } + } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { + *eax = *ebx = *ecx = *edx = 0; + } else { + *eax = 0; +- int apic_ids_sharing_l1 = cpu->l1_cache_per_core ? cs->nr_threads : 1; ++ addressable_cores_width = apicid_pkg_offset(&topo_info) - ++ apicid_core_offset(&topo_info); ++ + switch (count) { + case 0: /* L1 dcache info */ ++ addressable_threads_width = cpu->l1_cache_per_core ++ ? apicid_core_offset(&topo_info) ++ : 0; + encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache, +- apic_ids_sharing_l1, cs->nr_cores, ++ (1 << addressable_threads_width), ++ (1 << addressable_cores_width), + eax, ebx, ecx, edx); + break; + case 1: /* L1 icache info */ ++ addressable_threads_width = cpu->l1_cache_per_core ++ ? apicid_core_offset(&topo_info) ++ : 0; + encode_cache_cpuid4(env->cache_info_cpuid4.l1i_cache, +- apic_ids_sharing_l1, cs->nr_cores, ++ (1 << addressable_threads_width), ++ (1 << addressable_cores_width), + eax, ebx, ecx, edx); + break; + case 2: /* L2 cache info */ ++ addressable_threads_width = apicid_core_offset(&topo_info); + encode_cache_cpuid4(env->cache_info_cpuid4.l2_cache, +- cs->nr_threads, cs->nr_cores, ++ (1 << addressable_threads_width), ++ (1 << addressable_cores_width), + eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ +- die_offset = apicid_die_offset(&topo_info); + if (cpu->enable_l3_cache) { ++ addressable_threads_width = apicid_die_offset(&topo_info); + encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache, +- (1 << die_offset), cs->nr_cores, ++ (1 << addressable_threads_width), ++ (1 << addressable_cores_width), + eax, ebx, ecx, edx); + break; + } +@@ -6749,6 +6778,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + } + break; ++ } + case 5: + /* MONITOR/MWAIT Leaf */ + *eax = cpu->mwait.eax; /* Smallest monitor-line size in bytes */ +-- +2.47.3 + diff --git a/1188-i386-cpu-Use-APIC-ID-info-get-NumSharingCache-for-CP.patch b/1188-i386-cpu-Use-APIC-ID-info-get-NumSharingCache-for-CP.patch new file mode 100644 index 0000000000000000000000000000000000000000..c2d96aed4b996b4b917d7fed08dfb4e76365a1a2 --- /dev/null +++ b/1188-i386-cpu-Use-APIC-ID-info-get-NumSharingCache-for-CP.patch @@ -0,0 +1,79 @@ +From 5fa2d70fbdaf232f7d6f5c7a712ac58af9ada559 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:15 +0800 +Subject: [PATCH 10/83] i386/cpu: Use APIC ID info get NumSharingCache for + CPUID[0x8000001D].EAX[bits 25:14] + +commit 9a085c4b4adeec648d6506316b8a42fbd0cf7c3c upstream. + +The commit 8f4202fb1080 ("i386: Populate AMD Processor Cache Information +for cpuid 0x8000001D") adds the cache topology for AMD CPU by encoding +the number of sharing threads directly. + +From AMD's APM, NumSharingCache (CPUID[0x8000001D].EAX[bits 25:14]) +means [1]: + +The number of logical processors sharing this cache is the value of +this field incremented by 1. To determine which logical processors are +sharing a cache, determine a Share Id for each processor as follows: + +ShareId = LocalApicId >> log2(NumSharingCache+1) + +Logical processors with the same ShareId then share a cache. If +NumSharingCache+1 is not a power of two, round it up to the next power +of two. + +From the description above, the calculation of this field should be same +as CPUID[4].EAX[bits 25:14] for Intel CPUs. So also use the offsets of +APIC ID to calculate this field. + +[1]: APM, vol.3, appendix.E.4.15 Function 8000_001Dh--Cache Topology + Information + +Intel-SIG: commit 9a085c4b4ade i386/cpu: Use APIC ID info get NumSharingCache for CPUID[0x8000001D].EAX[bits 25:14]. +CPU new topology backporting + +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Reviewed-by: Babu Moger +Tested-by: Babu Moger +Reviewed-by: Xiaoyao Li +Message-ID: <20240424154929.1487382-8-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 65f77c8db8e..7702b2a9e87 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -335,7 +335,7 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) + { +- uint32_t l3_threads; ++ uint32_t num_sharing_cache; + assert(cache->size == cache->line_size * cache->associativity * + cache->partitions * cache->sets); + +@@ -344,11 +344,11 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, + + /* L3 is shared among multiple cores */ + if (cache->level == 3) { +- l3_threads = topo_info->cores_per_die * topo_info->threads_per_core; +- *eax |= (l3_threads - 1) << 14; ++ num_sharing_cache = 1 << apicid_die_offset(topo_info); + } else { +- *eax |= ((topo_info->threads_per_core - 1) << 14); ++ num_sharing_cache = 1 << apicid_core_offset(topo_info); + } ++ *eax |= (num_sharing_cache - 1) << 14; + + assert(cache->line_size > 0); + assert(cache->partitions > 0); +-- +2.47.3 + diff --git a/1189-i386-cpu-Consolidate-the-use-of-topo_info-in-cpu_x86.patch b/1189-i386-cpu-Consolidate-the-use-of-topo_info-in-cpu_x86.patch new file mode 100644 index 0000000000000000000000000000000000000000..a01c52b21adcb714bb45fa9afad2ded3aef362dc --- /dev/null +++ b/1189-i386-cpu-Consolidate-the-use-of-topo_info-in-cpu_x86.patch @@ -0,0 +1,166 @@ +From 529ada07957c45428396d17e8cb41b051e73d3f2 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:16 +0800 +Subject: [PATCH 11/83] i386/cpu: Consolidate the use of topo_info in + cpu_x86_cpuid() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 2613747a794c4de8cd04e4a24001765220e91f1b upstream. + +In cpu_x86_cpuid(), there are many variables in representing the cpu +topology, e.g., topo_info, cs->nr_cores and cs->nr_threads. + +Since the names of cs->nr_cores and cs->nr_threads do not accurately +represent its meaning, the use of cs->nr_cores or cs->nr_threads is +prone to confusion and mistakes. + +And the structure X86CPUTopoInfo names its members clearly, thus the +variable "topo_info" should be preferred. + +In addition, in cpu_x86_cpuid(), to uniformly use the topology variable, +replace env->dies with topo_info.dies_per_pkg as well. + +Intel-SIG: commit 2613747a794c i386/cpu: Consolidate the use of topo_info in cpu_x86_cpuid(). +CPU new topology backporting + +Suggested-by: Robert Hoo +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Reviewed-by: Xiaoyao Li +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-9-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 31 ++++++++++++++++++------------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 7702b2a9e87..84b0e5658c8 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6616,6 +6616,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + uint32_t limit; + uint32_t signature[3]; + X86CPUTopoInfo topo_info; ++ uint32_t cores_per_pkg; ++ uint32_t threads_per_pkg; + + if (index == 0x8C860000) { + *edx = env->features[FEAT_8C86_0000_EDX]; +@@ -6629,6 +6631,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + topo_info.cores_per_die = cs->nr_cores / env->nr_dies; + topo_info.threads_per_core = cs->nr_threads; + ++ cores_per_pkg = topo_info.cores_per_die * topo_info.dies_per_pkg; ++ threads_per_pkg = cores_per_pkg * topo_info.threads_per_core; ++ + /* Calculate & apply limits for different index ranges */ + if (index >= 0xC0000000) { + limit = env->cpuid_xlevel2; +@@ -6664,8 +6669,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *ecx |= CPUID_EXT_OSXSAVE; + } + *edx = env->features[FEAT_1_EDX]; +- if (cs->nr_cores * cs->nr_threads > 1) { +- *ebx |= (cs->nr_cores * cs->nr_threads) << 16; ++ if (threads_per_pkg > 1) { ++ *ebx |= threads_per_pkg << 16; + *edx |= CPUID_HT; + } + if (!cpu->enable_pmu) { +@@ -6713,15 +6718,15 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + */ + if (*eax & 31) { + int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14); +- int vcpus_per_socket = cs->nr_cores * cs->nr_threads; +- if (cs->nr_cores > 1) { ++ ++ if (cores_per_pkg > 1) { + addressable_cores_width = apicid_pkg_offset(&topo_info) - + apicid_core_offset(&topo_info); + + *eax &= ~0xFC000000; + *eax |= ((1 << addressable_cores_width) - 1) << 26; + } +- if (host_vcpus_per_cache > vcpus_per_socket) { ++ if (host_vcpus_per_cache > threads_per_pkg) { + /* Share the cache at package level. */ + addressable_threads_width = apicid_pkg_offset(&topo_info); + +@@ -6871,12 +6876,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + switch (count) { + case 0: + *eax = apicid_core_offset(&topo_info); +- *ebx = cs->nr_threads; ++ *ebx = topo_info.threads_per_core; + *ecx |= CPUID_TOPOLOGY_LEVEL_SMT; + break; + case 1: + *eax = apicid_pkg_offset(&topo_info); +- *ebx = cs->nr_cores * cs->nr_threads; ++ *ebx = threads_per_pkg; + *ecx |= CPUID_TOPOLOGY_LEVEL_CORE; + break; + default: +@@ -6896,7 +6901,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 0x1F: + /* V2 Extended Topology Enumeration Leaf */ +- if (env->nr_dies < 2) { ++ if (topo_info.dies_per_pkg < 2) { + *eax = *ebx = *ecx = *edx = 0; + break; + } +@@ -6906,7 +6911,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + switch (count) { + case 0: + *eax = apicid_core_offset(&topo_info); +- *ebx = cs->nr_threads; ++ *ebx = topo_info.threads_per_core; + *ecx |= CPUID_TOPOLOGY_LEVEL_SMT; + break; + case 1: +@@ -6916,7 +6921,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 2: + *eax = apicid_pkg_offset(&topo_info); +- *ebx = cs->nr_cores * cs->nr_threads; ++ *ebx = threads_per_pkg; + *ecx |= CPUID_TOPOLOGY_LEVEL_DIE; + break; + default: +@@ -7150,7 +7155,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + * discards multiple thread information if it is set. + * So don't set it here for Intel to make Linux guests happy. + */ +- if (cs->nr_cores * cs->nr_threads > 1) { ++ if (threads_per_pkg > 1) { + if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 || + env->cpuid_vendor2 != CPUID_VENDOR_INTEL_2 || + env->cpuid_vendor3 != CPUID_VENDOR_INTEL_3) { +@@ -7217,7 +7222,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *eax |= (cpu->guest_phys_bits << 16); + } + *ebx = env->features[FEAT_8000_0008_EBX]; +- if (cs->nr_cores * cs->nr_threads > 1) { ++ if (threads_per_pkg > 1) { + /* + * Bits 15:12 is "The number of bits in the initial + * Core::X86::Apic::ApicId[ApicId] value that indicate +@@ -7225,7 +7230,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + * Bits 7:0 is "The number of threads in the package is NC+1" + */ + *ecx = (apicid_pkg_offset(&topo_info) << 12) | +- ((cs->nr_cores * cs->nr_threads) - 1); ++ (threads_per_pkg - 1); + } else { + *ecx = 0; + } +-- +2.47.3 + diff --git a/1190-i386-cpu-Introduce-bitmap-to-cache-available-CPU-top.patch b/1190-i386-cpu-Introduce-bitmap-to-cache-available-CPU-top.patch new file mode 100644 index 0000000000000000000000000000000000000000..3830047cd1470d35e7294aeddb33db22d29af123 --- /dev/null +++ b/1190-i386-cpu-Introduce-bitmap-to-cache-available-CPU-top.patch @@ -0,0 +1,187 @@ +From 9eb0dcdb7c82de2b1cac903112cbe0c504109c6c Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:17 +0800 +Subject: [PATCH 12/83] i386/cpu: Introduce bitmap to cache available CPU + topology levels + +commit 6ddeb0ec8c29d51be49d5336c6d6508972b6d49c upstream. + +Currently, QEMU checks the specify number of topology domains to detect +if there's extended topology levels (e.g., checking nr_dies). + +With this bitmap, the extended CPU topology (the levels other than SMT, +core and package) could be easier to detect without touching the +topology details. + +This is also in preparation for the follow-up to decouple CPUID[0x1F] +subleaf with specific topology level. + +Intel-SIG: commit 6ddeb0ec8c29 i386/cpu: Introduce bitmap to cache available CPU topology levels. +CPU new topology backporting + +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Reviewed-by: Xiaoyao Li +Message-ID: <20240424154929.1487382-10-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86-common.c | 5 ++++- + include/hw/i386/topology.h | 23 +++++++++++++++++++++++ + target/i386/cpu.c | 18 +++++++++++++++--- + target/i386/cpu.h | 4 ++++ + target/i386/kvm/kvm.c | 3 ++- + 5 files changed, 48 insertions(+), 5 deletions(-) + +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +index d4f561102c2..c8c7bd35d08 100644 +--- a/hw/i386/x86-common.c ++++ b/hw/i386/x86-common.c +@@ -267,7 +267,10 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + + init_topo_info(&topo_info, x86ms); + +- env->nr_dies = ms->smp.dies; ++ if (ms->smp.dies > 1) { ++ env->nr_dies = ms->smp.dies; ++ set_bit(CPU_TOPO_LEVEL_DIE, env->avail_cpu_topo); ++ } + + /* + * If APIC ID is not set, +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index d4eeb7ab829..befeb92b0b1 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -60,6 +60,21 @@ typedef struct X86CPUTopoInfo { + unsigned threads_per_core; + } X86CPUTopoInfo; + ++/* ++ * CPUTopoLevel is the general i386 topology hierarchical representation, ++ * ordered by increasing hierarchical relationship. ++ * Its enumeration value is not bound to the type value of Intel (CPUID[0x1F]) ++ * or AMD (CPUID[0x80000026]). ++ */ ++enum CPUTopoLevel { ++ CPU_TOPO_LEVEL_INVALID, ++ CPU_TOPO_LEVEL_SMT, ++ CPU_TOPO_LEVEL_CORE, ++ CPU_TOPO_LEVEL_DIE, ++ CPU_TOPO_LEVEL_PACKAGE, ++ CPU_TOPO_LEVEL_MAX, ++}; ++ + /* Return the bit width needed for 'count' IDs */ + static unsigned apicid_bitwidth_for_count(unsigned count) + { +@@ -168,4 +183,12 @@ static inline apic_id_t x86_apicid_from_cpu_idx(X86CPUTopoInfo *topo_info, + return x86_apicid_from_topo_ids(topo_info, &topo_ids); + } + ++/* ++ * Check whether there's extended topology level (die)? ++ */ ++static inline bool x86_has_extended_topo(unsigned long *topo_bitmap) ++{ ++ return test_bit(CPU_TOPO_LEVEL_DIE, topo_bitmap); ++} ++ + #endif /* HW_I386_TOPOLOGY_H */ +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 84b0e5658c8..2980ec53c8c 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6901,7 +6901,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 0x1F: + /* V2 Extended Topology Enumeration Leaf */ +- if (topo_info.dies_per_pkg < 2) { ++ if (!x86_has_extended_topo(env->avail_cpu_topo)) { + *eax = *ebx = *ecx = *edx = 0; + break; + } +@@ -7764,7 +7764,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + * cpu->vendor_cpuid_only has been unset for compatibility with older + * machine types. + */ +- if ((env->nr_dies > 1) && ++ if (x86_has_extended_topo(env->avail_cpu_topo) && + (IS_INTEL_CPU(env) || !cpu->vendor_cpuid_only)) { + x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F); + } +@@ -8335,13 +8335,25 @@ static void x86_cpu_post_initfn(Object *obj) + accel_cpu_instance_init(CPU(obj)); + } + ++static void x86_cpu_init_default_topo(X86CPU *cpu) ++{ ++ CPUX86State *env = &cpu->env; ++ ++ env->nr_dies = 1; ++ ++ /* SMT, core and package levels are set by default. */ ++ set_bit(CPU_TOPO_LEVEL_SMT, env->avail_cpu_topo); ++ set_bit(CPU_TOPO_LEVEL_CORE, env->avail_cpu_topo); ++ set_bit(CPU_TOPO_LEVEL_PACKAGE, env->avail_cpu_topo); ++} ++ + static void x86_cpu_initfn(Object *obj) + { + X86CPU *cpu = X86_CPU(obj); + X86CPUClass *xcc = X86_CPU_GET_CLASS(obj); + CPUX86State *env = &cpu->env; + +- env->nr_dies = 1; ++ x86_cpu_init_default_topo(cpu); + + object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo", + x86_cpu_get_feature_words, +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 53e51423c80..531ba32ee42 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -24,6 +24,7 @@ + #include "cpu-qom.h" + #include "kvm/hyperv-proto.h" + #include "exec/cpu-defs.h" ++#include "hw/i386/topology.h" + #include "qapi/qapi-types-common.h" + #include "qemu/cpu-float.h" + #include "qemu/timer.h" +@@ -1972,6 +1973,9 @@ typedef struct CPUArchState { + + /* GHCB guest physical address info */ + uint64_t ghcb_gpa; ++ ++ /* Bitmap of available CPU topology levels for this CPU. */ ++ DECLARE_BITMAP(avail_cpu_topo, CPU_TOPO_LEVEL_MAX); + } CPUX86State; + + struct kvm_msrs; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 97bce2947d2..d119efe8643 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -51,6 +51,7 @@ + #include "hw/i386/apic_internal.h" + #include "hw/i386/apic-msidef.h" + #include "hw/i386/intel_iommu.h" ++#include "hw/i386/topology.h" + #include "hw/i386/x86-iommu.h" + #include "hw/i386/e820_memory_layout.h" + +@@ -1922,7 +1923,7 @@ int kvm_arch_init_vcpu(CPUState *cs) + break; + } + case 0x1f: +- if (env->nr_dies < 2) { ++ if (!x86_has_extended_topo(env->avail_cpu_topo)) { + cpuid_i--; + break; + } +-- +2.47.3 + diff --git a/1191-i386-Split-topology-types-of-CPUID-0x1F-from-the-def.patch b/1191-i386-Split-topology-types-of-CPUID-0x1F-from-the-def.patch new file mode 100644 index 0000000000000000000000000000000000000000..0aca9e1aab5980bf31fdd0c0d8e292221c8876c3 --- /dev/null +++ b/1191-i386-Split-topology-types-of-CPUID-0x1F-from-the-def.patch @@ -0,0 +1,119 @@ +From 85a80c84a9b80b073b2fa382ba39b97e17ec37e4 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:18 +0800 +Subject: [PATCH 13/83] i386: Split topology types of CPUID[0x1F] from the + definitions of CPUID[0xB] +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 0f6ed7ba135a45a4a28bddda74d1bf0061174b98 upstream. + +CPUID[0xB] defines SMT, Core and Invalid types, and this leaf is shared +by Intel and AMD CPUs. + +But for extended topology levels, Intel CPU (in CPUID[0x1F]) and AMD CPU +(in CPUID[0x80000026]) have the different definitions with different +enumeration values. + +Though CPUID[0x80000026] hasn't been implemented in QEMU, to avoid +possible misunderstanding, split topology types of CPUID[0x1F] from the +definitions of CPUID[0xB] and introduce CPUID[0x1F]-specific topology +types. + +Intel-SIG: commit 0f6ed7ba135a i386: Split topology types of CPUID[0x1F] from the definitions of CPUID[0xB]. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Tested-by: Yongwei Ma +Acked-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-11-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 14 +++++++------- + target/i386/cpu.h | 13 +++++++++---- + 2 files changed, 16 insertions(+), 11 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 2980ec53c8c..2e162e11d62 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6877,17 +6877,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + case 0: + *eax = apicid_core_offset(&topo_info); + *ebx = topo_info.threads_per_core; +- *ecx |= CPUID_TOPOLOGY_LEVEL_SMT; ++ *ecx |= CPUID_B_ECX_TOPO_LEVEL_SMT << 8; + break; + case 1: + *eax = apicid_pkg_offset(&topo_info); + *ebx = threads_per_pkg; +- *ecx |= CPUID_TOPOLOGY_LEVEL_CORE; ++ *ecx |= CPUID_B_ECX_TOPO_LEVEL_CORE << 8; + break; + default: + *eax = 0; + *ebx = 0; +- *ecx |= CPUID_TOPOLOGY_LEVEL_INVALID; ++ *ecx |= CPUID_B_ECX_TOPO_LEVEL_INVALID << 8; + } + + assert(!(*eax & ~0x1f)); +@@ -6912,22 +6912,22 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + case 0: + *eax = apicid_core_offset(&topo_info); + *ebx = topo_info.threads_per_core; +- *ecx |= CPUID_TOPOLOGY_LEVEL_SMT; ++ *ecx |= CPUID_1F_ECX_TOPO_LEVEL_SMT << 8; + break; + case 1: + *eax = apicid_die_offset(&topo_info); + *ebx = topo_info.cores_per_die * topo_info.threads_per_core; +- *ecx |= CPUID_TOPOLOGY_LEVEL_CORE; ++ *ecx |= CPUID_1F_ECX_TOPO_LEVEL_CORE << 8; + break; + case 2: + *eax = apicid_pkg_offset(&topo_info); + *ebx = threads_per_pkg; +- *ecx |= CPUID_TOPOLOGY_LEVEL_DIE; ++ *ecx |= CPUID_1F_ECX_TOPO_LEVEL_DIE << 8; + break; + default: + *eax = 0; + *ebx = 0; +- *ecx |= CPUID_TOPOLOGY_LEVEL_INVALID; ++ *ecx |= CPUID_1F_ECX_TOPO_LEVEL_INVALID << 8; + } + assert(!(*eax & ~0x1f)); + *ebx &= 0xffff; /* The count doesn't need to be reliable. */ +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 531ba32ee42..f6e590993b8 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1077,10 +1077,15 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); + #define CPUID_MWAIT_EMX (1U << 0) /* enumeration supported */ + + /* CPUID[0xB].ECX level types */ +-#define CPUID_TOPOLOGY_LEVEL_INVALID (0U << 8) +-#define CPUID_TOPOLOGY_LEVEL_SMT (1U << 8) +-#define CPUID_TOPOLOGY_LEVEL_CORE (2U << 8) +-#define CPUID_TOPOLOGY_LEVEL_DIE (5U << 8) ++#define CPUID_B_ECX_TOPO_LEVEL_INVALID 0 ++#define CPUID_B_ECX_TOPO_LEVEL_SMT 1 ++#define CPUID_B_ECX_TOPO_LEVEL_CORE 2 ++ ++/* COUID[0x1F].ECX level types */ ++#define CPUID_1F_ECX_TOPO_LEVEL_INVALID CPUID_B_ECX_TOPO_LEVEL_INVALID ++#define CPUID_1F_ECX_TOPO_LEVEL_SMT CPUID_B_ECX_TOPO_LEVEL_SMT ++#define CPUID_1F_ECX_TOPO_LEVEL_CORE CPUID_B_ECX_TOPO_LEVEL_CORE ++#define CPUID_1F_ECX_TOPO_LEVEL_DIE 5 + + /* MSR Feature Bits */ + #define MSR_ARCH_CAP_RDCL_NO (1U << 0) +-- +2.47.3 + diff --git a/1192-i386-cpu-Decouple-CPUID-0x1F-subleaf-with-specific-t.patch b/1192-i386-cpu-Decouple-CPUID-0x1F-subleaf-with-specific-t.patch new file mode 100644 index 0000000000000000000000000000000000000000..0c5a00f218867d3aa2a56579da4c39ad9f421a2d --- /dev/null +++ b/1192-i386-cpu-Decouple-CPUID-0x1F-subleaf-with-specific-t.patch @@ -0,0 +1,187 @@ +From 43e2abb36a4afc94bcf594fc5b4a73d5cee36f1c Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:19 +0800 +Subject: [PATCH 14/83] i386/cpu: Decouple CPUID[0x1F] subleaf with specific + topology level + +commit 822bce9f58df7ab46f70abc9c350341d5280c91a upstream. + +At present, the subleaf 0x02 of CPUID[0x1F] is bound to the "die" level. + +In fact, the specific topology level exposed in 0x1F depends on the +platform's support for extension levels (module, tile and die). + +To help expose "module" level in 0x1F, decouple CPUID[0x1F] subleaf +with specific topology level. + +Intel-SIG: commit 822bce9f58df i386/cpu: Decouple CPUID[0x1F] subleaf with specific topology level. +CPU new topology backporting + +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Reviewed-by: Xiaoyao Li +Message-ID: <20240424154929.1487382-12-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 135 +++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 110 insertions(+), 25 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 2e162e11d62..66134331e7e 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -273,6 +273,115 @@ static void encode_cache_cpuid4(CPUCacheInfo *cache, + (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0); + } + ++static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info, ++ enum CPUTopoLevel topo_level) ++{ ++ switch (topo_level) { ++ case CPU_TOPO_LEVEL_SMT: ++ return 1; ++ case CPU_TOPO_LEVEL_CORE: ++ return topo_info->threads_per_core; ++ case CPU_TOPO_LEVEL_DIE: ++ return topo_info->threads_per_core * topo_info->cores_per_die; ++ case CPU_TOPO_LEVEL_PACKAGE: ++ return topo_info->threads_per_core * topo_info->cores_per_die * ++ topo_info->dies_per_pkg; ++ default: ++ g_assert_not_reached(); ++ } ++ return 0; ++} ++ ++static uint32_t apicid_offset_by_topo_level(X86CPUTopoInfo *topo_info, ++ enum CPUTopoLevel topo_level) ++{ ++ switch (topo_level) { ++ case CPU_TOPO_LEVEL_SMT: ++ return 0; ++ case CPU_TOPO_LEVEL_CORE: ++ return apicid_core_offset(topo_info); ++ case CPU_TOPO_LEVEL_DIE: ++ return apicid_die_offset(topo_info); ++ case CPU_TOPO_LEVEL_PACKAGE: ++ return apicid_pkg_offset(topo_info); ++ default: ++ g_assert_not_reached(); ++ } ++ return 0; ++} ++ ++static uint32_t cpuid1f_topo_type(enum CPUTopoLevel topo_level) ++{ ++ switch (topo_level) { ++ case CPU_TOPO_LEVEL_INVALID: ++ return CPUID_1F_ECX_TOPO_LEVEL_INVALID; ++ case CPU_TOPO_LEVEL_SMT: ++ return CPUID_1F_ECX_TOPO_LEVEL_SMT; ++ case CPU_TOPO_LEVEL_CORE: ++ return CPUID_1F_ECX_TOPO_LEVEL_CORE; ++ case CPU_TOPO_LEVEL_DIE: ++ return CPUID_1F_ECX_TOPO_LEVEL_DIE; ++ default: ++ /* Other types are not supported in QEMU. */ ++ g_assert_not_reached(); ++ } ++ return 0; ++} ++ ++static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count, ++ X86CPUTopoInfo *topo_info, ++ uint32_t *eax, uint32_t *ebx, ++ uint32_t *ecx, uint32_t *edx) ++{ ++ X86CPU *cpu = env_archcpu(env); ++ unsigned long level, next_level; ++ uint32_t num_threads_next_level, offset_next_level; ++ ++ assert(count + 1 < CPU_TOPO_LEVEL_MAX); ++ ++ /* ++ * Find the No.(count + 1) topology level in avail_cpu_topo bitmap. ++ * The search starts from bit 1 (CPU_TOPO_LEVEL_INVALID + 1). ++ */ ++ level = CPU_TOPO_LEVEL_INVALID; ++ for (int i = 0; i <= count; i++) { ++ level = find_next_bit(env->avail_cpu_topo, ++ CPU_TOPO_LEVEL_PACKAGE, ++ level + 1); ++ ++ /* ++ * CPUID[0x1f] doesn't explicitly encode the package level, ++ * and it just encodes the invalid level (all fields are 0) ++ * into the last subleaf of 0x1f. ++ */ ++ if (level == CPU_TOPO_LEVEL_PACKAGE) { ++ level = CPU_TOPO_LEVEL_INVALID; ++ break; ++ } ++ } ++ ++ if (level == CPU_TOPO_LEVEL_INVALID) { ++ num_threads_next_level = 0; ++ offset_next_level = 0; ++ } else { ++ next_level = find_next_bit(env->avail_cpu_topo, ++ CPU_TOPO_LEVEL_PACKAGE, ++ level + 1); ++ num_threads_next_level = num_threads_by_topo_level(topo_info, ++ next_level); ++ offset_next_level = apicid_offset_by_topo_level(topo_info, ++ next_level); ++ } ++ ++ *eax = offset_next_level; ++ /* The count (bits 15-00) doesn't need to be reliable. */ ++ *ebx = num_threads_next_level & 0xffff; ++ *ecx = (count & 0xff) | (cpuid1f_topo_type(level) << 8); ++ *edx = cpu->apic_id; ++ ++ assert(!(*eax & ~0x1f)); ++} ++ + /* Encode cache info for CPUID[0x80000005].ECX or CPUID[0x80000005].EDX */ + static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache) + { +@@ -6906,31 +7015,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + } + +- *ecx = count & 0xff; +- *edx = cpu->apic_id; +- switch (count) { +- case 0: +- *eax = apicid_core_offset(&topo_info); +- *ebx = topo_info.threads_per_core; +- *ecx |= CPUID_1F_ECX_TOPO_LEVEL_SMT << 8; +- break; +- case 1: +- *eax = apicid_die_offset(&topo_info); +- *ebx = topo_info.cores_per_die * topo_info.threads_per_core; +- *ecx |= CPUID_1F_ECX_TOPO_LEVEL_CORE << 8; +- break; +- case 2: +- *eax = apicid_pkg_offset(&topo_info); +- *ebx = threads_per_pkg; +- *ecx |= CPUID_1F_ECX_TOPO_LEVEL_DIE << 8; +- break; +- default: +- *eax = 0; +- *ebx = 0; +- *ecx |= CPUID_1F_ECX_TOPO_LEVEL_INVALID << 8; +- } +- assert(!(*eax & ~0x1f)); +- *ebx &= 0xffff; /* The count doesn't need to be reliable. */ ++ encode_topo_cpuid1f(env, count, &topo_info, eax, ebx, ecx, edx); + break; + case 0xD: { + /* Processor Extended State */ +-- +2.47.3 + diff --git a/1193-i386-Introduce-module-level-cpu-topology-to-CPUX86St.patch b/1193-i386-Introduce-module-level-cpu-topology-to-CPUX86St.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c888e33cdfc75a8c96d032fcbb76f86f6d3669d --- /dev/null +++ b/1193-i386-Introduce-module-level-cpu-topology-to-CPUX86St.patch @@ -0,0 +1,83 @@ +From 78c3a66163ff4af2dc8ecacbcf1c5791aeca423f Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:20 +0800 +Subject: [PATCH 15/83] i386: Introduce module level cpu topology to + CPUX86State + +commit 81c392ab5c7489955d7e2b515b7186a4cd174c71 upstream. + +Intel CPUs implement module level on hybrid client products (e.g., +ADL-N, MTL, etc) and E-core server products. + +A module contains a set of cores that share certain resources (in +current products, the resource usually includes L2 cache, as well as +module scoped features and MSRs). + +Module level support is the prerequisite for L2 cache topology on +module level. With module level, we can implement the Guest's CPU +topology and future cache topology to be consistent with the Host's on +Intel hybrid client/E-core server platforms. + +Intel-SIG: commit 81c392ab5c74 i386: Introduce module level cpu topology to CPUX86State. +CPU new topology backporting + +Tested-by: Yongwei Ma +Co-developed-by: Zhuocheng Ding +Signed-off-by: Zhuocheng Ding +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-13-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86-common.c | 5 +++++ + target/i386/cpu.c | 1 + + target/i386/cpu.h | 3 +++ + 3 files changed, 9 insertions(+) + +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +index c8c7bd35d08..034a4f6f1ed 100644 +--- a/hw/i386/x86-common.c ++++ b/hw/i386/x86-common.c +@@ -267,6 +267,11 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + + init_topo_info(&topo_info, x86ms); + ++ if (ms->smp.modules > 1) { ++ env->nr_modules = ms->smp.modules; ++ /* TODO: Expose module level in CPUID[0x1F]. */ ++ } ++ + if (ms->smp.dies > 1) { + env->nr_dies = ms->smp.dies; + set_bit(CPU_TOPO_LEVEL_DIE, env->avail_cpu_topo); +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 66134331e7e..23f8f69c26f 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -8424,6 +8424,7 @@ static void x86_cpu_init_default_topo(X86CPU *cpu) + { + CPUX86State *env = &cpu->env; + ++ env->nr_modules = 1; + env->nr_dies = 1; + + /* SMT, core and package levels are set by default. */ +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index f6e590993b8..0855b1ed553 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1979,6 +1979,9 @@ typedef struct CPUArchState { + /* GHCB guest physical address info */ + uint64_t ghcb_gpa; + ++ /* Number of modules within one die. */ ++ unsigned nr_modules; ++ + /* Bitmap of available CPU topology levels for this CPU. */ + DECLARE_BITMAP(avail_cpu_topo, CPU_TOPO_LEVEL_MAX); + } CPUX86State; +-- +2.47.3 + diff --git a/1194-i386-Support-modules_per_die-in-X86CPUTopoInfo.patch b/1194-i386-Support-modules_per_die-in-X86CPUTopoInfo.patch new file mode 100644 index 0000000000000000000000000000000000000000..004a5e904856d0c66b8118d722a793dd59d78c8c --- /dev/null +++ b/1194-i386-Support-modules_per_die-in-X86CPUTopoInfo.patch @@ -0,0 +1,253 @@ +From ad16269c05dd18236da70745bcb5b660ca4ff4ef Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:21 +0800 +Subject: [PATCH 16/83] i386: Support modules_per_die in X86CPUTopoInfo + +commit 3568adc995b3906b5cc134753a829363f08bf6e1 upstream. + +Support module level in i386 cpu topology structure "X86CPUTopoInfo". + +Since x86 does not yet support the "modules" parameter in "-smp", +X86CPUTopoInfo.modules_per_die is currently always 1. + +Therefore, the module level width in APIC ID, which can be calculated by +"apicid_bitwidth_for_count(topo_info->modules_per_die)", is always 0 for +now, so we can directly add APIC ID related helpers to support module +level parsing. + +In addition, update topology structure in test-x86-topo.c. + +Intel-SIG: commit 3568adc995b3 i386: Support modules_per_die in X86CPUTopoInfo. +CPU new topology backporting + +Tested-by: Yongwei Ma +Co-developed-by: Zhuocheng Ding +Signed-off-by: Zhuocheng Ding +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-14-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86.c | 9 +++++++- + include/hw/i386/topology.h | 22 +++++++++++++++---- + target/i386/cpu.c | 13 ++++++----- + tests/unit/test-x86-topo.c | 45 ++++++++++++++++++++------------------ + 4 files changed, 58 insertions(+), 31 deletions(-) + +diff --git a/hw/i386/x86.c b/hw/i386/x86.c +index b9635c9ba42..2024dc9770c 100644 +--- a/hw/i386/x86.c ++++ b/hw/i386/x86.c +@@ -45,7 +45,14 @@ void init_topo_info(X86CPUTopoInfo *topo_info, + MachineState *ms = MACHINE(x86ms); + + topo_info->dies_per_pkg = ms->smp.dies; +- topo_info->cores_per_die = ms->smp.cores; ++ /* ++ * Though smp.modules means the number of modules in one cluster, ++ * i386 doesn't support cluster level so that the smp.clusters ++ * always defaults to 1, therefore using smp.modules directly is ++ * fine here. ++ */ ++ topo_info->modules_per_die = ms->smp.modules; ++ topo_info->cores_per_module = ms->smp.cores; + topo_info->threads_per_core = ms->smp.threads; + } + +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index befeb92b0b1..7622d806932 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -56,7 +56,8 @@ typedef struct X86CPUTopoIDs { + + typedef struct X86CPUTopoInfo { + unsigned dies_per_pkg; +- unsigned cores_per_die; ++ unsigned modules_per_die; ++ unsigned cores_per_module; + unsigned threads_per_core; + } X86CPUTopoInfo; + +@@ -92,7 +93,13 @@ static inline unsigned apicid_smt_width(X86CPUTopoInfo *topo_info) + /* Bit width of the Core_ID field */ + static inline unsigned apicid_core_width(X86CPUTopoInfo *topo_info) + { +- return apicid_bitwidth_for_count(topo_info->cores_per_die); ++ return apicid_bitwidth_for_count(topo_info->cores_per_module); ++} ++ ++/* Bit width of the Module_ID field */ ++static inline unsigned apicid_module_width(X86CPUTopoInfo *topo_info) ++{ ++ return apicid_bitwidth_for_count(topo_info->modules_per_die); + } + + /* Bit width of the Die_ID field */ +@@ -107,10 +114,16 @@ static inline unsigned apicid_core_offset(X86CPUTopoInfo *topo_info) + return apicid_smt_width(topo_info); + } + ++/* Bit offset of the Module_ID field */ ++static inline unsigned apicid_module_offset(X86CPUTopoInfo *topo_info) ++{ ++ return apicid_core_offset(topo_info) + apicid_core_width(topo_info); ++} ++ + /* Bit offset of the Die_ID field */ + static inline unsigned apicid_die_offset(X86CPUTopoInfo *topo_info) + { +- return apicid_core_offset(topo_info) + apicid_core_width(topo_info); ++ return apicid_module_offset(topo_info) + apicid_module_width(topo_info); + } + + /* Bit offset of the Pkg_ID (socket ID) field */ +@@ -142,7 +155,8 @@ static inline void x86_topo_ids_from_idx(X86CPUTopoInfo *topo_info, + X86CPUTopoIDs *topo_ids) + { + unsigned nr_dies = topo_info->dies_per_pkg; +- unsigned nr_cores = topo_info->cores_per_die; ++ unsigned nr_cores = topo_info->cores_per_module * ++ topo_info->modules_per_die; + unsigned nr_threads = topo_info->threads_per_core; + + topo_ids->pkg_id = cpu_index / (nr_dies * nr_cores * nr_threads); +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 23f8f69c26f..2048dd677b2 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -282,10 +282,11 @@ static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info, + case CPU_TOPO_LEVEL_CORE: + return topo_info->threads_per_core; + case CPU_TOPO_LEVEL_DIE: +- return topo_info->threads_per_core * topo_info->cores_per_die; ++ return topo_info->threads_per_core * topo_info->cores_per_module * ++ topo_info->modules_per_die; + case CPU_TOPO_LEVEL_PACKAGE: +- return topo_info->threads_per_core * topo_info->cores_per_die * +- topo_info->dies_per_pkg; ++ return topo_info->threads_per_core * topo_info->cores_per_module * ++ topo_info->modules_per_die * topo_info->dies_per_pkg; + default: + g_assert_not_reached(); + } +@@ -6737,10 +6738,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + + topo_info.dies_per_pkg = env->nr_dies; +- topo_info.cores_per_die = cs->nr_cores / env->nr_dies; ++ topo_info.modules_per_die = env->nr_modules; ++ topo_info.cores_per_module = cs->nr_cores / env->nr_dies / env->nr_modules; + topo_info.threads_per_core = cs->nr_threads; + +- cores_per_pkg = topo_info.cores_per_die * topo_info.dies_per_pkg; ++ cores_per_pkg = topo_info.cores_per_module * topo_info.modules_per_die * ++ topo_info.dies_per_pkg; + threads_per_pkg = cores_per_pkg * topo_info.threads_per_core; + + /* Calculate & apply limits for different index ranges */ +diff --git a/tests/unit/test-x86-topo.c b/tests/unit/test-x86-topo.c +index 2b104f86d7c..f21b8a5d95c 100644 +--- a/tests/unit/test-x86-topo.c ++++ b/tests/unit/test-x86-topo.c +@@ -30,13 +30,16 @@ static void test_topo_bits(void) + { + X86CPUTopoInfo topo_info = {0}; + +- /* simple tests for 1 thread per core, 1 core per die, 1 die per package */ +- topo_info = (X86CPUTopoInfo) {1, 1, 1}; ++ /* ++ * simple tests for 1 thread per core, 1 core per module, ++ * 1 module per die, 1 die per package ++ */ ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 1}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 0); + g_assert_cmpuint(apicid_core_width(&topo_info), ==, 0); + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 0); + +- topo_info = (X86CPUTopoInfo) {1, 1, 1}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 1}; + g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 0), ==, 0); + g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 1), ==, 1); + g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 2), ==, 2); +@@ -45,39 +48,39 @@ static void test_topo_bits(void) + + /* Test field width calculation for multiple values + */ +- topo_info = (X86CPUTopoInfo) {1, 1, 2}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 2}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 1); +- topo_info = (X86CPUTopoInfo) {1, 1, 3}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 3}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 2); +- topo_info = (X86CPUTopoInfo) {1, 1, 4}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 4}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 2); + +- topo_info = (X86CPUTopoInfo) {1, 1, 14}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 14}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 4); +- topo_info = (X86CPUTopoInfo) {1, 1, 15}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 15}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 4); +- topo_info = (X86CPUTopoInfo) {1, 1, 16}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 16}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 4); +- topo_info = (X86CPUTopoInfo) {1, 1, 17}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 1, 17}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 5); + + +- topo_info = (X86CPUTopoInfo) {1, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 30, 2}; + g_assert_cmpuint(apicid_core_width(&topo_info), ==, 5); +- topo_info = (X86CPUTopoInfo) {1, 31, 2}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 31, 2}; + g_assert_cmpuint(apicid_core_width(&topo_info), ==, 5); +- topo_info = (X86CPUTopoInfo) {1, 32, 2}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 32, 2}; + g_assert_cmpuint(apicid_core_width(&topo_info), ==, 5); +- topo_info = (X86CPUTopoInfo) {1, 33, 2}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 33, 2}; + g_assert_cmpuint(apicid_core_width(&topo_info), ==, 6); + +- topo_info = (X86CPUTopoInfo) {1, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 30, 2}; + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 0); +- topo_info = (X86CPUTopoInfo) {2, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {2, 1, 30, 2}; + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 1); +- topo_info = (X86CPUTopoInfo) {3, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {3, 1, 30, 2}; + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 2); +- topo_info = (X86CPUTopoInfo) {4, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {4, 1, 30, 2}; + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 2); + + /* build a weird topology and see if IDs are calculated correctly +@@ -85,18 +88,18 @@ static void test_topo_bits(void) + + /* This will use 2 bits for thread ID and 3 bits for core ID + */ +- topo_info = (X86CPUTopoInfo) {1, 6, 3}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 6, 3}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 2); + g_assert_cmpuint(apicid_core_offset(&topo_info), ==, 2); + g_assert_cmpuint(apicid_die_offset(&topo_info), ==, 5); + g_assert_cmpuint(apicid_pkg_offset(&topo_info), ==, 5); + +- topo_info = (X86CPUTopoInfo) {1, 6, 3}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 6, 3}; + g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 0), ==, 0); + g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 1), ==, 1); + g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 2), ==, 2); + +- topo_info = (X86CPUTopoInfo) {1, 6, 3}; ++ topo_info = (X86CPUTopoInfo) {1, 1, 6, 3}; + g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 1 * 3 + 0), ==, + (1 << 2) | 0); + g_assert_cmpuint(x86_apicid_from_cpu_idx(&topo_info, 1 * 3 + 1), ==, +-- +2.47.3 + diff --git a/1195-i386-Expose-module-level-in-CPUID-0x1F.patch b/1195-i386-Expose-module-level-in-CPUID-0x1F.patch new file mode 100644 index 0000000000000000000000000000000000000000..930250e57aa61257e1f45ea2a4573d4caae83993 --- /dev/null +++ b/1195-i386-Expose-module-level-in-CPUID-0x1F.patch @@ -0,0 +1,117 @@ +From 09075a4d9d39f2ae7d2c897a19733420ea874b06 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:22 +0800 +Subject: [PATCH 17/83] i386: Expose module level in CPUID[0x1F] + +commit 5304873acd12f7a4ddb07d3560ac5ac02a0e1060 upstream. + +Linux kernel (from v6.4, with commit edc0a2b595765 ("x86/topology: Fix +erroneous smp_num_siblings on Intel Hybrid platforms") is able to +handle platforms with Module level enumerated via CPUID.1F. + +Expose the module level in CPUID[0x1F] if the machine has more than 1 +modules. + +Intel-SIG: commit 5304873acd12 i386: Expose module level in CPUID[0x1F]. +CPU new topology backporting + +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-15-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86-common.c | 2 +- + include/hw/i386/topology.h | 6 ++++-- + target/i386/cpu.c | 6 ++++++ + target/i386/cpu.h | 1 + + 4 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +index 034a4f6f1ed..958e190c62d 100644 +--- a/hw/i386/x86-common.c ++++ b/hw/i386/x86-common.c +@@ -269,7 +269,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + + if (ms->smp.modules > 1) { + env->nr_modules = ms->smp.modules; +- /* TODO: Expose module level in CPUID[0x1F]. */ ++ set_bit(CPU_TOPO_LEVEL_MODULE, env->avail_cpu_topo); + } + + if (ms->smp.dies > 1) { +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index 7622d806932..ea871045779 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -71,6 +71,7 @@ enum CPUTopoLevel { + CPU_TOPO_LEVEL_INVALID, + CPU_TOPO_LEVEL_SMT, + CPU_TOPO_LEVEL_CORE, ++ CPU_TOPO_LEVEL_MODULE, + CPU_TOPO_LEVEL_DIE, + CPU_TOPO_LEVEL_PACKAGE, + CPU_TOPO_LEVEL_MAX, +@@ -198,11 +199,12 @@ static inline apic_id_t x86_apicid_from_cpu_idx(X86CPUTopoInfo *topo_info, + } + + /* +- * Check whether there's extended topology level (die)? ++ * Check whether there's extended topology level (module or die)? + */ + static inline bool x86_has_extended_topo(unsigned long *topo_bitmap) + { +- return test_bit(CPU_TOPO_LEVEL_DIE, topo_bitmap); ++ return test_bit(CPU_TOPO_LEVEL_MODULE, topo_bitmap) || ++ test_bit(CPU_TOPO_LEVEL_DIE, topo_bitmap); + } + + #endif /* HW_I386_TOPOLOGY_H */ +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 2048dd677b2..6d09dc4f229 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -281,6 +281,8 @@ static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info, + return 1; + case CPU_TOPO_LEVEL_CORE: + return topo_info->threads_per_core; ++ case CPU_TOPO_LEVEL_MODULE: ++ return topo_info->threads_per_core * topo_info->cores_per_module; + case CPU_TOPO_LEVEL_DIE: + return topo_info->threads_per_core * topo_info->cores_per_module * + topo_info->modules_per_die; +@@ -301,6 +303,8 @@ static uint32_t apicid_offset_by_topo_level(X86CPUTopoInfo *topo_info, + return 0; + case CPU_TOPO_LEVEL_CORE: + return apicid_core_offset(topo_info); ++ case CPU_TOPO_LEVEL_MODULE: ++ return apicid_module_offset(topo_info); + case CPU_TOPO_LEVEL_DIE: + return apicid_die_offset(topo_info); + case CPU_TOPO_LEVEL_PACKAGE: +@@ -320,6 +324,8 @@ static uint32_t cpuid1f_topo_type(enum CPUTopoLevel topo_level) + return CPUID_1F_ECX_TOPO_LEVEL_SMT; + case CPU_TOPO_LEVEL_CORE: + return CPUID_1F_ECX_TOPO_LEVEL_CORE; ++ case CPU_TOPO_LEVEL_MODULE: ++ return CPUID_1F_ECX_TOPO_LEVEL_MODULE; + case CPU_TOPO_LEVEL_DIE: + return CPUID_1F_ECX_TOPO_LEVEL_DIE; + default: +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 0855b1ed553..d42e846303c 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1085,6 +1085,7 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); + #define CPUID_1F_ECX_TOPO_LEVEL_INVALID CPUID_B_ECX_TOPO_LEVEL_INVALID + #define CPUID_1F_ECX_TOPO_LEVEL_SMT CPUID_B_ECX_TOPO_LEVEL_SMT + #define CPUID_1F_ECX_TOPO_LEVEL_CORE CPUID_B_ECX_TOPO_LEVEL_CORE ++#define CPUID_1F_ECX_TOPO_LEVEL_MODULE 3 + #define CPUID_1F_ECX_TOPO_LEVEL_DIE 5 + + /* MSR Feature Bits */ +-- +2.47.3 + diff --git a/1196-i386-Support-module_id-in-X86CPUTopoIDs.patch b/1196-i386-Support-module_id-in-X86CPUTopoIDs.patch new file mode 100644 index 0000000000000000000000000000000000000000..2446869403ba3151d5b0d0160bc248fb069d5d6b --- /dev/null +++ b/1196-i386-Support-module_id-in-X86CPUTopoIDs.patch @@ -0,0 +1,168 @@ +From 5b7085d03b08d941aed2cea37f40da36dbcba402 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:23 +0800 +Subject: [PATCH 18/83] i386: Support module_id in X86CPUTopoIDs + +commit b17a26bc4b0289ca7415f821bb0a89a8a333cea5 upstream. + +Add module_id member in X86CPUTopoIDs. + +module_id can be parsed from APIC ID, so also update APIC ID parsing +rule to support module level. With this support, the conversions with +module level between X86CPUTopoIDs, X86CPUTopoInfo and APIC ID are +completed. + +module_id can be also generated from cpu topology, and before i386 +supports "modules" in smp, the default "modules per die" (modules * +clusters) is only 1, thus the module_id generated in this way is 0, +so that it will not conflict with the module_id generated by APIC ID. + +Intel-SIG: commit b17a26bc4b02 i386: Support module_id in X86CPUTopoIDs. +CPU new topology backporting + +Tested-by: Yongwei Ma +Signed-off-by: Zhuocheng Ding +Co-developed-by: Zhuocheng Ding +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-16-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86-common.c | 27 +++++++++++++++++---------- + hw/i386/x86.c | 4 ++++ + include/hw/i386/topology.h | 17 +++++++++++++---- + 3 files changed, 34 insertions(+), 14 deletions(-) + +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +index 958e190c62d..5246da80361 100644 +--- a/hw/i386/x86-common.c ++++ b/hw/i386/x86-common.c +@@ -279,12 +279,9 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + + /* + * If APIC ID is not set, +- * set it based on socket/die/core/thread properties. ++ * set it based on socket/die/module/core/thread properties. + */ + if (cpu->apic_id == UNASSIGNED_APIC_ID) { +- int max_socket = (ms->smp.max_cpus - 1) / +- smp_threads / smp_cores / ms->smp.dies; +- + /* + * die-id was optional in QEMU 4.0 and older, so keep it optional + * if there's only one die per socket. +@@ -296,9 +293,9 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + if (cpu->socket_id < 0) { + error_setg(errp, "CPU socket-id is not set"); + return; +- } else if (cpu->socket_id > max_socket) { ++ } else if (cpu->socket_id > ms->smp.sockets - 1) { + error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", +- cpu->socket_id, max_socket); ++ cpu->socket_id, ms->smp.sockets - 1); + return; + } + if (cpu->die_id < 0) { +@@ -330,17 +327,27 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + topo_ids.die_id = cpu->die_id; + topo_ids.core_id = cpu->core_id; + topo_ids.smt_id = cpu->thread_id; ++ ++ /* ++ * TODO: This is the temporary initialization for topo_ids.module_id to ++ * avoid "maybe-uninitialized" compilation errors. Will remove when ++ * X86CPU supports module_id. ++ */ ++ topo_ids.module_id = 0; ++ + cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids); + } + + cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); + if (!cpu_slot) { + x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); ++ + error_setg(errp, +- "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with" +- " APIC ID %" PRIu32 ", valid index range 0:%d", +- topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id, +- cpu->apic_id, ms->possible_cpus->len - 1); ++ "Invalid CPU [socket: %u, die: %u, module: %u, core: %u, thread: %u]" ++ " with APIC ID %" PRIu32 ", valid index range 0:%d", ++ topo_ids.pkg_id, topo_ids.die_id, topo_ids.module_id, ++ topo_ids.core_id, topo_ids.smt_id, cpu->apic_id, ++ ms->possible_cpus->len - 1); + return; + } + +diff --git a/hw/i386/x86.c b/hw/i386/x86.c +index 2024dc9770c..19f1e1b1d6e 100644 +--- a/hw/i386/x86.c ++++ b/hw/i386/x86.c +@@ -135,6 +135,10 @@ const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms) + ms->possible_cpus->cpus[i].props.has_die_id = true; + ms->possible_cpus->cpus[i].props.die_id = topo_ids.die_id; + } ++ if (ms->smp.modules > 1) { ++ ms->possible_cpus->cpus[i].props.has_module_id = true; ++ ms->possible_cpus->cpus[i].props.module_id = topo_ids.module_id; ++ } + ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.core_id = topo_ids.core_id; + ms->possible_cpus->cpus[i].props.has_thread_id = true; +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index ea871045779..dff49fce115 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -50,6 +50,7 @@ typedef uint32_t apic_id_t; + typedef struct X86CPUTopoIDs { + unsigned pkg_id; + unsigned die_id; ++ unsigned module_id; + unsigned core_id; + unsigned smt_id; + } X86CPUTopoIDs; +@@ -143,6 +144,7 @@ static inline apic_id_t x86_apicid_from_topo_ids(X86CPUTopoInfo *topo_info, + { + return (topo_ids->pkg_id << apicid_pkg_offset(topo_info)) | + (topo_ids->die_id << apicid_die_offset(topo_info)) | ++ (topo_ids->module_id << apicid_module_offset(topo_info)) | + (topo_ids->core_id << apicid_core_offset(topo_info)) | + topo_ids->smt_id; + } +@@ -156,12 +158,16 @@ static inline void x86_topo_ids_from_idx(X86CPUTopoInfo *topo_info, + X86CPUTopoIDs *topo_ids) + { + unsigned nr_dies = topo_info->dies_per_pkg; +- unsigned nr_cores = topo_info->cores_per_module * +- topo_info->modules_per_die; ++ unsigned nr_modules = topo_info->modules_per_die; ++ unsigned nr_cores = topo_info->cores_per_module; + unsigned nr_threads = topo_info->threads_per_core; + +- topo_ids->pkg_id = cpu_index / (nr_dies * nr_cores * nr_threads); +- topo_ids->die_id = cpu_index / (nr_cores * nr_threads) % nr_dies; ++ topo_ids->pkg_id = cpu_index / (nr_dies * nr_modules * ++ nr_cores * nr_threads); ++ topo_ids->die_id = cpu_index / (nr_modules * nr_cores * ++ nr_threads) % nr_dies; ++ topo_ids->module_id = cpu_index / (nr_cores * nr_threads) % ++ nr_modules; + topo_ids->core_id = cpu_index / nr_threads % nr_cores; + topo_ids->smt_id = cpu_index % nr_threads; + } +@@ -179,6 +185,9 @@ static inline void x86_topo_ids_from_apicid(apic_id_t apicid, + topo_ids->core_id = + (apicid >> apicid_core_offset(topo_info)) & + ~(0xFFFFFFFFUL << apicid_core_width(topo_info)); ++ topo_ids->module_id = ++ (apicid >> apicid_module_offset(topo_info)) & ++ ~(0xFFFFFFFFUL << apicid_module_width(topo_info)); + topo_ids->die_id = + (apicid >> apicid_die_offset(topo_info)) & + ~(0xFFFFFFFFUL << apicid_die_width(topo_info)); +-- +2.47.3 + diff --git a/1197-i386-cpu-Introduce-module-id-to-X86CPU.patch b/1197-i386-cpu-Introduce-module-id-to-X86CPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..f72b8ceaba3daad69f81639b259d149945845568 --- /dev/null +++ b/1197-i386-cpu-Introduce-module-id-to-X86CPU.patch @@ -0,0 +1,132 @@ +From 760ed29a15e05022a0cb00fff72cba1d5586ba5f Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:24 +0800 +Subject: [PATCH 19/83] i386/cpu: Introduce module-id to X86CPU + +commit 588208346f92e6030ae1d4bee94096ca0e070b60 upstream. + +Introduce module-id to be consistent with the module-id field in +CpuInstanceProperties. + +Following the legacy smp check rules, also add the module_id validity +into x86_cpu_pre_plug(). + +Intel-SIG: commit 588208346f92 i386/cpu: Introduce module-id to X86CPU. +CPU new topology backporting + +Tested-by: Yongwei Ma +Co-developed-by: Zhuocheng Ding +Signed-off-by: Zhuocheng Ding +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-17-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86-common.c | 33 +++++++++++++++++++++++++-------- + target/i386/cpu.c | 2 ++ + target/i386/cpu.h | 1 + + 3 files changed, 28 insertions(+), 8 deletions(-) + +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +index 5246da80361..9af5a98c3d0 100644 +--- a/hw/i386/x86-common.c ++++ b/hw/i386/x86-common.c +@@ -290,6 +290,14 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + cpu->die_id = 0; + } + ++ /* ++ * module-id was optional in QEMU 9.0 and older, so keep it optional ++ * if there's only one module per die. ++ */ ++ if (cpu->module_id < 0 && ms->smp.modules == 1) { ++ cpu->module_id = 0; ++ } ++ + if (cpu->socket_id < 0) { + error_setg(errp, "CPU socket-id is not set"); + return; +@@ -306,6 +314,14 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + cpu->die_id, ms->smp.dies - 1); + return; + } ++ if (cpu->module_id < 0) { ++ error_setg(errp, "CPU module-id is not set"); ++ return; ++ } else if (cpu->module_id > ms->smp.modules - 1) { ++ error_setg(errp, "Invalid CPU module-id: %u must be in range 0:%u", ++ cpu->module_id, ms->smp.modules - 1); ++ return; ++ } + if (cpu->core_id < 0) { + error_setg(errp, "CPU core-id is not set"); + return; +@@ -325,16 +341,9 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + + topo_ids.pkg_id = cpu->socket_id; + topo_ids.die_id = cpu->die_id; ++ topo_ids.module_id = cpu->module_id; + topo_ids.core_id = cpu->core_id; + topo_ids.smt_id = cpu->thread_id; +- +- /* +- * TODO: This is the temporary initialization for topo_ids.module_id to +- * avoid "maybe-uninitialized" compilation errors. Will remove when +- * X86CPU supports module_id. +- */ +- topo_ids.module_id = 0; +- + cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids); + } + +@@ -379,6 +388,14 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + } + cpu->die_id = topo_ids.die_id; + ++ if (cpu->module_id != -1 && cpu->module_id != topo_ids.module_id) { ++ error_setg(errp, "property module-id: %u doesn't match set apic-id:" ++ " 0x%x (module-id: %u)", cpu->module_id, cpu->apic_id, ++ topo_ids.module_id); ++ return; ++ } ++ cpu->module_id = topo_ids.module_id; ++ + if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) { + error_setg(errp, "property core-id: %u doesn't match set apic-id:" + " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id, +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 6d09dc4f229..ff471a5748b 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -8643,12 +8643,14 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_UINT32("apic-id", X86CPU, apic_id, 0), + DEFINE_PROP_INT32("thread-id", X86CPU, thread_id, 0), + DEFINE_PROP_INT32("core-id", X86CPU, core_id, 0), ++ DEFINE_PROP_INT32("module-id", X86CPU, module_id, 0), + DEFINE_PROP_INT32("die-id", X86CPU, die_id, 0), + DEFINE_PROP_INT32("socket-id", X86CPU, socket_id, 0), + #else + DEFINE_PROP_UINT32("apic-id", X86CPU, apic_id, UNASSIGNED_APIC_ID), + DEFINE_PROP_INT32("thread-id", X86CPU, thread_id, -1), + DEFINE_PROP_INT32("core-id", X86CPU, core_id, -1), ++ DEFINE_PROP_INT32("module-id", X86CPU, module_id, -1), + DEFINE_PROP_INT32("die-id", X86CPU, die_id, -1), + DEFINE_PROP_INT32("socket-id", X86CPU, socket_id, -1), + #endif +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index d42e846303c..409104495a9 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2139,6 +2139,7 @@ struct ArchCPU { + int32_t node_id; /* NUMA node this CPU belongs to */ + int32_t socket_id; + int32_t die_id; ++ int32_t module_id; + int32_t core_id; + int32_t thread_id; + +-- +2.47.3 + diff --git a/1198-tests-Add-test-case-of-APIC-ID-for-module-level-pars.patch b/1198-tests-Add-test-case-of-APIC-ID-for-module-level-pars.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb161f0e813494a6aaee43047701485a72149e75 --- /dev/null +++ b/1198-tests-Add-test-case-of-APIC-ID-for-module-level-pars.patch @@ -0,0 +1,79 @@ +From e70022053bf0ac2b769ca3c720ec51d0ba514e28 Mon Sep 17 00:00:00 2001 +From: Zhuocheng Ding +Date: Wed, 24 Apr 2024 23:49:25 +0800 +Subject: [PATCH 20/83] tests: Add test case of APIC ID for module level + parsing + +commit 321d2599ebf9d27fbc41c672858048087f6a052d upstream. + +After i386 supports module level, it's time to add the test for module +level's parsing. + +Intel-SIG: commit 321d2599ebf9 tests: Add test case of APIC ID for module level parsing. +CPU new topology backporting + +Signed-off-by: Zhuocheng Ding +Co-developed-by: Zhao Liu +Signed-off-by: Zhao Liu +Reviewed-by: Yanan Wang +Tested-by: Babu Moger +Tested-by: Yongwei Ma +Acked-by: Michael S. Tsirkin +Message-ID: <20240424154929.1487382-18-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + tests/unit/test-x86-topo.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/tests/unit/test-x86-topo.c b/tests/unit/test-x86-topo.c +index f21b8a5d95c..55b731ccae5 100644 +--- a/tests/unit/test-x86-topo.c ++++ b/tests/unit/test-x86-topo.c +@@ -37,6 +37,7 @@ static void test_topo_bits(void) + topo_info = (X86CPUTopoInfo) {1, 1, 1, 1}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 0); + g_assert_cmpuint(apicid_core_width(&topo_info), ==, 0); ++ g_assert_cmpuint(apicid_module_width(&topo_info), ==, 0); + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 0); + + topo_info = (X86CPUTopoInfo) {1, 1, 1, 1}; +@@ -74,13 +75,22 @@ static void test_topo_bits(void) + topo_info = (X86CPUTopoInfo) {1, 1, 33, 2}; + g_assert_cmpuint(apicid_core_width(&topo_info), ==, 6); + +- topo_info = (X86CPUTopoInfo) {1, 1, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {1, 6, 30, 2}; ++ g_assert_cmpuint(apicid_module_width(&topo_info), ==, 3); ++ topo_info = (X86CPUTopoInfo) {1, 7, 30, 2}; ++ g_assert_cmpuint(apicid_module_width(&topo_info), ==, 3); ++ topo_info = (X86CPUTopoInfo) {1, 8, 30, 2}; ++ g_assert_cmpuint(apicid_module_width(&topo_info), ==, 3); ++ topo_info = (X86CPUTopoInfo) {1, 9, 30, 2}; ++ g_assert_cmpuint(apicid_module_width(&topo_info), ==, 4); ++ ++ topo_info = (X86CPUTopoInfo) {1, 6, 30, 2}; + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 0); +- topo_info = (X86CPUTopoInfo) {2, 1, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {2, 6, 30, 2}; + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 1); +- topo_info = (X86CPUTopoInfo) {3, 1, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {3, 6, 30, 2}; + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 2); +- topo_info = (X86CPUTopoInfo) {4, 1, 30, 2}; ++ topo_info = (X86CPUTopoInfo) {4, 6, 30, 2}; + g_assert_cmpuint(apicid_die_width(&topo_info), ==, 2); + + /* build a weird topology and see if IDs are calculated correctly +@@ -91,6 +101,7 @@ static void test_topo_bits(void) + topo_info = (X86CPUTopoInfo) {1, 1, 6, 3}; + g_assert_cmpuint(apicid_smt_width(&topo_info), ==, 2); + g_assert_cmpuint(apicid_core_offset(&topo_info), ==, 2); ++ g_assert_cmpuint(apicid_module_offset(&topo_info), ==, 5); + g_assert_cmpuint(apicid_die_offset(&topo_info), ==, 5); + g_assert_cmpuint(apicid_pkg_offset(&topo_info), ==, 5); + +-- +2.47.3 + diff --git a/1199-hw-i386-pc-Support-smp.modules-for-x86-PC-machine.patch b/1199-hw-i386-pc-Support-smp.modules-for-x86-PC-machine.patch new file mode 100644 index 0000000000000000000000000000000000000000..d4f0598ac01566a1549b0407550bd052e44e7d53 --- /dev/null +++ b/1199-hw-i386-pc-Support-smp.modules-for-x86-PC-machine.patch @@ -0,0 +1,104 @@ +From 1c0a4f7cb6316d28e064b840cedc1eab3d74db0a Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:26 +0800 +Subject: [PATCH 21/83] hw/i386/pc: Support smp.modules for x86 PC machine + +commit 6807487474165ddffd1016af1bf167e5c15e71bf upstream. + +As module-level topology support is added to X86CPU, now we can enable +the support for the modules parameter on PC machines. With this support, +we can define a 5-level x86 CPU topology with "-smp": + +-smp cpus=*,maxcpus=*,sockets=*,dies=*,modules=*,cores=*,threads=*. + +So, add the 5-level topology example in description of "-smp". + +Additionally, add the missed drawers and books options in previous +example. + +Intel-SIG: commit 680748747416 hw/i386/pc: Support smp.modules for x86 PC machine. +CPU new topology backporting + +Tested-by: Yongwei Ma +Co-developed-by: Zhuocheng Ding +Signed-off-by: Zhuocheng Ding +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Reviewed-by: Babu Moger +Message-ID: <20240424154929.1487382-19-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/pc.c | 1 + + qemu-options.hx | 18 ++++++++++-------- + 2 files changed, 11 insertions(+), 8 deletions(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 6fffaf6832e..03fb5ce1494 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1976,6 +1976,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) + mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE; + mc->nvdimm_supported = true; + mc->smp_props.dies_supported = true; ++ mc->smp_props.modules_supported = true; + mc->default_ram_id = "pc.ram"; + pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64; + +diff --git a/qemu-options.hx b/qemu-options.hx +index 45700a42cae..1be7ee39a2a 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -273,7 +273,8 @@ ERST + + DEF("smp", HAS_ARG, QEMU_OPTION_smp, + "-smp [[cpus=]n][,maxcpus=maxcpus][,drawers=drawers][,books=books][,sockets=sockets]\n" +- " [,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n" ++ " [,dies=dies][,clusters=clusters][,modules=modules][,cores=cores]\n" ++ " [,threads=threads]\n" + " set the number of initial CPUs to 'n' [default=1]\n" + " maxcpus= maximum number of total CPUs, including\n" + " offline CPUs for hotplug, etc\n" +@@ -282,7 +283,8 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp, + " sockets= number of sockets in one book\n" + " dies= number of dies in one socket\n" + " clusters= number of clusters in one die\n" +- " cores= number of cores in one cluster\n" ++ " modules= number of modules in one cluster\n" ++ " cores= number of cores in one module\n" + " threads= number of threads in one core\n" + "Note: Different machines may have different subsets of the CPU topology\n" + " parameters supported, so the actual meaning of the supported parameters\n" +@@ -298,7 +300,7 @@ DEF("smp", HAS_ARG, QEMU_OPTION_smp, + " must be set as 1 in the purpose of correct parsing.\n", + QEMU_ARCH_ALL) + SRST +-``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]`` ++``-smp [[cpus=]n][,maxcpus=maxcpus][,drawers=drawers][,books=books][,sockets=sockets][,dies=dies][,clusters=clusters][,modules=modules][,cores=cores][,threads=threads]`` + Simulate a SMP system with '\ ``n``\ ' CPUs initially present on + the machine type board. On boards supporting CPU hotplug, the optional + '\ ``maxcpus``\ ' parameter can be set to enable further CPUs to be +@@ -337,14 +339,14 @@ SRST + -smp 8,sockets=2,cores=2,threads=2,maxcpus=8 + + The following sub-option defines a CPU topology hierarchy (2 sockets +- totally on the machine, 2 dies per socket, 2 cores per die, 2 threads +- per core) for PC machines which support sockets/dies/cores/threads. +- Some members of the option can be omitted but their values will be +- automatically computed: ++ totally on the machine, 2 dies per socket, 2 modules per die, 2 cores per ++ module, 2 threads per core) for PC machines which support sockets/dies ++ /modules/cores/threads. Some members of the option can be omitted but ++ their values will be automatically computed: + + :: + +- -smp 16,sockets=2,dies=2,cores=2,threads=2,maxcpus=16 ++ -smp 32,sockets=2,dies=2,modules=2,cores=2,threads=2,maxcpus=32 + + The following sub-option defines a CPU topology hierarchy (2 sockets + totally on the machine, 2 clusters per socket, 2 cores per cluster, +-- +2.47.3 + diff --git a/1200-i386-Add-cache-topology-info-in-CPUCacheInfo.patch b/1200-i386-Add-cache-topology-info-in-CPUCacheInfo.patch new file mode 100644 index 0000000000000000000000000000000000000000..22d89630d25b908d3bb36effc2e317dafd4f8ad6 --- /dev/null +++ b/1200-i386-Add-cache-topology-info-in-CPUCacheInfo.patch @@ -0,0 +1,363 @@ +From 7a995bfa65226065e564f417751a4cee4bd7d229 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:27 +0800 +Subject: [PATCH 22/83] i386: Add cache topology info in CPUCacheInfo + +commit 9fcba76ab9c264d06394696c304f2462d9296918 upstream. + +Currently, by default, the cache topology is encoded as: +1. i/d cache is shared in one core. +2. L2 cache is shared in one core. +3. L3 cache is shared in one die. + +This default general setting has caused a misunderstanding, that is, the +cache topology is completely equated with a specific cpu topology, such +as the connection between L2 cache and core level, and the connection +between L3 cache and die level. + +In fact, the settings of these topologies depend on the specific +platform and are not static. For example, on Alder Lake-P, every +four Atom cores share the same L2 cache. + +Thus, we should explicitly define the corresponding cache topology for +different cache models to increase scalability. + +Except legacy_l2_cache_cpuid2 (its default topo level is +CPU_TOPO_LEVEL_UNKNOW), explicitly set the corresponding topology level +for all other cache models. In order to be compatible with the existing +cache topology, set the CPU_TOPO_LEVEL_CORE level for the i/d cache, set +the CPU_TOPO_LEVEL_CORE level for L2 cache, and set the +CPU_TOPO_LEVEL_DIE level for L3 cache. + +The field for CPUID[4].EAX[bits 25:14] or CPUID[0x8000001D].EAX[bits +25:14] will be set based on CPUCacheInfo.share_level. + +Intel-SIG: commit 9fcba76ab9c2 i386: Add cache topology info in CPUCacheInfo. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Tested-by: Yongwei Ma +Acked-by: Michael S. Tsirkin +Message-ID: <20240424154929.1487382-20-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 36 ++++++++++++++++++++++++++++++++++++ + target/i386/cpu.h | 7 +++++++ + 2 files changed, 43 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ff471a5748b..65e31837725 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -555,6 +555,7 @@ static CPUCacheInfo legacy_l1d_cache = { + .sets = 64, + .partitions = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }; + + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ +@@ -569,6 +570,7 @@ static CPUCacheInfo legacy_l1d_cache_amd = { + .partitions = 1, + .lines_per_tag = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }; + + /* L1 instruction cache: */ +@@ -582,6 +584,7 @@ static CPUCacheInfo legacy_l1i_cache = { + .sets = 64, + .partitions = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }; + + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ +@@ -596,6 +599,7 @@ static CPUCacheInfo legacy_l1i_cache_amd = { + .partitions = 1, + .lines_per_tag = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }; + + /* Level 2 unified cache: */ +@@ -609,6 +613,7 @@ static CPUCacheInfo legacy_l2_cache = { + .sets = 4096, + .partitions = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }; + + /*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */ +@@ -618,6 +623,7 @@ static CPUCacheInfo legacy_l2_cache_cpuid2 = { + .size = 2 * MiB, + .line_size = 64, + .associativity = 8, ++ .share_level = CPU_TOPO_LEVEL_INVALID, + }; + + +@@ -631,6 +637,7 @@ static CPUCacheInfo legacy_l2_cache_amd = { + .associativity = 16, + .sets = 512, + .partitions = 1, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }; + + /* Level 3 unified cache: */ +@@ -646,6 +653,7 @@ static CPUCacheInfo legacy_l3_cache = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, ++ .share_level = CPU_TOPO_LEVEL_DIE, + }; + + /* TLB definitions: */ +@@ -2014,6 +2022,7 @@ static const CPUCaches epyc_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2026,6 +2035,7 @@ static const CPUCaches epyc_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2036,6 +2046,7 @@ static const CPUCaches epyc_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2049,6 +2060,7 @@ static const CPUCaches epyc_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, ++ .share_level = CPU_TOPO_LEVEL_DIE, + }, + }; + +@@ -2064,6 +2076,7 @@ static CPUCaches epyc_v4_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2076,6 +2089,7 @@ static CPUCaches epyc_v4_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2086,6 +2100,7 @@ static CPUCaches epyc_v4_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2099,6 +2114,7 @@ static CPUCaches epyc_v4_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = false, ++ .share_level = CPU_TOPO_LEVEL_DIE, + }, + }; + +@@ -2114,6 +2130,7 @@ static const CPUCaches epyc_rome_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2126,6 +2143,7 @@ static const CPUCaches epyc_rome_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2136,6 +2154,7 @@ static const CPUCaches epyc_rome_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2149,6 +2168,7 @@ static const CPUCaches epyc_rome_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, ++ .share_level = CPU_TOPO_LEVEL_DIE, + }, + }; + +@@ -2164,6 +2184,7 @@ static const CPUCaches epyc_rome_v3_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2176,6 +2197,7 @@ static const CPUCaches epyc_rome_v3_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2186,6 +2208,7 @@ static const CPUCaches epyc_rome_v3_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2199,6 +2222,7 @@ static const CPUCaches epyc_rome_v3_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = false, ++ .share_level = CPU_TOPO_LEVEL_DIE, + }, + }; + +@@ -2214,6 +2238,7 @@ static const CPUCaches epyc_milan_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2226,6 +2251,7 @@ static const CPUCaches epyc_milan_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2236,6 +2262,7 @@ static const CPUCaches epyc_milan_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2249,6 +2276,7 @@ static const CPUCaches epyc_milan_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, ++ .share_level = CPU_TOPO_LEVEL_DIE, + }, + }; + +@@ -2264,6 +2292,7 @@ static const CPUCaches epyc_milan_v2_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2276,6 +2305,7 @@ static const CPUCaches epyc_milan_v2_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2286,6 +2316,7 @@ static const CPUCaches epyc_milan_v2_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2299,6 +2330,7 @@ static const CPUCaches epyc_milan_v2_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = false, ++ .share_level = CPU_TOPO_LEVEL_DIE, + }, + }; + +@@ -2314,6 +2346,7 @@ static const CPUCaches epyc_genoa_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2326,6 +2359,7 @@ static const CPUCaches epyc_genoa_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2336,6 +2370,7 @@ static const CPUCaches epyc_genoa_cache_info = { + .partitions = 1, + .sets = 2048, + .lines_per_tag = 1, ++ .share_level = CPU_TOPO_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2349,6 +2384,7 @@ static const CPUCaches epyc_genoa_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = false, ++ .share_level = CPU_TOPO_LEVEL_DIE, + }, + }; + +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 409104495a9..82dc77e914a 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1654,6 +1654,13 @@ typedef struct CPUCacheInfo { + * address bits. CPUID[4].EDX[bit 2]. + */ + bool complex_indexing; ++ ++ /* ++ * Cache Topology. The level that cache is shared in. ++ * Used to encode CPUID[4].EAX[bits 25:14] or ++ * CPUID[0x8000001D].EAX[bits 25:14]. ++ */ ++ enum CPUTopoLevel share_level; + } CPUCacheInfo; + + +-- +2.47.3 + diff --git a/1201-i386-cpu-Use-CPUCacheInfo.share_level-to-encode-CPUI.patch b/1201-i386-cpu-Use-CPUCacheInfo.share_level-to-encode-CPUI.patch new file mode 100644 index 0000000000000000000000000000000000000000..b2112ec9486972f99542a3dac862a988d3ca4424 --- /dev/null +++ b/1201-i386-cpu-Use-CPUCacheInfo.share_level-to-encode-CPUI.patch @@ -0,0 +1,223 @@ +From 5a2ed33ea35a596615ebf1590ab663359c4a23a1 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:28 +0800 +Subject: [PATCH 23/83] i386/cpu: Use CPUCacheInfo.share_level to encode + CPUID[4] + +commit f602eb925ac5d51d09de6c4b32ba8a5142055492 upstream. + +CPUID[4].EAX[bits 25:14] is used to represent the cache topology for +Intel CPUs. + +After cache models have topology information, we can use +CPUCacheInfo.share_level to decide which topology level to be encoded +into CPUID[4].EAX[bits 25:14]. + +And since with the helper max_processor_ids_for_cache(), the filed +CPUID[4].EAX[bits 25:14] (original virable "num_apic_ids") is parsed +based on cpu topology levels, which are verified when parsing -smp, it's +no need to check this value by "assert(num_apic_ids > 0)" again, so +remove this assert(). + +Additionally, wrap the encoding of CPUID[4].EAX[bits 31:26] into a +helper to make the code cleaner. + +Intel-SIG: commit f602eb925ac5 i386/cpu: Use CPUCacheInfo.share_level to encode CPUID[4]. +CPU new topology backporting + +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Message-ID: <20240424154929.1487382-21-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 94 +++++++++++++++++++++++++---------------------- + target/i386/cpu.h | 5 +++ + 2 files changed, 56 insertions(+), 43 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 65e31837725..f13dc3db58f 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -239,22 +239,53 @@ static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache) + ((t) == UNIFIED_CACHE) ? CACHE_TYPE_UNIFIED : \ + 0 /* Invalid value */) + ++static uint32_t max_thread_ids_for_cache(X86CPUTopoInfo *topo_info, ++ enum CPUTopoLevel share_level) ++{ ++ uint32_t num_ids = 0; ++ ++ switch (share_level) { ++ case CPU_TOPO_LEVEL_CORE: ++ num_ids = 1 << apicid_core_offset(topo_info); ++ break; ++ case CPU_TOPO_LEVEL_DIE: ++ num_ids = 1 << apicid_die_offset(topo_info); ++ break; ++ case CPU_TOPO_LEVEL_PACKAGE: ++ num_ids = 1 << apicid_pkg_offset(topo_info); ++ break; ++ default: ++ /* ++ * Currently there is no use case for SMT and MODULE, so use ++ * assert directly to facilitate debugging. ++ */ ++ g_assert_not_reached(); ++ } ++ ++ return num_ids - 1; ++} ++ ++static uint32_t max_core_ids_in_package(X86CPUTopoInfo *topo_info) ++{ ++ uint32_t num_cores = 1 << (apicid_pkg_offset(topo_info) - ++ apicid_core_offset(topo_info)); ++ return num_cores - 1; ++} + + /* Encode cache info for CPUID[4] */ + static void encode_cache_cpuid4(CPUCacheInfo *cache, +- int num_apic_ids, int num_cores, ++ X86CPUTopoInfo *topo_info, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) + { + assert(cache->size == cache->line_size * cache->associativity * + cache->partitions * cache->sets); + +- assert(num_apic_ids > 0); + *eax = CACHE_TYPE(cache->type) | + CACHE_LEVEL(cache->level) | + (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0) | +- ((num_cores - 1) << 26) | +- ((num_apic_ids - 1) << 14); ++ (max_core_ids_in_package(topo_info) << 26) | ++ (max_thread_ids_for_cache(topo_info, cache->share_level) << 14); + + assert(cache->line_size > 0); + assert(cache->partitions > 0); +@@ -6851,18 +6882,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (cpuid2_cache_descriptor(env->cache_info_cpuid2.l1i_cache) << 8) | + (cpuid2_cache_descriptor(env->cache_info_cpuid2.l2_cache)); + break; +- case 4: { +- /* +- * CPUID.04H:EAX[bits 25:14]: Maximum number of addressable IDs for +- * logical processors sharing this cache. +- */ +- int addressable_threads_width; +- /* +- * CPUID.04H:EAX[bits 31:26]: Maximum number of addressable IDs for +- * processor cores in the physical package. +- */ +- int addressable_cores_width; +- ++ case 4: + /* cache info: needed for Core compatibility */ + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); +@@ -6874,59 +6894,48 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14); + + if (cores_per_pkg > 1) { +- addressable_cores_width = apicid_pkg_offset(&topo_info) - +- apicid_core_offset(&topo_info); +- + *eax &= ~0xFC000000; +- *eax |= ((1 << addressable_cores_width) - 1) << 26; ++ *eax |= max_core_ids_in_package(&topo_info) << 26; + } + if (host_vcpus_per_cache > threads_per_pkg) { +- /* Share the cache at package level. */ +- addressable_threads_width = apicid_pkg_offset(&topo_info); +- + *eax &= ~0x3FFC000; +- *eax |= ((1 << addressable_threads_width) - 1) << 14; ++ ++ /* Share the cache at package level. */ ++ *eax |= max_thread_ids_for_cache(&topo_info, ++ CPU_TOPO_LEVEL_PACKAGE) << 14; + } + } + } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { + *eax = *ebx = *ecx = *edx = 0; + } else { + *eax = 0; +- addressable_cores_width = apicid_pkg_offset(&topo_info) - +- apicid_core_offset(&topo_info); + + switch (count) { + case 0: /* L1 dcache info */ +- addressable_threads_width = cpu->l1_cache_per_core +- ? apicid_core_offset(&topo_info) +- : 0; + encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache, +- (1 << addressable_threads_width), +- (1 << addressable_cores_width), ++ &topo_info, + eax, ebx, ecx, edx); ++ if (!cpu->l1_cache_per_core) { ++ *eax &= ~MAKE_64BIT_MASK(14, 12); ++ } + break; + case 1: /* L1 icache info */ +- addressable_threads_width = cpu->l1_cache_per_core +- ? apicid_core_offset(&topo_info) +- : 0; + encode_cache_cpuid4(env->cache_info_cpuid4.l1i_cache, +- (1 << addressable_threads_width), +- (1 << addressable_cores_width), ++ &topo_info, + eax, ebx, ecx, edx); ++ if (!cpu->l1_cache_per_core) { ++ *eax &= ~MAKE_64BIT_MASK(14, 12); ++ } + break; + case 2: /* L2 cache info */ +- addressable_threads_width = apicid_core_offset(&topo_info); + encode_cache_cpuid4(env->cache_info_cpuid4.l2_cache, +- (1 << addressable_threads_width), +- (1 << addressable_cores_width), ++ &topo_info, + eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ + if (cpu->enable_l3_cache) { +- addressable_threads_width = apicid_die_offset(&topo_info); + encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache, +- (1 << addressable_threads_width), +- (1 << addressable_cores_width), ++ &topo_info, + eax, ebx, ecx, edx); + break; + } +@@ -6937,7 +6946,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + } + break; +- } + case 5: + /* MONITOR/MWAIT Leaf */ + *eax = cpu->mwait.eax; /* Smallest monitor-line size in bytes */ +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 82dc77e914a..1b52e151217 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2092,6 +2092,11 @@ struct ArchCPU { + */ + bool enable_l3_cache; + ++ /* Compatibility bits for old machine types. ++ * If true present L1 cache as per-thread, not per-core. ++ */ ++ bool l1_cache_per_core; ++ + /* Compatibility bits for old machine types. + * If true present the old cache topology information + */ +-- +2.47.3 + diff --git a/1202-i386-cpu-Use-CPUCacheInfo.share_level-to-encode-CPUI.patch b/1202-i386-cpu-Use-CPUCacheInfo.share_level-to-encode-CPUI.patch new file mode 100644 index 0000000000000000000000000000000000000000..f4e95afed4820a3d40ce22945199f1877347f97e --- /dev/null +++ b/1202-i386-cpu-Use-CPUCacheInfo.share_level-to-encode-CPUI.patch @@ -0,0 +1,62 @@ +From da1f2dc58e6a7ec9133fff09867371ca89b5625f Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Wed, 24 Apr 2024 23:49:29 +0800 +Subject: [PATCH 24/83] i386/cpu: Use CPUCacheInfo.share_level to encode + CPUID[0x8000001D].EAX[bits 25:14] + +commit 5eb608a13b2dfb772c831d02000a3514d1f137aa upstream. + +CPUID[0x8000001D].EAX[bits 25:14] NumSharingCache: number of logical +processors sharing cache. + +The number of logical processors sharing this cache is +NumSharingCache + 1. + +After cache models have topology information, we can use +CPUCacheInfo.share_level to decide which topology level to be encoded +into CPUID[0x8000001D].EAX[bits 25:14]. + +Intel-SIG: commit 5eb608a13b2d i386/cpu: Use CPUCacheInfo.share_level to encode CPUID[0x8000001D].EAX[bits 25:14]. +CPU new topology backporting + +Tested-by: Yongwei Ma +Signed-off-by: Zhao Liu +Tested-by: Babu Moger +Reviewed-by: Babu Moger +Message-ID: <20240424154929.1487382-22-zhao1.liu@intel.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index f13dc3db58f..51b992f605d 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -482,20 +482,12 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) + { +- uint32_t num_sharing_cache; + assert(cache->size == cache->line_size * cache->associativity * + cache->partitions * cache->sets); + + *eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) | + (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0); +- +- /* L3 is shared among multiple cores */ +- if (cache->level == 3) { +- num_sharing_cache = 1 << apicid_die_offset(topo_info); +- } else { +- num_sharing_cache = 1 << apicid_core_offset(topo_info); +- } +- *eax |= (num_sharing_cache - 1) << 14; ++ *eax |= max_thread_ids_for_cache(topo_info, cache->share_level) << 14; + + assert(cache->line_size > 0); + assert(cache->partitions > 0); +-- +2.47.3 + diff --git a/1203-i386-Add-support-for-SUCCOR-feature.patch b/1203-i386-Add-support-for-SUCCOR-feature.patch new file mode 100644 index 0000000000000000000000000000000000000000..327a7787a638cf8e82ea010da0df341ec34ada23 --- /dev/null +++ b/1203-i386-Add-support-for-SUCCOR-feature.patch @@ -0,0 +1,106 @@ +From 6944fc3743f8dd4c442564e2eac96afdf25c3267 Mon Sep 17 00:00:00 2001 +From: John Allen +Date: Mon, 3 Jun 2024 19:36:21 +0000 +Subject: [PATCH 25/83] i386: Add support for SUCCOR feature + +commit 2ba8b7ee63589d4063c3b8dff3b70dbf9e224fc6 upstream. + +Add cpuid bit definition for the SUCCOR feature. This cpuid bit is required to +be exposed to guests to allow them to handle machine check exceptions on AMD +hosts. + +---- +v2: + - Add "succor" feature word. + - Add case to kvm_arch_get_supported_cpuid for the SUCCOR feature. + +Reported-by: William Roche +Intel-SIG: commit 2ba8b7ee6358 i386: Add support for SUCCOR feature. +CPU new topology backporting + +Reviewed-by: Joao Martins +Signed-off-by: John Allen +Message-ID: <20240603193622.47156-3-john.allen@amd.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 18 +++++++++++++++++- + target/i386/cpu.h | 4 ++++ + target/i386/kvm/kvm.c | 2 ++ + 3 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 51b992f605d..d8df876d405 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -1197,6 +1197,22 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .tcg_features = TCG_APM_FEATURES, + .unmigratable_flags = CPUID_APM_INVTSC, + }, ++ [FEAT_8000_0007_EBX] = { ++ .type = CPUID_FEATURE_WORD, ++ .feat_names = { ++ NULL, "succor", NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ }, ++ .cpuid = { .eax = 0x80000007, .reg = R_EBX, }, ++ .tcg_features = 0, ++ .unmigratable_flags = 0, ++ }, + [FEAT_8000_0008_EBX] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { +@@ -7339,7 +7355,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 0x80000007: + *eax = 0; +- *ebx = 0; ++ *ebx = env->features[FEAT_8000_0007_EBX]; + *ecx = 0; + *edx = env->features[FEAT_8000_0007_EDX]; + break; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 1b52e151217..8dbe87cac1d 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -620,6 +620,7 @@ typedef enum FeatureWord { + FEAT_7_1_EAX, /* CPUID[EAX=7,ECX=1].EAX */ + FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ + FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ ++ FEAT_8000_0007_EBX, /* CPUID[8000_0007].EBX */ + FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */ + FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */ + FEAT_8000_0021_EAX, /* CPUID[8000_0021].EAX */ +@@ -1012,6 +1013,9 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); + CPUID_24_0_EBX_AVX10_256 | \ + CPUID_24_0_EBX_AVX10_512) + ++/* RAS Features */ ++#define CPUID_8000_0007_EBX_SUCCOR (1U << 1) ++ + /* CLZERO instruction */ + #define CPUID_8000_0008_EBX_CLZERO (1U << 0) + /* Always save/restore FP error pointers */ +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index d119efe8643..78fecd564fa 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -484,6 +484,8 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + */ + cpuid_1_edx = kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX); + ret |= cpuid_1_edx & CPUID_EXT2_AMD_ALIASES; ++ } else if (function == 0x80000007 && reg == R_EBX) { ++ ret |= CPUID_8000_0007_EBX_SUCCOR; + } else if (function == KVM_CPUID_FEATURES && reg == R_EAX) { + /* kvm_pv_unhalt is reported by GET_SUPPORTED_CPUID, but it can't + * be enabled without the in-kernel irqchip +-- +2.47.3 + diff --git a/1204-i386-cpu-fixup-number-of-addressable-IDs-for-process.patch b/1204-i386-cpu-fixup-number-of-addressable-IDs-for-process.patch new file mode 100644 index 0000000000000000000000000000000000000000..569fdb9561e0024abeed685165bc62c4bd8d1491 --- /dev/null +++ b/1204-i386-cpu-fixup-number-of-addressable-IDs-for-process.patch @@ -0,0 +1,59 @@ +From 445e0250ba06441ed1f8e2cc0e4b5952db1e0341 Mon Sep 17 00:00:00 2001 +From: Chuang Xu +Date: Tue, 11 Jun 2024 11:23:14 +0800 +Subject: [PATCH 26/83] i386/cpu: fixup number of addressable IDs for processor + cores in the physical package + +commit 903916f0a017fe4b7789f1c6c6982333a5a71876 upstream. + +When QEMU is started with: +-cpu host,host-cache-info=on,l3-cache=off \ +-smp 2,sockets=1,dies=1,cores=1,threads=2 +Guest can't acquire maximum number of addressable IDs for processor cores in +the physical package from CPUID[04H]. + +When creating a CPU topology of 1 core per package, host-cache-info only +uses the Host's addressable core IDs field (CPUID.04H.EAX[bits 31-26]), +resulting in a conflict (on the multicore Host) between the Guest core +topology information in this field and the Guest's actual cores number. + +Fix it by removing the unnecessary condition to cover 1 core per package +case. This is safe because cores_per_pkg will not be 0 and will be at +least 1. + +Fixes: d7caf13b5fcf ("x86: cpu: fixup number of addressable IDs for logical processors sharing cache") +Intel-SIG: commit 903916f0a017 i386/cpu: fixup number of addressable IDs for processor cores in the physical package. +CPU new topology backporting + +Signed-off-by: Guixiong Wei +Signed-off-by: Yipeng Yin +Signed-off-by: Chuang Xu +Reviewed-by: Zhao Liu +Message-ID: <20240611032314.64076-1-xuchuangxclwt@bytedance.com> +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index d8df876d405..5ec9952881b 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6901,10 +6901,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (*eax & 31) { + int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14); + +- if (cores_per_pkg > 1) { +- *eax &= ~0xFC000000; +- *eax |= max_core_ids_in_package(&topo_info) << 26; +- } ++ *eax &= ~0xFC000000; ++ *eax |= max_core_ids_in_package(&topo_info) << 26; + if (host_vcpus_per_cache > threads_per_pkg) { + *eax &= ~0x3FFC000; + +-- +2.47.3 + diff --git a/1205-i386-cpu-Don-t-enumerate-the-invalid-CPU-topology-le.patch b/1205-i386-cpu-Don-t-enumerate-the-invalid-CPU-topology-le.patch new file mode 100644 index 0000000000000000000000000000000000000000..2332f51b66fbc116779cf0c0aba5141c73f9ba78 --- /dev/null +++ b/1205-i386-cpu-Don-t-enumerate-the-invalid-CPU-topology-le.patch @@ -0,0 +1,100 @@ +From b644363dcc0f275f7c8b8248aa9213e15b559475 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 1 Nov 2024 16:33:23 +0800 +Subject: [PATCH 27/83] i386/cpu: Don't enumerate the "invalid" CPU topology + level +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 34230ce5a97b898a53032b958841e74fde0bdac1 upstream. + +In the follow-up change, the CPU topology enumeration will be moved to +QAPI. And considerring "invalid" should not be exposed to QAPI as an +unsettable item, so, as a preparation for future changes, remove +"invalid" level from the current CPU topology enumeration structure +and define it by a macro instead. + +Due to the removal of the enumeration of "invalid", bit 0 of +CPUX86State.avail_cpu_topo bitmap will no longer correspond to "invalid" +level, but will start at the SMT level. Therefore, to honor this change, +update the encoding rule for CPUID[0x1F]. + +Intel-SIG: commit 34230ce5a97b i386/cpu: Don't enumerate the "invalid" CPU topology level. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Jonathan Cameron +Message-ID: <20241101083331.340178-2-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + include/hw/i386/topology.h | 3 ++- + target/i386/cpu.c | 13 ++++++++----- + 2 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index dff49fce115..48b43edc5a9 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -62,6 +62,8 @@ typedef struct X86CPUTopoInfo { + unsigned threads_per_core; + } X86CPUTopoInfo; + ++#define CPU_TOPO_LEVEL_INVALID CPU_TOPO_LEVEL_MAX ++ + /* + * CPUTopoLevel is the general i386 topology hierarchical representation, + * ordered by increasing hierarchical relationship. +@@ -69,7 +71,6 @@ typedef struct X86CPUTopoInfo { + * or AMD (CPUID[0x80000026]). + */ + enum CPUTopoLevel { +- CPU_TOPO_LEVEL_INVALID, + CPU_TOPO_LEVEL_SMT, + CPU_TOPO_LEVEL_CORE, + CPU_TOPO_LEVEL_MODULE, +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 5ec9952881b..9da84f5c0ec 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -372,20 +372,21 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count, + uint32_t *ecx, uint32_t *edx) + { + X86CPU *cpu = env_archcpu(env); +- unsigned long level, next_level; ++ unsigned long level, base_level, next_level; + uint32_t num_threads_next_level, offset_next_level; + +- assert(count + 1 < CPU_TOPO_LEVEL_MAX); ++ assert(count <= CPU_TOPO_LEVEL_PACKAGE); + + /* + * Find the No.(count + 1) topology level in avail_cpu_topo bitmap. +- * The search starts from bit 1 (CPU_TOPO_LEVEL_INVALID + 1). ++ * The search starts from bit 0 (CPU_TOPO_LEVEL_SMT). + */ +- level = CPU_TOPO_LEVEL_INVALID; ++ level = CPU_TOPO_LEVEL_SMT; ++ base_level = level; + for (int i = 0; i <= count; i++) { + level = find_next_bit(env->avail_cpu_topo, + CPU_TOPO_LEVEL_PACKAGE, +- level + 1); ++ base_level); + + /* + * CPUID[0x1f] doesn't explicitly encode the package level, +@@ -396,6 +397,8 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count, + level = CPU_TOPO_LEVEL_INVALID; + break; + } ++ /* Search the next level. */ ++ base_level = level + 1; + } + + if (level == CPU_TOPO_LEVEL_INVALID) { +-- +2.47.3 + diff --git a/1206-hw-core-Make-CPU-topology-enumeration-arch-agnostic.patch b/1206-hw-core-Make-CPU-topology-enumeration-arch-agnostic.patch new file mode 100644 index 0000000000000000000000000000000000000000..aac365001ecc4e6b3f3a857c0972b52d9a7e8345 --- /dev/null +++ b/1206-hw-core-Make-CPU-topology-enumeration-arch-agnostic.patch @@ -0,0 +1,696 @@ +From c135a2b164dc0beedd5b01a723bc36dfb15764f0 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 1 Nov 2024 16:33:24 +0800 +Subject: [PATCH 28/83] hw/core: Make CPU topology enumeration arch-agnostic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit e823ebe77d8f38b181a3c277d5dd9399748bf566 upstream. + +Cache topology needs to be defined based on CPU topology levels. Thus, +define CPU topology enumeration in qapi/machine.json to make it generic +for all architectures. + +To match the general topology naming style, rename CPU_TOPO_LEVEL_* to +CPU_TOPOLOGY_LEVEL_*, and rename SMT and package levels to thread and +socket. + +Also, enumerate additional topology levels for non-i386 arches, and add +a CPU_TOPOLOGY_LEVEL_DEFAULT to help future smp-cache object to work +with compatibility requirement of arch-specific cache topology models. + +Intel-SIG: commit e823ebe77d8f hw/core: Make CPU topology enumeration arch-agnostic. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Tested-by: Yongwei Ma +Reviewed-by: Jonathan Cameron +Acked-by: Philippe Mathieu-Daudé +Message-ID: <20241101083331.340178-3-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86-common.c | 4 +- + include/hw/i386/topology.h | 23 ++---- + qapi/machine-common.json | 44 +++++++++++- + target/i386/cpu.c | 144 ++++++++++++++++++------------------- + target/i386/cpu.h | 4 +- + 5 files changed, 123 insertions(+), 96 deletions(-) + +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +index 9af5a98c3d0..e6b34269c0f 100644 +--- a/hw/i386/x86-common.c ++++ b/hw/i386/x86-common.c +@@ -269,12 +269,12 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + + if (ms->smp.modules > 1) { + env->nr_modules = ms->smp.modules; +- set_bit(CPU_TOPO_LEVEL_MODULE, env->avail_cpu_topo); ++ set_bit(CPU_TOPOLOGY_LEVEL_MODULE, env->avail_cpu_topo); + } + + if (ms->smp.dies > 1) { + env->nr_dies = ms->smp.dies; +- set_bit(CPU_TOPO_LEVEL_DIE, env->avail_cpu_topo); ++ set_bit(CPU_TOPOLOGY_LEVEL_DIE, env->avail_cpu_topo); + } + + /* +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index 48b43edc5a9..b2c8bf2de15 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -39,7 +39,7 @@ + * CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width(). + */ + +- ++#include "qapi/qapi-types-machine-common.h" + #include "qemu/bitops.h" + + /* +@@ -62,22 +62,7 @@ typedef struct X86CPUTopoInfo { + unsigned threads_per_core; + } X86CPUTopoInfo; + +-#define CPU_TOPO_LEVEL_INVALID CPU_TOPO_LEVEL_MAX +- +-/* +- * CPUTopoLevel is the general i386 topology hierarchical representation, +- * ordered by increasing hierarchical relationship. +- * Its enumeration value is not bound to the type value of Intel (CPUID[0x1F]) +- * or AMD (CPUID[0x80000026]). +- */ +-enum CPUTopoLevel { +- CPU_TOPO_LEVEL_SMT, +- CPU_TOPO_LEVEL_CORE, +- CPU_TOPO_LEVEL_MODULE, +- CPU_TOPO_LEVEL_DIE, +- CPU_TOPO_LEVEL_PACKAGE, +- CPU_TOPO_LEVEL_MAX, +-}; ++#define CPU_TOPOLOGY_LEVEL_INVALID CPU_TOPOLOGY_LEVEL__MAX + + /* Return the bit width needed for 'count' IDs */ + static unsigned apicid_bitwidth_for_count(unsigned count) +@@ -213,8 +198,8 @@ static inline apic_id_t x86_apicid_from_cpu_idx(X86CPUTopoInfo *topo_info, + */ + static inline bool x86_has_extended_topo(unsigned long *topo_bitmap) + { +- return test_bit(CPU_TOPO_LEVEL_MODULE, topo_bitmap) || +- test_bit(CPU_TOPO_LEVEL_DIE, topo_bitmap); ++ return test_bit(CPU_TOPOLOGY_LEVEL_MODULE, topo_bitmap) || ++ test_bit(CPU_TOPOLOGY_LEVEL_DIE, topo_bitmap); + } + + #endif /* HW_I386_TOPOLOGY_H */ +diff --git a/qapi/machine-common.json b/qapi/machine-common.json +index fa6bd71d128..563360052eb 100644 +--- a/qapi/machine-common.json ++++ b/qapi/machine-common.json +@@ -5,7 +5,7 @@ + # See the COPYING file in the top-level directory. + + ## +-# = Machines S390 data types ++# = Common machine types + ## + + ## +@@ -19,3 +19,45 @@ + { 'enum': 'CpuS390Entitlement', + 'prefix': 'S390_CPU_ENTITLEMENT', + 'data': [ 'auto', 'low', 'medium', 'high' ] } ++ ++## ++# @CpuTopologyLevel: ++# ++# An enumeration of CPU topology levels. ++# ++# @thread: thread level, which would also be called SMT level or ++# logical processor level. The @threads option in ++# SMPConfiguration is used to configure the topology of this ++# level. ++# ++# @core: core level. The @cores option in SMPConfiguration is used ++# to configure the topology of this level. ++# ++# @module: module level. The @modules option in SMPConfiguration is ++# used to configure the topology of this level. ++# ++# @cluster: cluster level. The @clusters option in SMPConfiguration ++# is used to configure the topology of this level. ++# ++# @die: die level. The @dies option in SMPConfiguration is used to ++# configure the topology of this level. ++# ++# @socket: socket level, which would also be called package level. ++# The @sockets option in SMPConfiguration is used to configure ++# the topology of this level. ++# ++# @book: book level. The @books option in SMPConfiguration is used ++# to configure the topology of this level. ++# ++# @drawer: drawer level. The @drawers option in SMPConfiguration is ++# used to configure the topology of this level. ++# ++# @default: default level. Some architectures will have default ++# topology settings (e.g., cache topology), and this special ++# level means following the architecture-specific settings. ++# ++# Since: 9.2 ++## ++{ 'enum': 'CpuTopologyLevel', ++ 'data': [ 'thread', 'core', 'module', 'cluster', 'die', ++ 'socket', 'book', 'drawer', 'default' ] } +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 9da84f5c0ec..3259448a7cf 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -240,23 +240,23 @@ static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache) + 0 /* Invalid value */) + + static uint32_t max_thread_ids_for_cache(X86CPUTopoInfo *topo_info, +- enum CPUTopoLevel share_level) ++ enum CpuTopologyLevel share_level) + { + uint32_t num_ids = 0; + + switch (share_level) { +- case CPU_TOPO_LEVEL_CORE: ++ case CPU_TOPOLOGY_LEVEL_CORE: + num_ids = 1 << apicid_core_offset(topo_info); + break; +- case CPU_TOPO_LEVEL_DIE: ++ case CPU_TOPOLOGY_LEVEL_DIE: + num_ids = 1 << apicid_die_offset(topo_info); + break; +- case CPU_TOPO_LEVEL_PACKAGE: ++ case CPU_TOPOLOGY_LEVEL_SOCKET: + num_ids = 1 << apicid_pkg_offset(topo_info); + break; + default: + /* +- * Currently there is no use case for SMT and MODULE, so use ++ * Currently there is no use case for THREAD and MODULE, so use + * assert directly to facilitate debugging. + */ + g_assert_not_reached(); +@@ -305,19 +305,19 @@ static void encode_cache_cpuid4(CPUCacheInfo *cache, + } + + static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info, +- enum CPUTopoLevel topo_level) ++ enum CpuTopologyLevel topo_level) + { + switch (topo_level) { +- case CPU_TOPO_LEVEL_SMT: ++ case CPU_TOPOLOGY_LEVEL_THREAD: + return 1; +- case CPU_TOPO_LEVEL_CORE: ++ case CPU_TOPOLOGY_LEVEL_CORE: + return topo_info->threads_per_core; +- case CPU_TOPO_LEVEL_MODULE: ++ case CPU_TOPOLOGY_LEVEL_MODULE: + return topo_info->threads_per_core * topo_info->cores_per_module; +- case CPU_TOPO_LEVEL_DIE: ++ case CPU_TOPOLOGY_LEVEL_DIE: + return topo_info->threads_per_core * topo_info->cores_per_module * + topo_info->modules_per_die; +- case CPU_TOPO_LEVEL_PACKAGE: ++ case CPU_TOPOLOGY_LEVEL_SOCKET: + return topo_info->threads_per_core * topo_info->cores_per_module * + topo_info->modules_per_die * topo_info->dies_per_pkg; + default: +@@ -327,18 +327,18 @@ static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info, + } + + static uint32_t apicid_offset_by_topo_level(X86CPUTopoInfo *topo_info, +- enum CPUTopoLevel topo_level) ++ enum CpuTopologyLevel topo_level) + { + switch (topo_level) { +- case CPU_TOPO_LEVEL_SMT: ++ case CPU_TOPOLOGY_LEVEL_THREAD: + return 0; +- case CPU_TOPO_LEVEL_CORE: ++ case CPU_TOPOLOGY_LEVEL_CORE: + return apicid_core_offset(topo_info); +- case CPU_TOPO_LEVEL_MODULE: ++ case CPU_TOPOLOGY_LEVEL_MODULE: + return apicid_module_offset(topo_info); +- case CPU_TOPO_LEVEL_DIE: ++ case CPU_TOPOLOGY_LEVEL_DIE: + return apicid_die_offset(topo_info); +- case CPU_TOPO_LEVEL_PACKAGE: ++ case CPU_TOPOLOGY_LEVEL_SOCKET: + return apicid_pkg_offset(topo_info); + default: + g_assert_not_reached(); +@@ -346,18 +346,18 @@ static uint32_t apicid_offset_by_topo_level(X86CPUTopoInfo *topo_info, + return 0; + } + +-static uint32_t cpuid1f_topo_type(enum CPUTopoLevel topo_level) ++static uint32_t cpuid1f_topo_type(enum CpuTopologyLevel topo_level) + { + switch (topo_level) { +- case CPU_TOPO_LEVEL_INVALID: ++ case CPU_TOPOLOGY_LEVEL_INVALID: + return CPUID_1F_ECX_TOPO_LEVEL_INVALID; +- case CPU_TOPO_LEVEL_SMT: ++ case CPU_TOPOLOGY_LEVEL_THREAD: + return CPUID_1F_ECX_TOPO_LEVEL_SMT; +- case CPU_TOPO_LEVEL_CORE: ++ case CPU_TOPOLOGY_LEVEL_CORE: + return CPUID_1F_ECX_TOPO_LEVEL_CORE; +- case CPU_TOPO_LEVEL_MODULE: ++ case CPU_TOPOLOGY_LEVEL_MODULE: + return CPUID_1F_ECX_TOPO_LEVEL_MODULE; +- case CPU_TOPO_LEVEL_DIE: ++ case CPU_TOPOLOGY_LEVEL_DIE: + return CPUID_1F_ECX_TOPO_LEVEL_DIE; + default: + /* Other types are not supported in QEMU. */ +@@ -375,17 +375,17 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count, + unsigned long level, base_level, next_level; + uint32_t num_threads_next_level, offset_next_level; + +- assert(count <= CPU_TOPO_LEVEL_PACKAGE); ++ assert(count <= CPU_TOPOLOGY_LEVEL_SOCKET); + + /* + * Find the No.(count + 1) topology level in avail_cpu_topo bitmap. +- * The search starts from bit 0 (CPU_TOPO_LEVEL_SMT). ++ * The search starts from bit 0 (CPU_TOPOLOGY_LEVEL_THREAD). + */ +- level = CPU_TOPO_LEVEL_SMT; ++ level = CPU_TOPOLOGY_LEVEL_THREAD; + base_level = level; + for (int i = 0; i <= count; i++) { + level = find_next_bit(env->avail_cpu_topo, +- CPU_TOPO_LEVEL_PACKAGE, ++ CPU_TOPOLOGY_LEVEL_SOCKET, + base_level); + + /* +@@ -393,20 +393,20 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count, + * and it just encodes the invalid level (all fields are 0) + * into the last subleaf of 0x1f. + */ +- if (level == CPU_TOPO_LEVEL_PACKAGE) { +- level = CPU_TOPO_LEVEL_INVALID; ++ if (level == CPU_TOPOLOGY_LEVEL_SOCKET) { ++ level = CPU_TOPOLOGY_LEVEL_INVALID; + break; + } + /* Search the next level. */ + base_level = level + 1; + } + +- if (level == CPU_TOPO_LEVEL_INVALID) { ++ if (level == CPU_TOPOLOGY_LEVEL_INVALID) { + num_threads_next_level = 0; + offset_next_level = 0; + } else { + next_level = find_next_bit(env->avail_cpu_topo, +- CPU_TOPO_LEVEL_PACKAGE, ++ CPU_TOPOLOGY_LEVEL_SOCKET, + level + 1); + num_threads_next_level = num_threads_by_topo_level(topo_info, + next_level); +@@ -581,7 +581,7 @@ static CPUCacheInfo legacy_l1d_cache = { + .sets = 64, + .partitions = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ +@@ -596,7 +596,7 @@ static CPUCacheInfo legacy_l1d_cache_amd = { + .partitions = 1, + .lines_per_tag = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + + /* L1 instruction cache: */ +@@ -610,7 +610,7 @@ static CPUCacheInfo legacy_l1i_cache = { + .sets = 64, + .partitions = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ +@@ -625,7 +625,7 @@ static CPUCacheInfo legacy_l1i_cache_amd = { + .partitions = 1, + .lines_per_tag = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + + /* Level 2 unified cache: */ +@@ -639,7 +639,7 @@ static CPUCacheInfo legacy_l2_cache = { + .sets = 4096, + .partitions = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + + /*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */ +@@ -649,7 +649,7 @@ static CPUCacheInfo legacy_l2_cache_cpuid2 = { + .size = 2 * MiB, + .line_size = 64, + .associativity = 8, +- .share_level = CPU_TOPO_LEVEL_INVALID, ++ .share_level = CPU_TOPOLOGY_LEVEL_INVALID, + }; + + +@@ -663,7 +663,7 @@ static CPUCacheInfo legacy_l2_cache_amd = { + .associativity = 16, + .sets = 512, + .partitions = 1, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + + /* Level 3 unified cache: */ +@@ -679,7 +679,7 @@ static CPUCacheInfo legacy_l3_cache = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, +- .share_level = CPU_TOPO_LEVEL_DIE, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }; + + /* TLB definitions: */ +@@ -2064,7 +2064,7 @@ static const CPUCaches epyc_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2077,7 +2077,7 @@ static const CPUCaches epyc_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2088,7 +2088,7 @@ static const CPUCaches epyc_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2102,7 +2102,7 @@ static const CPUCaches epyc_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, +- .share_level = CPU_TOPO_LEVEL_DIE, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, + }; + +@@ -2118,7 +2118,7 @@ static CPUCaches epyc_v4_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2131,7 +2131,7 @@ static CPUCaches epyc_v4_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2142,7 +2142,7 @@ static CPUCaches epyc_v4_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2156,7 +2156,7 @@ static CPUCaches epyc_v4_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = false, +- .share_level = CPU_TOPO_LEVEL_DIE, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, + }; + +@@ -2172,7 +2172,7 @@ static const CPUCaches epyc_rome_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2185,7 +2185,7 @@ static const CPUCaches epyc_rome_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2196,7 +2196,7 @@ static const CPUCaches epyc_rome_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2210,7 +2210,7 @@ static const CPUCaches epyc_rome_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, +- .share_level = CPU_TOPO_LEVEL_DIE, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, + }; + +@@ -2226,7 +2226,7 @@ static const CPUCaches epyc_rome_v3_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2239,7 +2239,7 @@ static const CPUCaches epyc_rome_v3_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2250,7 +2250,7 @@ static const CPUCaches epyc_rome_v3_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2264,7 +2264,7 @@ static const CPUCaches epyc_rome_v3_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = false, +- .share_level = CPU_TOPO_LEVEL_DIE, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, + }; + +@@ -2280,7 +2280,7 @@ static const CPUCaches epyc_milan_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2293,7 +2293,7 @@ static const CPUCaches epyc_milan_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2304,7 +2304,7 @@ static const CPUCaches epyc_milan_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2318,7 +2318,7 @@ static const CPUCaches epyc_milan_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, +- .share_level = CPU_TOPO_LEVEL_DIE, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, + }; + +@@ -2334,7 +2334,7 @@ static const CPUCaches epyc_milan_v2_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2347,7 +2347,7 @@ static const CPUCaches epyc_milan_v2_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2358,7 +2358,7 @@ static const CPUCaches epyc_milan_v2_cache_info = { + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2372,7 +2372,7 @@ static const CPUCaches epyc_milan_v2_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = false, +- .share_level = CPU_TOPO_LEVEL_DIE, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, + }; + +@@ -2388,7 +2388,7 @@ static const CPUCaches epyc_genoa_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, +@@ -2401,7 +2401,7 @@ static const CPUCaches epyc_genoa_cache_info = { + .lines_per_tag = 1, + .self_init = 1, + .no_invd_sharing = true, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2412,7 +2412,7 @@ static const CPUCaches epyc_genoa_cache_info = { + .partitions = 1, + .sets = 2048, + .lines_per_tag = 1, +- .share_level = CPU_TOPO_LEVEL_CORE, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, +@@ -2426,7 +2426,7 @@ static const CPUCaches epyc_genoa_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = false, +- .share_level = CPU_TOPO_LEVEL_DIE, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, + }; + +@@ -6911,7 +6911,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + + /* Share the cache at package level. */ + *eax |= max_thread_ids_for_cache(&topo_info, +- CPU_TOPO_LEVEL_PACKAGE) << 14; ++ CPU_TOPOLOGY_LEVEL_SOCKET) << 14; + } + } + } else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) { +@@ -8489,10 +8489,10 @@ static void x86_cpu_init_default_topo(X86CPU *cpu) + env->nr_modules = 1; + env->nr_dies = 1; + +- /* SMT, core and package levels are set by default. */ +- set_bit(CPU_TOPO_LEVEL_SMT, env->avail_cpu_topo); +- set_bit(CPU_TOPO_LEVEL_CORE, env->avail_cpu_topo); +- set_bit(CPU_TOPO_LEVEL_PACKAGE, env->avail_cpu_topo); ++ /* thread, core and socket levels are set by default. */ ++ set_bit(CPU_TOPOLOGY_LEVEL_THREAD, env->avail_cpu_topo); ++ set_bit(CPU_TOPOLOGY_LEVEL_CORE, env->avail_cpu_topo); ++ set_bit(CPU_TOPOLOGY_LEVEL_SOCKET, env->avail_cpu_topo); + } + + static void x86_cpu_initfn(Object *obj) +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 8dbe87cac1d..888dfb3ae6b 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1664,7 +1664,7 @@ typedef struct CPUCacheInfo { + * Used to encode CPUID[4].EAX[bits 25:14] or + * CPUID[0x8000001D].EAX[bits 25:14]. + */ +- enum CPUTopoLevel share_level; ++ CpuTopologyLevel share_level; + } CPUCacheInfo; + + +@@ -1995,7 +1995,7 @@ typedef struct CPUArchState { + unsigned nr_modules; + + /* Bitmap of available CPU topology levels for this CPU. */ +- DECLARE_BITMAP(avail_cpu_topo, CPU_TOPO_LEVEL_MAX); ++ DECLARE_BITMAP(avail_cpu_topo, CPU_TOPOLOGY_LEVEL__MAX); + } CPUX86State; + + struct kvm_msrs; +-- +2.47.3 + diff --git a/1207-qapi-qom-Define-cache-enumeration-and-properties-for.patch b/1207-qapi-qom-Define-cache-enumeration-and-properties-for.patch new file mode 100644 index 0000000000000000000000000000000000000000..07511e4d5fe8393d31b2c91fce9bed6812ed01af --- /dev/null +++ b/1207-qapi-qom-Define-cache-enumeration-and-properties-for.patch @@ -0,0 +1,300 @@ +From 8d412dd73ec144478384c92e736230ada7ef2d63 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 1 Nov 2024 16:33:25 +0800 +Subject: [PATCH 29/83] qapi/qom: Define cache enumeration and properties for + machine +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 4e88e7e3403df23a0fd7a95daad1f00da80bcf81 upstream. + +The x86 and ARM need to allow user to configure cache properties +(current only topology): + * For x86, the default cache topology model (of max/host CPU) does not + always match the Host's real physical cache topology. Performance can + increase when the configured virtual topology is closer to the + physical topology than a default topology would be. + * For ARM, QEMU can't get the cache topology information from the CPU + registers, then user configuration is necessary. Additionally, the + cache information is also needed for MPAM emulation (for TCG) to + build the right PPTT. + +Define smp-cache related enumeration and properties in QAPI, so that +user could configure cache properties for SMP system through -machine in +the subsequent patch. + +Cache enumeration (CacheLevelAndType) is implemented as the combination +of cache level (level 1/2/3) and cache type (data/instruction/unified). + +Currently, separated L1 cache (L1 data cache and L1 instruction cache) +with unified higher-level cache (e.g., unified L2 and L3 caches), is the +most common cache architectures. + +Therefore, enumerate the L1 D-cache, L1 I-cache, L2 cache and L3 cache +with smp-cache object to add the basic cache topology support. Other +kinds of caches (e.g., L1 unified or L2/L3 separated caches) can be +added directly into CacheLevelAndType if necessary. + +Cache properties (SmpCacheProperties) currently only contains cache +topology information, and other cache properties can be added in it +if necessary. + +Note, define cache topology based on CPU topology level with two +reasons: + + 1. In practice, a cache will always be bound to the CPU container + (either private in the CPU container or shared among multiple + containers), and CPU container is often expressed in terms of CPU + topology level. + 2. The x86's cache-related CPUIDs encode cache topology based on APIC + ID's CPU topology layout. And the ACPI PPTT table that ARM/RISCV + relies on also requires CPU containers to help indicate the private + shared hierarchy of the cache. Therefore, for SMP systems, it is + natural to use the CPU topology hierarchy directly in QEMU to define + the cache topology. + +With smp-cache QAPI support, add smp cache topology for machine by +parsing the smp-cache object list. + +Also add the helper to access/update cache topology level of machine. + +Intel-SIG: commit 4e88e7e3403d qapi/qom: Define cache enumeration and properties for machine. +CPU new topology backporting + +Suggested-by: Daniel P. Berrange +Signed-off-by: Zhao Liu +Tested-by: Yongwei Ma +Reviewed-by: Jonathan Cameron +Message-ID: <20241101083331.340178-4-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 37 +++++++++++++++++++++++++++++ + hw/core/machine.c | 44 +++++++++++++++++++++++++++++++++++ + include/hw/boards.h | 12 ++++++++++ + qapi/machine-common.json | 50 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 143 insertions(+) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index cfb4beb0baa..3b1ae5d88c4 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -290,6 +290,31 @@ void machine_parse_smp_config(MachineState *ms, + } + } + ++bool machine_parse_smp_cache(MachineState *ms, ++ const SmpCachePropertiesList *caches, ++ Error **errp) ++{ ++ const SmpCachePropertiesList *node; ++ DECLARE_BITMAP(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX); ++ ++ for (node = caches; node; node = node->next) { ++ /* Prohibit users from repeating settings. */ ++ if (test_bit(node->value->cache, caches_bitmap)) { ++ error_setg(errp, ++ "Invalid cache properties: %s. " ++ "The cache properties are duplicated", ++ CacheLevelAndType_str(node->value->cache)); ++ return false; ++ } ++ ++ machine_set_cache_topo_level(ms, node->value->cache, ++ node->value->topology); ++ set_bit(node->value->cache, caches_bitmap); ++ } ++ ++ return true; ++} ++ + unsigned int machine_topo_get_cores_per_socket(const MachineState *ms) + { + return ms->smp.cores * ms->smp.modules * ms->smp.clusters * ms->smp.dies; +@@ -299,3 +324,15 @@ unsigned int machine_topo_get_threads_per_socket(const MachineState *ms) + { + return ms->smp.threads * machine_topo_get_cores_per_socket(ms); + } ++ ++CpuTopologyLevel machine_get_cache_topo_level(const MachineState *ms, ++ CacheLevelAndType cache) ++{ ++ return ms->smp_cache.props[cache].topology; ++} ++ ++void machine_set_cache_topo_level(MachineState *ms, CacheLevelAndType cache, ++ CpuTopologyLevel level) ++{ ++ ms->smp_cache.props[cache].topology = level; ++} +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 1d1e9ce0f03..86887393ca6 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -903,6 +903,40 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, + machine_parse_smp_config(ms, config, errp); + } + ++static void machine_get_smp_cache(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ MachineState *ms = MACHINE(obj); ++ SmpCache *cache = &ms->smp_cache; ++ SmpCachePropertiesList *head = NULL; ++ SmpCachePropertiesList **tail = &head; ++ ++ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) { ++ SmpCacheProperties *node = g_new(SmpCacheProperties, 1); ++ ++ node->cache = cache->props[i].cache; ++ node->topology = cache->props[i].topology; ++ QAPI_LIST_APPEND(tail, node); ++ } ++ ++ visit_type_SmpCachePropertiesList(v, name, &head, errp); ++ qapi_free_SmpCachePropertiesList(head); ++} ++ ++static void machine_set_smp_cache(Object *obj, Visitor *v, const char *name, ++ void *opaque, Error **errp) ++{ ++ MachineState *ms = MACHINE(obj); ++ SmpCachePropertiesList *caches; ++ ++ if (!visit_type_SmpCachePropertiesList(v, name, &caches, errp)) { ++ return; ++ } ++ ++ machine_parse_smp_cache(ms, caches, errp); ++ qapi_free_SmpCachePropertiesList(caches); ++} ++ + static void machine_get_boot(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) + { +@@ -1022,6 +1056,11 @@ static void machine_class_init(ObjectClass *oc, void *data) + object_class_property_set_description(oc, "smp", + "CPU topology"); + ++ object_class_property_add(oc, "smp-cache", "SmpCachePropertiesWrapper", ++ machine_get_smp_cache, machine_set_smp_cache, NULL, NULL); ++ object_class_property_set_description(oc, "smp-cache", ++ "Cache properties list for SMP machine"); ++ + object_class_property_add(oc, "phandle-start", "int", + machine_get_phandle_start, machine_set_phandle_start, + NULL, NULL); +@@ -1160,6 +1199,11 @@ static void machine_initfn(Object *obj) + ms->smp.cores = 1; + ms->smp.threads = 1; + ++ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) { ++ ms->smp_cache.props[i].cache = (CacheLevelAndType)i; ++ ms->smp_cache.props[i].topology = CPU_TOPOLOGY_LEVEL_DEFAULT; ++ } ++ + machine_copy_boot_config(ms, &(BootConfiguration){ 0 }); + } + +diff --git a/include/hw/boards.h b/include/hw/boards.h +index 642aa5532e2..f85a0c08aae 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -36,8 +36,15 @@ void machine_set_cpu_numa_node(MachineState *machine, + Error **errp); + void machine_parse_smp_config(MachineState *ms, + const SMPConfiguration *config, Error **errp); ++bool machine_parse_smp_cache(MachineState *ms, ++ const SmpCachePropertiesList *caches, ++ Error **errp); + unsigned int machine_topo_get_cores_per_socket(const MachineState *ms); + unsigned int machine_topo_get_threads_per_socket(const MachineState *ms); ++CpuTopologyLevel machine_get_cache_topo_level(const MachineState *ms, ++ CacheLevelAndType cache); ++void machine_set_cache_topo_level(MachineState *ms, CacheLevelAndType cache, ++ CpuTopologyLevel level); + void machine_memory_devices_init(MachineState *ms, hwaddr base, uint64_t size); + + /** +@@ -352,6 +359,10 @@ typedef struct CpuTopology { + unsigned int max_cpus; + } CpuTopology; + ++typedef struct SmpCache { ++ SmpCacheProperties props[CACHE_LEVEL_AND_TYPE__MAX]; ++} SmpCache; ++ + /** + * MachineState: + */ +@@ -404,6 +415,7 @@ struct MachineState { + AccelState *accelerator; + CPUArchIdList *possible_cpus; + CpuTopology smp; ++ SmpCache smp_cache; + struct NVDIMMState *nvdimms_state; + struct NumaState *numa_state; + }; +diff --git a/qapi/machine-common.json b/qapi/machine-common.json +index 563360052eb..2a562579335 100644 +--- a/qapi/machine-common.json ++++ b/qapi/machine-common.json +@@ -61,3 +61,53 @@ + { 'enum': 'CpuTopologyLevel', + 'data': [ 'thread', 'core', 'module', 'cluster', 'die', + 'socket', 'book', 'drawer', 'default' ] } ++ ++## ++# @CacheLevelAndType: ++# ++# Caches a system may have. The enumeration value here is the ++# combination of cache level and cache type. ++# ++# @l1d: L1 data cache. ++# ++# @l1i: L1 instruction cache. ++# ++# @l2: L2 (unified) cache. ++# ++# @l3: L3 (unified) cache ++# ++# Since: 9.2 ++## ++{ 'enum': 'CacheLevelAndType', ++ 'data': [ 'l1d', 'l1i', 'l2', 'l3' ] } ++ ++## ++# @SmpCacheProperties: ++# ++# Cache information for SMP system. ++# ++# @cache: Cache name, which is the combination of cache level ++# and cache type. ++# ++# @topology: Cache topology level. It accepts the CPU topology ++# enumeration as the parameter, i.e., CPUs in the same ++# topology container share the same cache. ++# ++# Since: 9.2 ++## ++{ 'struct': 'SmpCacheProperties', ++ 'data': { ++ 'cache': 'CacheLevelAndType', ++ 'topology': 'CpuTopologyLevel' } } ++ ++## ++# @SmpCachePropertiesWrapper: ++# ++# List wrapper of SmpCacheProperties. ++# ++# @caches: the list of SmpCacheProperties. ++# ++# Since 9.2 ++## ++{ 'struct': 'SmpCachePropertiesWrapper', ++ 'data': { 'caches': ['SmpCacheProperties'] } } +-- +2.47.3 + diff --git a/1208-hw-core-Check-smp-cache-topology-support-for-machine.patch b/1208-hw-core-Check-smp-cache-topology-support-for-machine.patch new file mode 100644 index 0000000000000000000000000000000000000000..be8c478213c88d201ae0120147d1a55ff1ae7921 --- /dev/null +++ b/1208-hw-core-Check-smp-cache-topology-support-for-machine.patch @@ -0,0 +1,118 @@ +From 5beecd2c1af97f61cc7d1745e6b616bc81f7b623 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 1 Nov 2024 16:33:26 +0800 +Subject: [PATCH 30/83] hw/core: Check smp cache topology support for machine +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit f35c0221fef864e65db7641bb041c5f913e31475 upstream. + +Add cache_supported flags in SMPCompatProps to allow machines to +configure various caches support. + +And check the compatibility of the cache properties with the +machine support in machine_parse_smp_cache(). + +Intel-SIG: commit f35c0221fef8 hw/core: Check smp cache topology support for machine. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Tested-by: Yongwei Ma +Reviewed-by: Jonathan Cameron +Message-ID: <20241101083331.340178-5-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 41 +++++++++++++++++++++++++++++++++++++++++ + include/hw/boards.h | 3 +++ + 2 files changed, 44 insertions(+) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 3b1ae5d88c4..942d7392580 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -290,10 +290,32 @@ void machine_parse_smp_config(MachineState *ms, + } + } + ++static bool machine_check_topo_support(MachineState *ms, ++ CpuTopologyLevel topo, ++ Error **errp) ++{ ++ MachineClass *mc = MACHINE_GET_CLASS(ms); ++ ++ if ((topo == CPU_TOPOLOGY_LEVEL_MODULE && !mc->smp_props.modules_supported) || ++ (topo == CPU_TOPOLOGY_LEVEL_CLUSTER && !mc->smp_props.clusters_supported) || ++ (topo == CPU_TOPOLOGY_LEVEL_DIE && !mc->smp_props.dies_supported) || ++ (topo == CPU_TOPOLOGY_LEVEL_BOOK && !mc->smp_props.books_supported) || ++ (topo == CPU_TOPOLOGY_LEVEL_DRAWER && !mc->smp_props.drawers_supported)) { ++ error_setg(errp, ++ "Invalid topology level: %s. " ++ "The topology level is not supported by this machine", ++ CpuTopologyLevel_str(topo)); ++ return false; ++ } ++ ++ return true; ++} ++ + bool machine_parse_smp_cache(MachineState *ms, + const SmpCachePropertiesList *caches, + Error **errp) + { ++ MachineClass *mc = MACHINE_GET_CLASS(ms); + const SmpCachePropertiesList *node; + DECLARE_BITMAP(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX); + +@@ -312,6 +334,25 @@ bool machine_parse_smp_cache(MachineState *ms, + set_bit(node->value->cache, caches_bitmap); + } + ++ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) { ++ const SmpCacheProperties *props = &ms->smp_cache.props[i]; ++ ++ /* ++ * Reject non "default" topology level if the cache isn't ++ * supported by the machine. ++ */ ++ if (props->topology != CPU_TOPOLOGY_LEVEL_DEFAULT && ++ !mc->smp_props.cache_supported[props->cache]) { ++ error_setg(errp, ++ "%s cache topology not supported by this machine", ++ CacheLevelAndType_str(node->value->cache)); ++ return false; ++ } ++ ++ if (!machine_check_topo_support(ms, props->topology, errp)) { ++ return false; ++ } ++ } + return true; + } + +diff --git a/include/hw/boards.h b/include/hw/boards.h +index f85a0c08aae..e50418e120f 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -145,6 +145,8 @@ typedef struct { + * @books_supported - whether books are supported by the machine + * @drawers_supported - whether drawers are supported by the machine + * @modules_supported - whether modules are supported by the machine ++ * @cache_supported - whether cache (l1d, l1i, l2 and l3) configuration are ++ * supported by the machine + */ + typedef struct { + bool prefer_sockets; +@@ -154,6 +156,7 @@ typedef struct { + bool books_supported; + bool drawers_supported; + bool modules_supported; ++ bool cache_supported[CACHE_LEVEL_AND_TYPE__MAX]; + } SMPCompatProps; + + /** +-- +2.47.3 + diff --git a/1209-hw-core-Add-a-helper-to-check-the-cache-topology-lev.patch b/1209-hw-core-Add-a-helper-to-check-the-cache-topology-lev.patch new file mode 100644 index 0000000000000000000000000000000000000000..77d44fbb8d3744e1e90d9fe7c950e24feca05524 --- /dev/null +++ b/1209-hw-core-Add-a-helper-to-check-the-cache-topology-lev.patch @@ -0,0 +1,108 @@ +From 9eaaaca7b6fb3fd01ce583e20fde79ec14c38421 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 1 Nov 2024 16:33:27 +0800 +Subject: [PATCH 31/83] hw/core: Add a helper to check the cache topology level +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 07995a46bae9d2ec0971b435834c60a4df84b03f upstream. + +Currently, we have no way to expose the arch-specific default cache +model because the cache model is sometimes related to the CPU model +(e.g., i386). + +Since the user might configure "default" level, any comparison with +"default" is meaningless before the machine knows the specific level +that "default" refers to. + +We can only check the correctness of the cache topology after the arch +loads the user-configured cache model from MachineState.smp_cache and +consumes the special "default" level by replacing it with the specific +level. + +Intel-SIG: commit 07995a46bae9 hw/core: Add a helper to check the cache topology level. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Jonathan Cameron +Message-ID: <20241101083331.340178-6-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 48 +++++++++++++++++++++++++++++++++++++++++++ + include/hw/boards.h | 1 + + 2 files changed, 49 insertions(+) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 942d7392580..37297cb4c88 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -377,3 +377,51 @@ void machine_set_cache_topo_level(MachineState *ms, CacheLevelAndType cache, + { + ms->smp_cache.props[cache].topology = level; + } ++ ++/* ++ * When both cache1 and cache2 are configured with specific topology levels ++ * (not default level), is cache1's topology level higher than cache2? ++ */ ++static bool smp_cache_topo_cmp(const SmpCache *smp_cache, ++ CacheLevelAndType cache1, ++ CacheLevelAndType cache2) ++{ ++ /* ++ * Before comparing, the "default" topology level should be replaced ++ * with the specific level. ++ */ ++ assert(smp_cache->props[cache1].topology != CPU_TOPOLOGY_LEVEL_DEFAULT); ++ ++ return smp_cache->props[cache1].topology > smp_cache->props[cache2].topology; ++} ++ ++/* ++ * Currently, we have no way to expose the arch-specific default cache model ++ * because the cache model is sometimes related to the CPU model (e.g., i386). ++ * ++ * We can only check the correctness of the cache topology after the arch loads ++ * the user-configured cache model from MachineState and consumes the special ++ * "default" level by replacing it with the specific level. ++ */ ++bool machine_check_smp_cache(const MachineState *ms, Error **errp) ++{ ++ if (smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L1D, ++ CACHE_LEVEL_AND_TYPE_L2) || ++ smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L1I, ++ CACHE_LEVEL_AND_TYPE_L2)) { ++ error_setg(errp, ++ "Invalid smp cache topology. " ++ "L2 cache topology level shouldn't be lower than L1 cache"); ++ return false; ++ } ++ ++ if (smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L2, ++ CACHE_LEVEL_AND_TYPE_L3)) { ++ error_setg(errp, ++ "Invalid smp cache topology. " ++ "L3 cache topology level shouldn't be lower than L2 cache"); ++ return false; ++ } ++ ++ return true; ++} +diff --git a/include/hw/boards.h b/include/hw/boards.h +index e50418e120f..cda7a647dbf 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -45,6 +45,7 @@ CpuTopologyLevel machine_get_cache_topo_level(const MachineState *ms, + CacheLevelAndType cache); + void machine_set_cache_topo_level(MachineState *ms, CacheLevelAndType cache, + CpuTopologyLevel level); ++bool machine_check_smp_cache(const MachineState *ms, Error **errp); + void machine_memory_devices_init(MachineState *ms, hwaddr base, uint64_t size); + + /** +-- +2.47.3 + diff --git a/1210-hw-core-machine-smp-Initialize-caches_bitmap-before-.patch b/1210-hw-core-machine-smp-Initialize-caches_bitmap-before-.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7c20bbf1a1781ac19b52f9bbfc7b4123e99e269 --- /dev/null +++ b/1210-hw-core-machine-smp-Initialize-caches_bitmap-before-.patch @@ -0,0 +1,47 @@ +From 207352b309ae3f2b1869a5f4955b992a8b2f5ec8 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Sun, 10 Nov 2024 23:09:00 +0800 +Subject: [PATCH 32/83] hw/core/machine-smp: Initialize caches_bitmap before + reading +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 9c2644948c71db61a04f22398cde72224a98267a upstream. + +The caches_bitmap is defined in machine_parse_smp_cache(), but it was +not initialized. + +Initialize caches_bitmap by clearing all its bits to zero. + +Resolves: Coverity CID 1565389 +Fixes: 4e88e7e3403d ("qapi/qom: Define cache enumeration and properties for machine") +Reported-by: Peter Maydell +Intel-SIG: commit 9c2644948c71 hw/core/machine-smp: Initialize caches_bitmap before reading. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Philippe Mathieu-Daudé +Link: https://lore.kernel.org/r/20241110150901.130647-2-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 37297cb4c88..30fa851cfc9 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -319,6 +319,7 @@ bool machine_parse_smp_cache(MachineState *ms, + const SmpCachePropertiesList *node; + DECLARE_BITMAP(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX); + ++ bitmap_zero(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX); + for (node = caches; node; node = node->next) { + /* Prohibit users from repeating settings. */ + if (test_bit(node->value->cache, caches_bitmap)) { +-- +2.47.3 + diff --git a/1211-hw-core-machine-smp-Fix-error-message-parameter.patch b/1211-hw-core-machine-smp-Fix-error-message-parameter.patch new file mode 100644 index 0000000000000000000000000000000000000000..a4527cf1f3ab56c715477c81764cd634b8023941 --- /dev/null +++ b/1211-hw-core-machine-smp-Fix-error-message-parameter.patch @@ -0,0 +1,48 @@ +From 07f1105e0dadeb3a3d3b4ed6d57b874bf8d98b8e Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Sun, 10 Nov 2024 23:09:01 +0800 +Subject: [PATCH 33/83] hw/core/machine-smp: Fix error message parameter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 37ee17eebb93eb485fc122452a4c7e9202a8b449 upstream. + +In the loop checking smp cache support, the error message should report +the current cache level and type. + +Fix the parameter of error_setg() to ensure it reports the correct cache +level and type. + +Resolves: Coverity CID 1565391 +Fixes: f35c0221fef8 ("hw/core: Check smp cache topology support for machine") +Reported-by: Peter Maydell +Intel-SIG: commit 37ee17eebb93 hw/core/machine-smp: Fix error message parameter. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Philippe Mathieu-Daudé +Link: https://lore.kernel.org/r/20241110150901.130647-3-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 30fa851cfc9..aea5bb53e35 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -346,7 +346,7 @@ bool machine_parse_smp_cache(MachineState *ms, + !mc->smp_props.cache_supported[props->cache]) { + error_setg(errp, + "%s cache topology not supported by this machine", +- CacheLevelAndType_str(node->value->cache)); ++ CacheLevelAndType_str(props->cache)); + return false; + } + +-- +2.47.3 + diff --git a/1212-i386-cpu-Extract-a-common-fucntion-to-setup-value-of.patch b/1212-i386-cpu-Extract-a-common-fucntion-to-setup-value-of.patch new file mode 100644 index 0000000000000000000000000000000000000000..121702fe98a801a433b5a6b7a243d6743531864d --- /dev/null +++ b/1212-i386-cpu-Extract-a-common-fucntion-to-setup-value-of.patch @@ -0,0 +1,106 @@ +From bff5649fefa2cbbca0fc41dc5a5d9d36e11e8fb9 Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:16 -0500 +Subject: [PATCH 34/83] i386/cpu: Extract a common fucntion to setup value of + MSR_CORE_THREAD_COUNT + +commit d3bb5d0d4f5d4ad7dc6c02ea5fea51ca2f946593 upstream. + +There are duplicated code to setup the value of MSR_CORE_THREAD_COUNT. +Extract a common function for it. + +Intel-SIG: commit d3bb5d0d4f5d i386/cpu: Extract a common fucntion to setup value of MSR_CORE_THREAD_COUNT. +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Link: https://lore.kernel.org/r/20241219110125.1266461-2-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu-sysemu.c | 10 ++++++++++ + target/i386/cpu.h | 2 ++ + target/i386/hvf/x86_emu.c | 3 +-- + target/i386/kvm/kvm.c | 5 +---- + target/i386/tcg/sysemu/misc_helper.c | 3 +-- + 5 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c +index 2375e48178f..227bfb9a788 100644 +--- a/target/i386/cpu-sysemu.c ++++ b/target/i386/cpu-sysemu.c +@@ -354,3 +354,13 @@ void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, + qapi_free_GuestPanicInformation(panic_info); + } + ++uint64_t cpu_x86_get_msr_core_thread_count(X86CPU *cpu) ++{ ++ CPUState *cs = CPU(cpu); ++ uint64_t val; ++ ++ val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */ ++ val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */ ++ ++ return val; ++} +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 888dfb3ae6b..6157243806a 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2326,6 +2326,8 @@ static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu, + cs->halted = 0; + } + ++uint64_t cpu_x86_get_msr_core_thread_count(X86CPU *cpu); ++ + int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector, + target_ulong *base, unsigned int *limit, + unsigned int *flags); +diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c +index 3a3f0a50d0b..eb8e7767fbf 100644 +--- a/target/i386/hvf/x86_emu.c ++++ b/target/i386/hvf/x86_emu.c +@@ -745,8 +745,7 @@ void simulate_rdmsr(CPUX86State *env) + val = env->mtrr_deftype; + break; + case MSR_CORE_THREAD_COUNT: +- val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */ +- val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */ ++ val = cpu_x86_get_msr_core_thread_count(cpu); + break; + default: + /* fprintf(stderr, "%s: unknown msr 0x%x\n", __func__, msr); */ +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 78fecd564fa..7482001c3bd 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -2509,10 +2509,7 @@ static int kvm_get_supported_msrs(KVMState *s) + static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr, + uint64_t *val) + { +- CPUState *cs = CPU(cpu); +- +- *val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */ +- *val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */ ++ *val = cpu_x86_get_msr_core_thread_count(cpu); + + return true; + } +diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c +index 1901712ecef..f380b587892 100644 +--- a/target/i386/tcg/sysemu/misc_helper.c ++++ b/target/i386/tcg/sysemu/misc_helper.c +@@ -454,8 +454,7 @@ void helper_rdmsr(CPUX86State *env) + val = x86_cpu->ucode_rev; + break; + case MSR_CORE_THREAD_COUNT: { +- CPUState *cs = CPU(x86_cpu); +- val = (cs->nr_threads * cs->nr_cores) | (cs->nr_cores << 16); ++ val = cpu_x86_get_msr_core_thread_count(x86_cpu); + break; + } + default: +-- +2.47.3 + diff --git a/1213-i386-cpu-Drop-the-variable-smp_cores-and-smp_threads.patch b/1213-i386-cpu-Drop-the-variable-smp_cores-and-smp_threads.patch new file mode 100644 index 0000000000000000000000000000000000000000..51bfb0e360d662285496fb8b321cf04d3548b45a --- /dev/null +++ b/1213-i386-cpu-Drop-the-variable-smp_cores-and-smp_threads.patch @@ -0,0 +1,63 @@ +From f7ac37f626c47bcf5ac0b8cbd74b58dba3084afd Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:17 -0500 +Subject: [PATCH 35/83] i386/cpu: Drop the variable smp_cores and smp_threads + in x86_cpu_pre_plug() + +commit 81bd60625fc23cb8d4d0e682dcc4223d5e1ead84 upstream. + +No need to define smp_cores and smp_threads, just using ms->smp.cores +and ms->smp.threads is straightforward. It's also consistent with other +checks of socket/die/module. + +Intel-SIG: commit 81bd60625fc2 i386/cpu: Drop the variable smp_cores and smp_threads in x86_cpu_pre_plug(). +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Link: https://lore.kernel.org/r/20241219110125.1266461-3-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86-common.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +index e6b34269c0f..6c509622212 100644 +--- a/hw/i386/x86-common.c ++++ b/hw/i386/x86-common.c +@@ -244,8 +244,6 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + CPUX86State *env = &cpu->env; + MachineState *ms = MACHINE(hotplug_dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); +- unsigned int smp_cores = ms->smp.cores; +- unsigned int smp_threads = ms->smp.threads; + X86CPUTopoInfo topo_info; + + if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { +@@ -325,17 +323,17 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + if (cpu->core_id < 0) { + error_setg(errp, "CPU core-id is not set"); + return; +- } else if (cpu->core_id > (smp_cores - 1)) { ++ } else if (cpu->core_id > (ms->smp.cores - 1)) { + error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", +- cpu->core_id, smp_cores - 1); ++ cpu->core_id, ms->smp.cores - 1); + return; + } + if (cpu->thread_id < 0) { + error_setg(errp, "CPU thread-id is not set"); + return; +- } else if (cpu->thread_id > (smp_threads - 1)) { ++ } else if (cpu->thread_id > (ms->smp.threads - 1)) { + error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", +- cpu->thread_id, smp_threads - 1); ++ cpu->thread_id, ms->smp.threads - 1); + return; + } + +-- +2.47.3 + diff --git a/1214-i386-cpu-Drop-cores_per_pkg-in-cpu_x86_cpuid.patch b/1214-i386-cpu-Drop-cores_per_pkg-in-cpu_x86_cpuid.patch new file mode 100644 index 0000000000000000000000000000000000000000..28857c7cc8830732dc5d11523ffe540124c87312 --- /dev/null +++ b/1214-i386-cpu-Drop-cores_per_pkg-in-cpu_x86_cpuid.patch @@ -0,0 +1,50 @@ +From cd98fb5dec9284bc4f1b3afc02bdb7877f9ac905 Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:18 -0500 +Subject: [PATCH 36/83] i386/cpu: Drop cores_per_pkg in cpu_x86_cpuid() + +commit 00ec7be67c3981b486293aa8e0aef9534f229c5e upstream. + +Local variable cores_per_pkg is only used to calculate threads_per_pkg. +No need for it. Drop it and open-code it instead. + +Intel-SIG: commit 00ec7be67c39 i386/cpu: Drop cores_per_pkg in cpu_x86_cpuid(). +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Link: https://lore.kernel.org/r/20241219110125.1266461-4-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 3259448a7cf..b17306897e0 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6810,7 +6810,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + uint32_t limit; + uint32_t signature[3]; + X86CPUTopoInfo topo_info; +- uint32_t cores_per_pkg; + uint32_t threads_per_pkg; + + if (index == 0x8C860000) { +@@ -6826,9 +6825,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + topo_info.cores_per_module = cs->nr_cores / env->nr_dies / env->nr_modules; + topo_info.threads_per_core = cs->nr_threads; + +- cores_per_pkg = topo_info.cores_per_module * topo_info.modules_per_die * +- topo_info.dies_per_pkg; +- threads_per_pkg = cores_per_pkg * topo_info.threads_per_core; ++ threads_per_pkg = topo_info.threads_per_core * topo_info.cores_per_module * ++ topo_info.modules_per_die * topo_info.dies_per_pkg; + + /* Calculate & apply limits for different index ranges */ + if (index >= 0xC0000000) { +-- +2.47.3 + diff --git a/1215-i386-topology-Update-the-comment-of-x86_apicid_from_.patch b/1215-i386-topology-Update-the-comment-of-x86_apicid_from_.patch new file mode 100644 index 0000000000000000000000000000000000000000..aa85bbbffa6fa373715286b6a1ff8d4f9f9352ff --- /dev/null +++ b/1215-i386-topology-Update-the-comment-of-x86_apicid_from_.patch @@ -0,0 +1,44 @@ +From a9378a060c57d423aca57c3f9ca0854a708e9e8f Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:19 -0500 +Subject: [PATCH 37/83] i386/topology: Update the comment of + x86_apicid_from_topo_ids() + +commit 8f78378de70fc79fdc7e1318496bd91ddd22df49 upstream. + +Update the comment of x86_apicid_from_topo_ids() to match the current +implementation, + +Intel-SIG: commit 8f78378de70f i386/topology: Update the comment of x86_apicid_from_topo_ids(). +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Link: https://lore.kernel.org/r/20241219110125.1266461-5-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + include/hw/i386/topology.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index b2c8bf2de15..21b65219a5c 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -121,9 +121,10 @@ static inline unsigned apicid_pkg_offset(X86CPUTopoInfo *topo_info) + } + + /* +- * Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID ++ * Make APIC ID for the CPU based on topology and IDs of each topology level. + * +- * The caller must make sure core_id < nr_cores and smt_id < nr_threads. ++ * The caller must make sure the ID of each level doesn't exceed the width of ++ * the level. + */ + static inline apic_id_t x86_apicid_from_topo_ids(X86CPUTopoInfo *topo_info, + const X86CPUTopoIDs *topo_ids) +-- +2.47.3 + diff --git a/1216-i386-topology-Introduce-helpers-for-various-topology.patch b/1216-i386-topology-Introduce-helpers-for-various-topology.patch new file mode 100644 index 0000000000000000000000000000000000000000..7789f518bf39f1ecd4422a8887dedb52e0cdbfc4 --- /dev/null +++ b/1216-i386-topology-Introduce-helpers-for-various-topology.patch @@ -0,0 +1,96 @@ +From 954f76d6f411759e18614237ff09964ad02419c5 Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:20 -0500 +Subject: [PATCH 38/83] i386/topology: Introduce helpers for various topology + info of different level + +commit e60cbeec190d349682bf97cf55446e8ae260b11a upstream. + +Introduce various helpers for getting the topology info of different +semantics. Using the helper is more self-explanatory. + +Besides, the semantic of the helper will stay unchanged even when new +topology is added in the future. At that time, updating the +implementation of the helper without affecting the callers. + +Intel-SIG: commit e60cbeec190d i386/topology: Introduce helpers for various topology info of different level. +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Link: https://lore.kernel.org/r/20241219110125.1266461-6-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + include/hw/i386/topology.h | 25 +++++++++++++++++++++++++ + target/i386/cpu.c | 11 ++++------- + 2 files changed, 29 insertions(+), 7 deletions(-) + +diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h +index 21b65219a5c..f6380f1ed75 100644 +--- a/include/hw/i386/topology.h ++++ b/include/hw/i386/topology.h +@@ -203,4 +203,29 @@ static inline bool x86_has_extended_topo(unsigned long *topo_bitmap) + test_bit(CPU_TOPOLOGY_LEVEL_DIE, topo_bitmap); + } + ++static inline unsigned x86_module_per_pkg(X86CPUTopoInfo *topo_info) ++{ ++ return topo_info->modules_per_die * topo_info->dies_per_pkg; ++} ++ ++static inline unsigned x86_cores_per_pkg(X86CPUTopoInfo *topo_info) ++{ ++ return topo_info->cores_per_module * x86_module_per_pkg(topo_info); ++} ++ ++static inline unsigned x86_threads_per_pkg(X86CPUTopoInfo *topo_info) ++{ ++ return topo_info->threads_per_core * x86_cores_per_pkg(topo_info); ++} ++ ++static inline unsigned x86_threads_per_module(X86CPUTopoInfo *topo_info) ++{ ++ return topo_info->threads_per_core * topo_info->cores_per_module; ++} ++ ++static inline unsigned x86_threads_per_die(X86CPUTopoInfo *topo_info) ++{ ++ return x86_threads_per_module(topo_info) * topo_info->modules_per_die; ++} ++ + #endif /* HW_I386_TOPOLOGY_H */ +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index b17306897e0..25a2f0acb18 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -313,13 +313,11 @@ static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info, + case CPU_TOPOLOGY_LEVEL_CORE: + return topo_info->threads_per_core; + case CPU_TOPOLOGY_LEVEL_MODULE: +- return topo_info->threads_per_core * topo_info->cores_per_module; ++ return x86_threads_per_module(topo_info); + case CPU_TOPOLOGY_LEVEL_DIE: +- return topo_info->threads_per_core * topo_info->cores_per_module * +- topo_info->modules_per_die; ++ return x86_threads_per_die(topo_info); + case CPU_TOPOLOGY_LEVEL_SOCKET: +- return topo_info->threads_per_core * topo_info->cores_per_module * +- topo_info->modules_per_die * topo_info->dies_per_pkg; ++ return x86_threads_per_pkg(topo_info); + default: + g_assert_not_reached(); + } +@@ -6825,8 +6823,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + topo_info.cores_per_module = cs->nr_cores / env->nr_dies / env->nr_modules; + topo_info.threads_per_core = cs->nr_threads; + +- threads_per_pkg = topo_info.threads_per_core * topo_info.cores_per_module * +- topo_info.modules_per_die * topo_info.dies_per_pkg; ++ threads_per_pkg = x86_threads_per_pkg(&topo_info); + + /* Calculate & apply limits for different index ranges */ + if (index >= 0xC0000000) { +-- +2.47.3 + diff --git a/1217-i386-cpu-Track-a-X86CPUTopoInfo-directly-in-CPUX86St.patch b/1217-i386-cpu-Track-a-X86CPUTopoInfo-directly-in-CPUX86St.patch new file mode 100644 index 0000000000000000000000000000000000000000..270baecf731ee7e044821e75ac7bc1a6b51cca20 --- /dev/null +++ b/1217-i386-cpu-Track-a-X86CPUTopoInfo-directly-in-CPUX86St.patch @@ -0,0 +1,303 @@ +From 9697c5d86e1d26692cb07c494502a1367729eb85 Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:21 -0500 +Subject: [PATCH 39/83] i386/cpu: Track a X86CPUTopoInfo directly in + CPUX86State + +commit 84b71a131c1bc84c36fafb63271080ecf9f2ff7a upstream. + +The name of nr_modules/nr_dies are ambiguous and they mislead people. + +The purpose of them is to record and form the topology information. So +just maintain a X86CPUTopoInfo member in CPUX86State instead. Then +nr_modules and nr_dies can be dropped. + +As the benefit, x86 can switch to use information in +CPUX86State::topo_info and get rid of the nr_cores and nr_threads in +CPUState. This helps remove the dependency on qemu_init_vcpu(), so that +x86 can get and use topology info earlier in x86_cpu_realizefn(); drop +the comment that highlighted the depedency. + +Intel-SIG: commit 84b71a131c1b i386/cpu: Track a X86CPUTopoInfo directly in CPUX86State. +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Link: https://lore.kernel.org/r/20241219110125.1266461-7-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/x86-common.c | 12 ++++------ + target/i386/cpu-sysemu.c | 6 ++--- + target/i386/cpu.c | 51 +++++++++++++++++----------------------- + target/i386/cpu.h | 6 +---- + 4 files changed, 30 insertions(+), 45 deletions(-) + +diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c +index 6c509622212..199a193bb6e 100644 +--- a/hw/i386/x86-common.c ++++ b/hw/i386/x86-common.c +@@ -244,7 +244,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + CPUX86State *env = &cpu->env; + MachineState *ms = MACHINE(hotplug_dev); + X86MachineState *x86ms = X86_MACHINE(hotplug_dev); +- X86CPUTopoInfo topo_info; ++ X86CPUTopoInfo *topo_info = &env->topo_info; + + if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) { + error_setg(errp, "Invalid CPU type, expected cpu type: '%s'", +@@ -263,15 +263,13 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + } + } + +- init_topo_info(&topo_info, x86ms); ++ init_topo_info(topo_info, x86ms); + + if (ms->smp.modules > 1) { +- env->nr_modules = ms->smp.modules; + set_bit(CPU_TOPOLOGY_LEVEL_MODULE, env->avail_cpu_topo); + } + + if (ms->smp.dies > 1) { +- env->nr_dies = ms->smp.dies; + set_bit(CPU_TOPOLOGY_LEVEL_DIE, env->avail_cpu_topo); + } + +@@ -342,12 +340,12 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + topo_ids.module_id = cpu->module_id; + topo_ids.core_id = cpu->core_id; + topo_ids.smt_id = cpu->thread_id; +- cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids); ++ cpu->apic_id = x86_apicid_from_topo_ids(topo_info, &topo_ids); + } + + cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx); + if (!cpu_slot) { +- x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); ++ x86_topo_ids_from_apicid(cpu->apic_id, topo_info, &topo_ids); + + error_setg(errp, + "Invalid CPU [socket: %u, die: %u, module: %u, core: %u, thread: %u]" +@@ -370,7 +368,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev, + /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn() + * once -smp refactoring is complete and there will be CPU private + * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */ +- x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids); ++ x86_topo_ids_from_apicid(cpu->apic_id, topo_info, &topo_ids); + if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) { + error_setg(errp, "property socket-id: %u doesn't match set apic-id:" + " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id, +diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c +index 227bfb9a788..35d1cefcb39 100644 +--- a/target/i386/cpu-sysemu.c ++++ b/target/i386/cpu-sysemu.c +@@ -356,11 +356,11 @@ void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, + + uint64_t cpu_x86_get_msr_core_thread_count(X86CPU *cpu) + { +- CPUState *cs = CPU(cpu); ++ CPUX86State *env = &cpu->env; + uint64_t val; + +- val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */ +- val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */ ++ val = x86_threads_per_pkg(&env->topo_info); /* thread count, bits 15..0 */ ++ val |= x86_cores_per_pkg(&env->topo_info) << 16; /* core count, bits 31..16 */ + + return val; + } +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 25a2f0acb18..7f232d82140 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6807,7 +6807,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + CPUState *cs = env_cpu(env); + uint32_t limit; + uint32_t signature[3]; +- X86CPUTopoInfo topo_info; ++ X86CPUTopoInfo *topo_info = &env->topo_info; + uint32_t threads_per_pkg; + + if (index == 0x8C860000) { +@@ -6818,12 +6818,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + return; + } + +- topo_info.dies_per_pkg = env->nr_dies; +- topo_info.modules_per_die = env->nr_modules; +- topo_info.cores_per_module = cs->nr_cores / env->nr_dies / env->nr_modules; +- topo_info.threads_per_core = cs->nr_threads; +- +- threads_per_pkg = x86_threads_per_pkg(&topo_info); ++ threads_per_pkg = x86_threads_per_pkg(topo_info); + + /* Calculate & apply limits for different index ranges */ + if (index >= 0xC0000000) { +@@ -6900,12 +6895,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + int host_vcpus_per_cache = 1 + ((*eax & 0x3FFC000) >> 14); + + *eax &= ~0xFC000000; +- *eax |= max_core_ids_in_package(&topo_info) << 26; ++ *eax |= max_core_ids_in_package(topo_info) << 26; + if (host_vcpus_per_cache > threads_per_pkg) { + *eax &= ~0x3FFC000; + + /* Share the cache at package level. */ +- *eax |= max_thread_ids_for_cache(&topo_info, ++ *eax |= max_thread_ids_for_cache(topo_info, + CPU_TOPOLOGY_LEVEL_SOCKET) << 14; + } + } +@@ -6917,7 +6912,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + switch (count) { + case 0: /* L1 dcache info */ + encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache, +- &topo_info, ++ topo_info, + eax, ebx, ecx, edx); + if (!cpu->l1_cache_per_core) { + *eax &= ~MAKE_64BIT_MASK(14, 12); +@@ -6925,7 +6920,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 1: /* L1 icache info */ + encode_cache_cpuid4(env->cache_info_cpuid4.l1i_cache, +- &topo_info, ++ topo_info, + eax, ebx, ecx, edx); + if (!cpu->l1_cache_per_core) { + *eax &= ~MAKE_64BIT_MASK(14, 12); +@@ -6933,13 +6928,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 2: /* L2 cache info */ + encode_cache_cpuid4(env->cache_info_cpuid4.l2_cache, +- &topo_info, ++ topo_info, + eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ + if (cpu->enable_l3_cache) { + encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache, +- &topo_info, ++ topo_info, + eax, ebx, ecx, edx); + break; + } +@@ -7041,12 +7036,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + + switch (count) { + case 0: +- *eax = apicid_core_offset(&topo_info); +- *ebx = topo_info.threads_per_core; ++ *eax = apicid_core_offset(topo_info); ++ *ebx = topo_info->threads_per_core; + *ecx |= CPUID_B_ECX_TOPO_LEVEL_SMT << 8; + break; + case 1: +- *eax = apicid_pkg_offset(&topo_info); ++ *eax = apicid_pkg_offset(topo_info); + *ebx = threads_per_pkg; + *ecx |= CPUID_B_ECX_TOPO_LEVEL_CORE << 8; + break; +@@ -7072,7 +7067,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + } + +- encode_topo_cpuid1f(env, count, &topo_info, eax, ebx, ecx, edx); ++ encode_topo_cpuid1f(env, count, topo_info, eax, ebx, ecx, edx); + break; + case 0xD: { + /* Processor Extended State */ +@@ -7371,7 +7366,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + * thread ID within a package". + * Bits 7:0 is "The number of threads in the package is NC+1" + */ +- *ecx = (apicid_pkg_offset(&topo_info) << 12) | ++ *ecx = (apicid_pkg_offset(topo_info) << 12) | + (threads_per_pkg - 1); + } else { + *ecx = 0; +@@ -7400,19 +7395,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + switch (count) { + case 0: /* L1 dcache info */ + encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache, +- &topo_info, eax, ebx, ecx, edx); ++ topo_info, eax, ebx, ecx, edx); + break; + case 1: /* L1 icache info */ + encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache, +- &topo_info, eax, ebx, ecx, edx); ++ topo_info, eax, ebx, ecx, edx); + break; + case 2: /* L2 cache info */ + encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache, +- &topo_info, eax, ebx, ecx, edx); ++ topo_info, eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ + encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache, +- &topo_info, eax, ebx, ecx, edx); ++ topo_info, eax, ebx, ecx, edx); + break; + default: /* end of info */ + *eax = *ebx = *ecx = *edx = 0; +@@ -7421,7 +7416,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 0x8000001E: + if (cpu->core_id <= 255) { +- encode_topo_cpuid8000001e(cpu, &topo_info, eax, ebx, ecx, edx); ++ encode_topo_cpuid8000001e(cpu, topo_info, eax, ebx, ecx, edx); + } else { + *eax = 0; + *ebx = 0; +@@ -8308,16 +8303,13 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + * fixes this issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX + * based on inputs (sockets,cores,threads), it is still better to give + * users a warning. +- * +- * NOTE: the following code has to follow qemu_init_vcpu(). Otherwise +- * cs->nr_threads hasn't be populated yet and the checking is incorrect. + */ + if (IS_AMD_CPU(env) && + !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) && +- cs->nr_threads > 1 && !ht_warned) { ++ env->topo_info.threads_per_core > 1 && !ht_warned) { + warn_report("This family of AMD CPU doesn't support " + "hyperthreading(%d)", +- cs->nr_threads); ++ env->topo_info.threads_per_core); + error_printf("Please configure -smp options properly" + " or try enabling topoext feature.\n"); + ht_warned = true; +@@ -8481,8 +8473,7 @@ static void x86_cpu_init_default_topo(X86CPU *cpu) + { + CPUX86State *env = &cpu->env; + +- env->nr_modules = 1; +- env->nr_dies = 1; ++ env->topo_info = (X86CPUTopoInfo) {1, 1, 1, 1}; + + /* thread, core and socket levels are set by default. */ + set_bit(CPU_TOPOLOGY_LEVEL_THREAD, env->avail_cpu_topo); +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 6157243806a..1aa42f6f832 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1985,14 +1985,10 @@ typedef struct CPUArchState { + + TPRAccess tpr_access_type; + +- /* Number of dies within this CPU package. */ +- unsigned nr_dies; +- + /* GHCB guest physical address info */ + uint64_t ghcb_gpa; + +- /* Number of modules within one die. */ +- unsigned nr_modules; ++ X86CPUTopoInfo topo_info; + + /* Bitmap of available CPU topology levels for this CPU. */ + DECLARE_BITMAP(avail_cpu_topo, CPU_TOPOLOGY_LEVEL__MAX); +-- +2.47.3 + diff --git a/1218-i386-cpu-Hoist-check-of-CPUID_EXT3_TOPOEXT-against-t.patch b/1218-i386-cpu-Hoist-check-of-CPUID_EXT3_TOPOEXT-against-t.patch new file mode 100644 index 0000000000000000000000000000000000000000..0c9cb1b587ea328e20eeeae4ef31e37e2bfec8d0 --- /dev/null +++ b/1218-i386-cpu-Hoist-check-of-CPUID_EXT3_TOPOEXT-against-t.patch @@ -0,0 +1,79 @@ +From cc90dc46dd37806fa202271a2066aa83bc96f98f Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:22 -0500 +Subject: [PATCH 40/83] i386/cpu: Hoist check of CPUID_EXT3_TOPOEXT against + threads_per_core + +commit 473d79b56a1645be90b890f9623b27acd0afba49 upstream. + +Now it changes to use env->topo_info.threads_per_core and doesn't depend +on qemu_init_vcpu() anymore. Put it together with other feature checks +before qemu_init_vcpu() + +Intel-SIG: commit 473d79b56a16 i386/cpu: Hoist check of CPUID_EXT3_TOPOEXT against threads_per_core. +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Link: https://lore.kernel.org/r/20241219110125.1266461-8-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 7f232d82140..e283e6e6392 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -8195,6 +8195,23 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + */ + cpu->mwait.ecx |= CPUID_MWAIT_EMX | CPUID_MWAIT_IBE; + ++ /* ++ * Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU ++ * fixes this issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX ++ * based on inputs (sockets,cores,threads), it is still better to give ++ * users a warning. ++ */ ++ if (IS_AMD_CPU(env) && ++ !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) && ++ env->topo_info.threads_per_core > 1 && !ht_warned) { ++ warn_report("This family of AMD CPU doesn't support " ++ "hyperthreading(%d)", ++ env->topo_info.threads_per_core); ++ error_printf("Please configure -smp options properly" ++ " or try enabling topoext feature.\n"); ++ ht_warned = true; ++ } ++ + /* For 64bit systems think about the number of physical bits to present. + * ideally this should be the same as the host; anything other than matching + * the host can cause incorrect guest behaviour. +@@ -8298,23 +8315,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + + qemu_init_vcpu(cs); + +- /* +- * Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU +- * fixes this issue by adjusting CPUID_0000_0001_EBX and CPUID_8000_0008_ECX +- * based on inputs (sockets,cores,threads), it is still better to give +- * users a warning. +- */ +- if (IS_AMD_CPU(env) && +- !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_TOPOEXT) && +- env->topo_info.threads_per_core > 1 && !ht_warned) { +- warn_report("This family of AMD CPU doesn't support " +- "hyperthreading(%d)", +- env->topo_info.threads_per_core); +- error_printf("Please configure -smp options properly" +- " or try enabling topoext feature.\n"); +- ht_warned = true; +- } +- + #ifndef CONFIG_USER_ONLY + x86_cpu_apic_realize(cpu, &local_err); + if (local_err != NULL) { +-- +2.47.3 + diff --git a/1219-cpu-Remove-nr_cores-from-struct-CPUState.patch b/1219-cpu-Remove-nr_cores-from-struct-CPUState.patch new file mode 100644 index 0000000000000000000000000000000000000000..b0d98282420c6a19316aa6bc4b36445ae7a73c70 --- /dev/null +++ b/1219-cpu-Remove-nr_cores-from-struct-CPUState.patch @@ -0,0 +1,71 @@ +From 2f61ac37a5b45f76114613fba3eb4a98b55d7cd8 Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:23 -0500 +Subject: [PATCH 41/83] cpu: Remove nr_cores from struct CPUState + +commit 6e090ffe0d188e1f09d4efcd10d82158f92abfbb upstream. + +There is no user of it now, remove it. + +Intel-SIG: commit 6e090ffe0d18 cpu: Remove nr_cores from struct CPUState. +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Link: https://lore.kernel.org/r/20241219110125.1266461-9-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/cpu-common.c | 1 - + include/hw/core/cpu.h | 2 -- + system/cpus.c | 1 - + 3 files changed, 4 deletions(-) + +diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c +index 82dae51a550..160ac8b27c8 100644 +--- a/hw/core/cpu-common.c ++++ b/hw/core/cpu-common.c +@@ -245,7 +245,6 @@ static void cpu_common_initfn(Object *obj) + cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; + /* user-mode doesn't have configurable SMP topology */ + /* the default value is changed by qemu_init_vcpu() for system-mode */ +- cpu->nr_cores = 1; + cpu->nr_threads = 1; + cpu->cflags_next_tb = -1; + +diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h +index be87df14bb7..4411ceee951 100644 +--- a/include/hw/core/cpu.h ++++ b/include/hw/core/cpu.h +@@ -407,7 +407,6 @@ struct qemu_work_item; + * Under TCG this value is propagated to @tcg_cflags. + * See TranslationBlock::TCG CF_CLUSTER_MASK. + * @tcg_cflags: Pre-computed cflags for this cpu. +- * @nr_cores: Number of cores within this CPU package. + * @nr_threads: Number of threads within this CPU core. + * @running: #true if CPU is currently running (lockless). + * @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end; +@@ -461,7 +460,6 @@ struct CPUState { + CPUClass *cc; + /*< public >*/ + +- int nr_cores; + int nr_threads; + + struct QemuThread *thread; +diff --git a/system/cpus.c b/system/cpus.c +index cbeec13f391..48328dd749f 100644 +--- a/system/cpus.c ++++ b/system/cpus.c +@@ -645,7 +645,6 @@ void qemu_init_vcpu(CPUState *cpu) + { + MachineState *ms = MACHINE(qdev_get_machine()); + +- cpu->nr_cores = machine_topo_get_cores_per_socket(ms); + cpu->nr_threads = ms->smp.threads; + cpu->stopped = true; + cpu->random_seed = qemu_guest_random_seed_thread_part1(); +-- +2.47.3 + diff --git a/1220-i386-cpu-Set-up-CPUID_HT-in-x86_cpu_expand_features-.patch b/1220-i386-cpu-Set-up-CPUID_HT-in-x86_cpu_expand_features-.patch new file mode 100644 index 0000000000000000000000000000000000000000..a0ba31c559ebc4d7a62d032998d92b6c392febf7 --- /dev/null +++ b/1220-i386-cpu-Set-up-CPUID_HT-in-x86_cpu_expand_features-.patch @@ -0,0 +1,54 @@ +From a3d4dc2f33c3993ad4ab9ea208a6aaafcc66972c Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:24 -0500 +Subject: [PATCH 42/83] i386/cpu: Set up CPUID_HT in x86_cpu_expand_features() + instead of cpu_x86_cpuid() + +commit c6bd2dd634208ca717b6dc010064fe34d1359080 upstream. + +Currently CPUID_HT is evaluated in cpu_x86_cpuid() each time. It's not a +correct usage of how feature bit is maintained and evaluated. The +expected practice is that features are tracked in env->features[] and +cpu_x86_cpuid() should be the consumer of env->features[]. + +Track CPUID_HT in env->features[FEAT_1_EDX] instead and evaluate it in +cpu's realizefn(). + +Intel-SIG: commit c6bd2dd63420 i386/cpu: Set up CPUID_HT in x86_cpu_expand_features() instead of cpu_x86_cpuid(). +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Link: https://lore.kernel.org/r/20241219110125.1266461-10-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e283e6e6392..be4010e303e 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6857,7 +6857,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *edx = env->features[FEAT_1_EDX]; + if (threads_per_pkg > 1) { + *ebx |= threads_per_pkg << 16; +- *edx |= CPUID_HT; + } + if (!cpu->enable_pmu) { + *ecx &= ~CPUID_EXT_PDCM; +@@ -7845,6 +7844,10 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + } + } + ++ if (x86_threads_per_pkg(&env->topo_info) > 1) { ++ env->features[FEAT_1_EDX] |= CPUID_HT; ++ } ++ + for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) { + FeatureDep *d = &feature_dependencies[i]; + if (!(env->features[d->from.index] & d->from.mask)) { +-- +2.47.3 + diff --git a/1221-i386-cpu-Set-and-track-CPUID_EXT3_CMP_LEG-in-env-fea.patch b/1221-i386-cpu-Set-and-track-CPUID_EXT3_CMP_LEG-in-env-fea.patch new file mode 100644 index 0000000000000000000000000000000000000000..df055156d236c088d3198015b15d5fd7cdded34e --- /dev/null +++ b/1221-i386-cpu-Set-and-track-CPUID_EXT3_CMP_LEG-in-env-fea.patch @@ -0,0 +1,64 @@ +From 64b6e188d47b519a81126bf6c918bac427688b35 Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 19 Dec 2024 06:01:25 -0500 +Subject: [PATCH 43/83] i386/cpu: Set and track CPUID_EXT3_CMP_LEG in + env->features[FEAT_8000_0001_ECX] + +commit 99a637a86f55c8486b06c698656befdf012eec4d upstream. + +The correct usage is tracking and maintaining features in env->features[] +instead of manually set it in cpu_x86_cpuid(). + +Intel-SIG: commit 99a637a86f55 i386/cpu: Set and track CPUID_EXT3_CMP_LEG in env->features[FEAT_8000_0001_ECX]. +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Link: https://lore.kernel.org/r/20241219110125.1266461-11-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index be4010e303e..36ade2c2b67 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7287,17 +7287,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *ecx = env->features[FEAT_8000_0001_ECX]; + *edx = env->features[FEAT_8000_0001_EDX]; + +- /* The Linux kernel checks for the CMPLegacy bit and +- * discards multiple thread information if it is set. +- * So don't set it here for Intel to make Linux guests happy. +- */ +- if (threads_per_pkg > 1) { +- if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 || +- env->cpuid_vendor2 != CPUID_VENDOR_INTEL_2 || +- env->cpuid_vendor3 != CPUID_VENDOR_INTEL_3) { +- *ecx |= 1 << 1; /* CmpLegacy bit */ +- } +- } + if (tcg_enabled() && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && + !(env->hflags & HF_LMA_MASK)) { + *edx &= ~CPUID_EXT2_SYSCALL; +@@ -7846,6 +7835,15 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + + if (x86_threads_per_pkg(&env->topo_info) > 1) { + env->features[FEAT_1_EDX] |= CPUID_HT; ++ ++ /* ++ * The Linux kernel checks for the CMPLegacy bit and ++ * discards multiple thread information if it is set. ++ * So don't set it here for Intel to make Linux guests happy. ++ */ ++ if (!IS_INTEL_CPU(env)) { ++ env->features[FEAT_8000_0001_ECX] |= CPUID_EXT3_CMP_LEG; ++ } + } + + for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) { +-- +2.47.3 + diff --git a/1222-hw-core-machine-Reject-thread-level-cache.patch b/1222-hw-core-machine-Reject-thread-level-cache.patch new file mode 100644 index 0000000000000000000000000000000000000000..af820970143d8c406200553d19fe2d99db22c2fd --- /dev/null +++ b/1222-hw-core-machine-Reject-thread-level-cache.patch @@ -0,0 +1,62 @@ +From 000fc8b5a7ce098722933002cfebca201b25cd85 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 10 Jan 2025 22:51:11 +0800 +Subject: [PATCH 44/83] hw/core/machine: Reject thread level cache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 0d2d00e57a55d3d8205923e60c2553d83d288ebb upstream. + +Currently, neither i386 nor ARM have real hardware support for per- +thread cache, and there is no clear demand for this specific cache +topology. + +Additionally, since ARM even can't support this special cache topology +in device tree, it is unnecessary to support it at this moment, even +though per-thread cache might have potential scheduling benefits for +VMs without CPU affinity. + +Therefore, disable thread-level cache topology in the general machine +part. At present, i386 has not enabled SMP cache, so disabling the +thread parameter does not pose compatibility issues. + +In the future, if there is a clear demand for this feature, the correct +approach would be to add a new control field in MachineClass.smp_props +and enable it only for the machines that require it. + +Intel-SIG: commit 0d2d00e57a55 hw/core/machine: Reject thread level cache. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Philippe Mathieu-Daudé +Message-ID: <20250110145115.1574345-2-zhao1.liu@intel.com> +Signed-off-by: Philippe Mathieu-Daudé +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index aea5bb53e35..96200e3153d 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -350,6 +350,13 @@ bool machine_parse_smp_cache(MachineState *ms, + return false; + } + ++ if (props->topology == CPU_TOPOLOGY_LEVEL_THREAD) { ++ error_setg(errp, ++ "%s level cache not supported by this machine", ++ CpuTopologyLevel_str(props->topology)); ++ return false; ++ } ++ + if (!machine_check_topo_support(ms, props->topology, errp)) { + return false; + } +-- +2.47.3 + diff --git a/1223-i386-pc-Support-cache-topology-in-machine-for-PC-mac.patch b/1223-i386-pc-Support-cache-topology-in-machine-for-PC-mac.patch new file mode 100644 index 0000000000000000000000000000000000000000..bec44ff368d751f288e5a7976c6104878cd6d408 --- /dev/null +++ b/1223-i386-pc-Support-cache-topology-in-machine-for-PC-mac.patch @@ -0,0 +1,96 @@ +From 8320970ef7ee52519cbe3839a523cff80c8ea637 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 10 Jan 2025 22:51:14 +0800 +Subject: [PATCH 45/83] i386/pc: Support cache topology in -machine for PC + machine + +commit 90df2cac3700188acadd12948fdad8e9b1459646 upstream. + +Allow user to configure l1d, l1i, l2 and l3 cache topologies for PC +machine. + +Additionally, add the document of "-machine smp-cache" in +qemu-options.hx. + +Intel-SIG: commit 90df2cac3700 i386/pc: Support cache topology in -machine for PC machine. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Tested-by: Yongwei Ma +Reviewed-by: Jonathan Cameron +Reviewed-by: Michael S. Tsirkin +Link: https://lore.kernel.org/r/20250110145115.1574345-5-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/pc.c | 4 ++++ + qemu-options.hx | 30 +++++++++++++++++++++++++++++- + 2 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index 03fb5ce1494..a1b4b0360fb 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -1977,6 +1977,10 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) + mc->nvdimm_supported = true; + mc->smp_props.dies_supported = true; + mc->smp_props.modules_supported = true; ++ 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->default_ram_id = "pc.ram"; + pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64; + +diff --git a/qemu-options.hx b/qemu-options.hx +index 1be7ee39a2a..725cc7d3538 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -37,7 +37,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ + " memory-encryption=@var{} memory encryption object to use (default=none)\n" + " hmat=on|off controls ACPI HMAT support (default=off)\n" + " memory-backend='backend-id' specifies explicitly provided backend for main RAM (default=none)\n" +- " cxl-fmw.0.targets.0=firsttarget,cxl-fmw.0.targets.1=secondtarget,cxl-fmw.0.size=size[,cxl-fmw.0.interleave-granularity=granularity]\n", ++ " cxl-fmw.0.targets.0=firsttarget,cxl-fmw.0.targets.1=secondtarget,cxl-fmw.0.size=size[,cxl-fmw.0.interleave-granularity=granularity]\n" ++ " smp-cache.0.cache=cachename,smp-cache.0.topology=topologylevel\n", + QEMU_ARCH_ALL) + SRST + ``-machine [type=]name[,prop=value[,...]]`` +@@ -157,6 +158,33 @@ SRST + :: + + -machine cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=128G,cxl-fmw.0.interleave-granularity=512k ++ ++ ``smp-cache.0.cache=cachename,smp-cache.0.topology=topologylevel`` ++ Define cache properties for SMP system. ++ ++ ``cache=cachename`` specifies the cache that the properties will be ++ applied on. This field is the combination of cache level and cache ++ type. It supports ``l1d`` (L1 data cache), ``l1i`` (L1 instruction ++ cache), ``l2`` (L2 unified cache) and ``l3`` (L3 unified cache). ++ ++ ``topology=topologylevel`` sets the cache topology level. It accepts ++ CPU topology levels including ``core``, ``module``, ``cluster``, ``die``, ++ ``socket``, ``book``, ``drawer`` and a special value ``default``. If ++ ``default`` is set, then the cache topology will follow the architecture's ++ default cache topology model. If another topology level is set, the cache ++ will be shared at corresponding CPU topology level. For example, ++ ``topology=core`` makes the cache shared by all threads within a core. ++ The omitting cache will default to using the ``default`` level. ++ ++ The default cache topology model for an i386 PC machine is as follows: ++ ``l1d``, ``l1i``, and ``l2`` caches are per ``core``, while the ``l3`` ++ cache is per ``die``. ++ ++ Example: ++ ++ :: ++ ++ -machine smp-cache.0.cache=l1d,smp-cache.0.topology=core,smp-cache.1.cache=l1i,smp-cache.1.topology=core + ERST + + DEF("M", HAS_ARG, QEMU_OPTION_M, +-- +2.47.3 + diff --git a/1224-i386-cpu-Update-cache-topology-with-machine-s-config.patch b/1224-i386-cpu-Update-cache-topology-with-machine-s-config.patch new file mode 100644 index 0000000000000000000000000000000000000000..a2202c71d1f2ea5c2887cbb35ff0716e8131e04f --- /dev/null +++ b/1224-i386-cpu-Update-cache-topology-with-machine-s-config.patch @@ -0,0 +1,116 @@ +From 5ca86b19ccd964cddd487d7b3869be053ee50154 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 10 Jan 2025 22:51:13 +0800 +Subject: [PATCH 46/83] i386/cpu: Update cache topology with machine's + configuration + +commit 5ca9282d25157004601c520ed59dcb380177f728 upstream. + +User will configure smp cache topology via -machine smp-cache. + +For this case, update the x86 CPUs' cache topology with user's +configuration in MachineState. + +Intel-SIG: commit 5ca9282d2515 i386/cpu: Update cache topology with machine's configuration. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Tested-by: Yongwei Ma +Reviewed-by: Jonathan Cameron +Reviewed-by: Michael S. Tsirkin +Link: https://lore.kernel.org/r/20250110145115.1574345-4-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 67 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 36ade2c2b67..90e62ae1533 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -8060,6 +8060,64 @@ static void x86_cpu_hyperv_realize(X86CPU *cpu) + cpu->hyperv_limits[2] = 0; + } + ++#ifndef CONFIG_USER_ONLY ++static bool x86_cpu_update_smp_cache_topo(MachineState *ms, X86CPU *cpu, ++ Error **errp) ++{ ++ CPUX86State *env = &cpu->env; ++ CpuTopologyLevel level; ++ ++ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D); ++ if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) { ++ env->cache_info_cpuid4.l1d_cache->share_level = level; ++ env->cache_info_amd.l1d_cache->share_level = level; ++ } else { ++ machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D, ++ env->cache_info_cpuid4.l1d_cache->share_level); ++ machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D, ++ env->cache_info_amd.l1d_cache->share_level); ++ } ++ ++ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I); ++ if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) { ++ env->cache_info_cpuid4.l1i_cache->share_level = level; ++ env->cache_info_amd.l1i_cache->share_level = level; ++ } else { ++ machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I, ++ env->cache_info_cpuid4.l1i_cache->share_level); ++ machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I, ++ env->cache_info_amd.l1i_cache->share_level); ++ } ++ ++ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2); ++ if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) { ++ env->cache_info_cpuid4.l2_cache->share_level = level; ++ env->cache_info_amd.l2_cache->share_level = level; ++ } else { ++ machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2, ++ env->cache_info_cpuid4.l2_cache->share_level); ++ machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2, ++ env->cache_info_amd.l2_cache->share_level); ++ } ++ ++ level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3); ++ if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) { ++ env->cache_info_cpuid4.l3_cache->share_level = level; ++ env->cache_info_amd.l3_cache->share_level = level; ++ } else { ++ machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3, ++ env->cache_info_cpuid4.l3_cache->share_level); ++ machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3, ++ env->cache_info_amd.l3_cache->share_level); ++ } ++ ++ if (!machine_check_smp_cache(ms, errp)) { ++ return false; ++ } ++ return true; ++} ++#endif ++ + static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + { + CPUState *cs = CPU(dev); +@@ -8302,6 +8360,15 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + + #ifndef CONFIG_USER_ONLY + MachineState *ms = MACHINE(qdev_get_machine()); ++ ++ /* ++ * TODO: Add a SMPCompatProps.has_caches flag to avoid useless updates ++ * if user didn't set smp_cache. ++ */ ++ if (!x86_cpu_update_smp_cache_topo(ms, cpu, errp)) { ++ return; ++ } ++ + qemu_register_reset(x86_cpu_machine_reset_cb, cpu); + + if (cpu->env.features[FEAT_1_EDX] & CPUID_APIC || ms->smp.cpus > 1) { +-- +2.47.3 + diff --git a/1225-i386-cpu-add-has_caches-flag-to-check-smp_cache-conf.patch b/1225-i386-cpu-add-has_caches-flag-to-check-smp_cache-conf.patch new file mode 100644 index 0000000000000000000000000000000000000000..48584625538f6dbb95649cf90b92cd5a581c99ba --- /dev/null +++ b/1225-i386-cpu-add-has_caches-flag-to-check-smp_cache-conf.patch @@ -0,0 +1,89 @@ +From 80988b252f4d11ae4f8855b8c27418dc73feedb2 Mon Sep 17 00:00:00 2001 +From: Alireza Sanaee +Date: Fri, 10 Jan 2025 22:51:15 +0800 +Subject: [PATCH 47/83] i386/cpu: add has_caches flag to check smp_cache + configuration + +commit 47fc56f36d333263a5865caad306336e3e61e348 upstream. + +Add has_caches flag to SMPCompatProps, which helps in avoiding +extra checks for every single layer of caches in x86 (and ARM in +future). + +Intel-SIG: commit 47fc56f36d33 i386/cpu: add has_caches flag to check smp_cache configuration. +CPU new topology backporting + +Signed-off-by: Alireza Sanaee +Signed-off-by: Zhao Liu +Reviewed-by: Jonathan Cameron +Reviewed-by: Michael S. Tsirkin +Link: https://lore.kernel.org/r/20250110145115.1574345-6-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/core/machine-smp.c | 2 ++ + include/hw/boards.h | 3 +++ + target/i386/cpu.c | 11 +++++------ + 3 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c +index 96200e3153d..50b8b0bc4ad 100644 +--- a/hw/core/machine-smp.c ++++ b/hw/core/machine-smp.c +@@ -361,6 +361,8 @@ bool machine_parse_smp_cache(MachineState *ms, + return false; + } + } ++ ++ mc->smp_props.has_caches = true; + return true; + } + +diff --git a/include/hw/boards.h b/include/hw/boards.h +index cda7a647dbf..9e7aa736379 100644 +--- a/include/hw/boards.h ++++ b/include/hw/boards.h +@@ -148,6 +148,8 @@ typedef struct { + * @modules_supported - whether modules are supported by the machine + * @cache_supported - whether cache (l1d, l1i, l2 and l3) configuration are + * supported by the machine ++ * @has_caches - whether cache properties are explicitly specified in the ++ * user provided smp-cache configuration + */ + typedef struct { + bool prefer_sockets; +@@ -158,6 +160,7 @@ typedef struct { + bool drawers_supported; + bool modules_supported; + bool cache_supported[CACHE_LEVEL_AND_TYPE__MAX]; ++ bool has_caches; + } SMPCompatProps; + + /** +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 90e62ae1533..db70c335b99 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -8360,13 +8360,12 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + + #ifndef CONFIG_USER_ONLY + MachineState *ms = MACHINE(qdev_get_machine()); ++ MachineClass *mc = MACHINE_GET_CLASS(ms); + +- /* +- * TODO: Add a SMPCompatProps.has_caches flag to avoid useless updates +- * if user didn't set smp_cache. +- */ +- if (!x86_cpu_update_smp_cache_topo(ms, cpu, errp)) { +- return; ++ if (mc->smp_props.has_caches) { ++ if (!x86_cpu_update_smp_cache_topo(ms, cpu, errp)) { ++ return; ++ } + } + + qemu_register_reset(x86_cpu_machine_reset_cb, cpu); +-- +2.47.3 + diff --git a/1226-i386-cpu-Support-module-level-cache-topology.patch b/1226-i386-cpu-Support-module-level-cache-topology.patch new file mode 100644 index 0000000000000000000000000000000000000000..5a29900b0bcc95073f385c75b05925d29a063ff4 --- /dev/null +++ b/1226-i386-cpu-Support-module-level-cache-topology.patch @@ -0,0 +1,51 @@ +From dc2ed17daefc9c3c4a85f7117d0d1020349f2292 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 10 Jan 2025 22:51:12 +0800 +Subject: [PATCH 48/83] i386/cpu: Support module level cache topology + +commit 2152b4bfcd91d7d8b99cd502ed049b0ab8e38649 upstream. + +Allow cache to be defined at the module level. This increases +flexibility for x86 users to customize their cache topology. + +Intel-SIG: commit 2152b4bfcd91 i386/cpu: Support module level cache topology. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Tested-by: Yongwei Ma +Reviewed-by: Jonathan Cameron +Reviewed-by: Michael S. Tsirkin +Link: https://lore.kernel.org/r/20250110145115.1574345-3-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index db70c335b99..ec9c671e12f 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -248,6 +248,9 @@ static uint32_t max_thread_ids_for_cache(X86CPUTopoInfo *topo_info, + case CPU_TOPOLOGY_LEVEL_CORE: + num_ids = 1 << apicid_core_offset(topo_info); + break; ++ case CPU_TOPOLOGY_LEVEL_MODULE: ++ num_ids = 1 << apicid_module_offset(topo_info); ++ break; + case CPU_TOPOLOGY_LEVEL_DIE: + num_ids = 1 << apicid_die_offset(topo_info); + break; +@@ -256,7 +259,7 @@ static uint32_t max_thread_ids_for_cache(X86CPUTopoInfo *topo_info, + break; + default: + /* +- * Currently there is no use case for THREAD and MODULE, so use ++ * Currently there is no use case for THREAD, so use + * assert directly to facilitate debugging. + */ + g_assert_not_reached(); +-- +2.47.3 + diff --git a/1227-i386-cpu-Introduce-enable_cpuid_0x1f-to-force-exposi.patch b/1227-i386-cpu-Introduce-enable_cpuid_0x1f-to-force-exposi.patch new file mode 100644 index 0000000000000000000000000000000000000000..4f6acb27e751aae0ccf4f3cee733fa6991800648 --- /dev/null +++ b/1227-i386-cpu-Introduce-enable_cpuid_0x1f-to-force-exposi.patch @@ -0,0 +1,102 @@ +From ede35129021bf232d6a89767b4600c1fdb57dacc Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Thu, 8 May 2025 10:59:39 -0400 +Subject: [PATCH 49/83] i386/cpu: Introduce enable_cpuid_0x1f to force exposing + CPUID 0x1f + +commit ab8bd85adf75900edc2764d0ebe8b53867cc54aa upstream. + +Currently, QEMU exposes CPUID 0x1f to guest only when necessary, i.e., +when topology level that cannot be enumerated by leaf 0xB, e.g., die or +module level, are configured for the guest, e.g., -smp xx,dies=2. + +However, TDX architecture forces to require CPUID 0x1f to configure CPU +topology. + +Introduce a bool flag, enable_cpuid_0x1f, in CPU for the case that +requires CPUID leaf 0x1f to be exposed to guest. + +Introduce a new function x86_has_cpuid_0x1f(), which is the wrapper of +cpu->enable_cpuid_0x1f and x86_has_extended_topo() to check if it needs +to enable cpuid leaf 0x1f for the guest. + +Intel-SIG: commit ab8bd85adf75 i386/cpu: Introduce enable_cpuid_0x1f to force exposing CPUID 0x1f. +CPU new topology backporting + +Signed-off-by: Xiaoyao Li +Reviewed-by: Zhao Liu +Link: https://lore.kernel.org/r/20250508150002.689633-34-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 4 ++-- + target/i386/cpu.h | 9 +++++++++ + target/i386/kvm/kvm.c | 2 +- + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ec9c671e12f..9b538f2159c 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7064,7 +7064,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 0x1F: + /* V2 Extended Topology Enumeration Leaf */ +- if (!x86_has_extended_topo(env->avail_cpu_topo)) { ++ if (!x86_has_cpuid_0x1f(cpu)) { + *eax = *ebx = *ecx = *edx = 0; + break; + } +@@ -7905,7 +7905,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) + * cpu->vendor_cpuid_only has been unset for compatibility with older + * machine types. + */ +- if (x86_has_extended_topo(env->avail_cpu_topo) && ++ if (x86_has_cpuid_0x1f(cpu) && + (IS_INTEL_CPU(env) || !cpu->vendor_cpuid_only)) { + x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F); + } +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 1aa42f6f832..dffba3a5312 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2105,6 +2105,9 @@ struct ArchCPU { + /* Compatibility bits for old machine types: */ + bool enable_cpuid_0xb; + ++ /* Force to enable cpuid 0x1f */ ++ bool enable_cpuid_0x1f; ++ + /* Enable auto level-increase for all CPUID leaves */ + bool full_cpuid_auto_level; + +@@ -2362,6 +2365,12 @@ void cpu_clear_apic_feature(CPUX86State *env); + void host_cpuid(uint32_t function, uint32_t count, + uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); + ++static inline bool x86_has_cpuid_0x1f(X86CPU *cpu) ++{ ++ return cpu->enable_cpuid_0x1f || ++ x86_has_extended_topo(cpu->env.avail_cpu_topo); ++} ++ + /* helper.c */ + void x86_cpu_set_a20(X86CPU *cpu, int a20_state); + void cpu_sync_avx_hflag(CPUX86State *env); +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index 7482001c3bd..72e06fbbef7 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -1925,7 +1925,7 @@ int kvm_arch_init_vcpu(CPUState *cs) + break; + } + case 0x1f: +- if (!x86_has_extended_topo(env->avail_cpu_topo)) { ++ if (!x86_has_cpuid_0x1f(env_archcpu(env))) { + cpuid_i--; + break; + } +-- +2.47.3 + diff --git a/1228-i386-cpu-Rename-enable_cpuid_0x1f-to-force_cpuid_0x1.patch b/1228-i386-cpu-Rename-enable_cpuid_0x1f-to-force_cpuid_0x1.patch new file mode 100644 index 0000000000000000000000000000000000000000..6820f0bae5e2149b750728a468d97327db88d386 --- /dev/null +++ b/1228-i386-cpu-Rename-enable_cpuid_0x1f-to-force_cpuid_0x1.patch @@ -0,0 +1,55 @@ +From ebcaef305fb93136f00f28553db5461a74bf62de Mon Sep 17 00:00:00 2001 +From: Xiaoyao Li +Date: Tue, 3 Jun 2025 01:03:03 -0400 +Subject: [PATCH 50/83] i386/cpu: Rename enable_cpuid_0x1f to force_cpuid_0x1f +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 90d2bbd1f6edfa22a056070ee62ded55099cd56d upstream. + +The name of "enable_cpuid_0x1f" isn't right to its behavior because the +leaf 0x1f can be enabled even when "enable_cpuid_0x1f" is false. + +Rename it to "force_cpuid_0x1f" to better reflect its behavior. + +Intel-SIG: commit 90d2bbd1f6ed i386/cpu: Rename enable_cpuid_0x1f to force_cpuid_0x1f. +CPU new topology backporting + +Suggested-by: Igor Mammedov +Signed-off-by: Xiaoyao Li +Reviewed-by: Daniel P. Berrangé +Reviewed-by: Igor Mammedov +Link: https://lore.kernel.org/r/20250603050305.1704586-2-xiaoyao.li@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index dffba3a5312..1eddd7ea2d1 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2106,7 +2106,7 @@ struct ArchCPU { + bool enable_cpuid_0xb; + + /* Force to enable cpuid 0x1f */ +- bool enable_cpuid_0x1f; ++ bool force_cpuid_0x1f; + + /* Enable auto level-increase for all CPUID leaves */ + bool full_cpuid_auto_level; +@@ -2367,7 +2367,7 @@ void host_cpuid(uint32_t function, uint32_t count, + + static inline bool x86_has_cpuid_0x1f(X86CPU *cpu) + { +- return cpu->enable_cpuid_0x1f || ++ return cpu->force_cpuid_0x1f || + x86_has_extended_topo(cpu->env.avail_cpu_topo); + } + +-- +2.47.3 + diff --git a/1229-i386-cpu-Refine-comment-of-CPUID2CacheDescriptorInfo.patch b/1229-i386-cpu-Refine-comment-of-CPUID2CacheDescriptorInfo.patch new file mode 100644 index 0000000000000000000000000000000000000000..1920240d3b093aeeef6084290ccf188af9d64db1 --- /dev/null +++ b/1229-i386-cpu-Refine-comment-of-CPUID2CacheDescriptorInfo.patch @@ -0,0 +1,89 @@ +From 990a15eff6905172b8ac0ffdfcd162e1d90971b5 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:26 +0800 +Subject: [PATCH 51/83] i386/cpu: Refine comment of CPUID2CacheDescriptorInfo + +commit 1034b94fe98da35857f261d4db89ce2ebed8c5c3 upstream. + +Refer to SDM vol.3 table 1-21, add the notes about the missing +descriptor, and fix the typo and comment format. + +Intel-SIG: commit 1034b94fe98d i386/cpu: Refine comment of CPUID2CacheDescriptorInfo. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-2-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 31 ++++++++++++++++++++++--------- + 1 file changed, 22 insertions(+), 9 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 9b538f2159c..2ddb38c0308 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -64,6 +64,7 @@ struct CPUID2CacheDescriptorInfo { + + /* + * Known CPUID 2 cache descriptors. ++ * TLB, prefetch and sectored cache related descriptors are not included. + * From Intel SDM Volume 2A, CPUID instruction + */ + struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = { +@@ -85,18 +86,29 @@ struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = { + .associativity = 2, .line_size = 64, }, + [0x21] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, + .associativity = 8, .line_size = 64, }, +- /* lines per sector is not supported cpuid2_cache_descriptor(), +- * so descriptors 0x22, 0x23 are not included +- */ ++ /* ++ * lines per sector is not supported cpuid2_cache_descriptor(), ++ * so descriptors 0x22, 0x23 are not included ++ */ + [0x24] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 16, .line_size = 64, }, +- /* lines per sector is not supported cpuid2_cache_descriptor(), +- * so descriptors 0x25, 0x20 are not included +- */ ++ /* ++ * lines per sector is not supported cpuid2_cache_descriptor(), ++ * so descriptors 0x25, 0x29 are not included ++ */ + [0x2C] = { .level = 1, .type = DATA_CACHE, .size = 32 * KiB, + .associativity = 8, .line_size = 64, }, + [0x30] = { .level = 1, .type = INSTRUCTION_CACHE, .size = 32 * KiB, + .associativity = 8, .line_size = 64, }, ++ /* ++ * Newer Intel CPUs (having the cores without L3, e.g., Intel MTL, ARL) ++ * use CPUID 0x4 leaf to describe cache topology, by encoding CPUID 0x2 ++ * leaf with 0xFF. For older CPUs (without 0x4 leaf), it's also valid ++ * to just ignore L3's code if there's no L3. ++ * ++ * This already covers all the cases in QEMU, so code 0x40 is not ++ * included. ++ */ + [0x41] = { .level = 2, .type = UNIFIED_CACHE, .size = 128 * KiB, + .associativity = 4, .line_size = 32, }, + [0x42] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, +@@ -134,9 +146,10 @@ struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = { + .associativity = 4, .line_size = 64, }, + [0x78] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 4, .line_size = 64, }, +- /* lines per sector is not supported cpuid2_cache_descriptor(), +- * so descriptors 0x79, 0x7A, 0x7B, 0x7C are not included. +- */ ++ /* ++ * lines per sector is not supported cpuid2_cache_descriptor(), ++ * so descriptors 0x79, 0x7A, 0x7B, 0x7C are not included. ++ */ + [0x7D] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, + .associativity = 8, .line_size = 64, }, + [0x7F] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, +-- +2.47.3 + diff --git a/1230-i386-cpu-Add-descriptor-0x49-for-CPUID-0x2-encoding.patch b/1230-i386-cpu-Add-descriptor-0x49-for-CPUID-0x2-encoding.patch new file mode 100644 index 0000000000000000000000000000000000000000..b39c71050e4b1302eaec5e9633ee7b2144ea777f --- /dev/null +++ b/1230-i386-cpu-Add-descriptor-0x49-for-CPUID-0x2-encoding.patch @@ -0,0 +1,58 @@ +From 7f6614fb44ef590b190cf74e81654a0db40cc972 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:27 +0800 +Subject: [PATCH 52/83] i386/cpu: Add descriptor 0x49 for CPUID 0x2 encoding + +commit 67d54014afcfdd316a0e9c979a0ff8145d4cf963 upstream. + +The legacy_l2_cache (2nd-level cache: 4 MByte, 16-way set associative, +64 byte line size) corresponds to descriptor 0x49, but at present +cpuid2_cache_descriptors doesn't support descriptor 0x49 because it has +multiple meanings. + +The 0x49 is necessary when CPUID 0x2 and 0x4 leaves have the consistent +cache model, and use legacy_l2_cache as the default L2 cache. + +Therefore, add descriptor 0x49 to represent general L2 cache. + +Intel-SIG: commit 67d54014afcf i386/cpu: Add descriptor 0x49 for CPUID 0x2 encoding. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-3-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 2ddb38c0308..f86e1f7921b 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -125,7 +125,18 @@ struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = { + .associativity = 8, .line_size = 64, }, + [0x48] = { .level = 2, .type = UNIFIED_CACHE, .size = 3 * MiB, + .associativity = 12, .line_size = 64, }, +- /* Descriptor 0x49 depends on CPU family/model, so it is not included */ ++ /* ++ * Descriptor 0x49 has 2 cases: ++ * - 2nd-level cache: 4 MByte, 16-way set associative, 64 byte line size. ++ * - 3rd-level cache: 4MB, 16-way set associative, 64-byte line size ++ * (Intel Xeon processor MP, Family 0FH, Model 06H). ++ * ++ * When it represents L3, then it depends on CPU family/model. Fortunately, ++ * the legacy cache/CPU models don't have such special L3. So, just add it ++ * to represent the general L2 case. ++ */ ++ [0x49] = { .level = 2, .type = UNIFIED_CACHE, .size = 4 * MiB, ++ .associativity = 16, .line_size = 64, }, + [0x4A] = { .level = 3, .type = UNIFIED_CACHE, .size = 6 * MiB, + .associativity = 12, .line_size = 64, }, + [0x4B] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, +-- +2.47.3 + diff --git a/1231-i386-cpu-Add-default-cache-model-for-Intel-CPUs-with.patch b/1231-i386-cpu-Add-default-cache-model-for-Intel-CPUs-with.patch new file mode 100644 index 0000000000000000000000000000000000000000..faf9ed3a4c6e1698980f41fab7d19d6395d51b55 --- /dev/null +++ b/1231-i386-cpu-Add-default-cache-model-for-Intel-CPUs-with.patch @@ -0,0 +1,162 @@ +From 1c0c60c8808ac34aeaa4e95e11e7a880d085ee9e Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:28 +0800 +Subject: [PATCH 53/83] i386/cpu: Add default cache model for Intel CPUs with + level < 4 + +commit 2c70a50c8c3d8620f34884b340778358b6faf5d4 upstream. + +Old Intel CPUs with CPUID level < 4, use CPUID 0x2 leaf (if available) +to encode cache information. + +Introduce a cache model "legacy_intel_cpuid2_cache_info" for the CPUs +with CPUID level < 4, based on legacy_l1d_cache, legacy_l1i_cache, +legacy_l2_cache_cpuid2 and legacy_l3_cache. But for L2 cache, this +cache model completes self_init, sets, partitions, no_invd_sharing and +share_level fields, referring legacy_l2_cache, to avoid someone +increases CPUID level manually and meets assert() error. But the cache +information present in CPUID 0x2 leaf doesn't change. + +This new cache model makes it possible to remove legacy_l2_cache_cpuid2 +in X86CPUState and help to clarify historical cache inconsistency issue. + +Furthermore, apply this legacy cache model to all Intel CPUs with CPUID +level < 4. This includes not only "pentium2" and "pentium3" (which have +0x2 leaf), but also "486" and "pentium" (which only have 0x1 leaf, and +cache model won't be presented, just for simplicity). + +A legacy_intel_cpuid2_cache_info cache model doesn't change the cache +information of the above CPUs, because they just depend on 0x2 leaf. + +Only when someone adjusts the min-level to >=4 will the cache +information in CPUID leaf 4 differ from before: previously, the L2 +cache information in CPUID leaf 0x2 and 0x4 was different, but now with +legacy_intel_cpuid2_cache_info, the information they present will be +consistent. This case almost never happens, emulating a CPUID that is +not supported by the "ancient" hardware is itself meaningless behavior. + +Therefore, even though there's the above difference (for really rare +case) and considering these old CPUs ("486", "pentium", "pentium2" and +"pentium3") won't be used for migration, there's no need to add new +versioned CPU models + +Intel-SIG: commit 2c70a50c8c3d i386/cpu: Add default cache model for Intel CPUs with level < 4. +CPU new topology backporting + +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-4-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 65 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index f86e1f7921b..14cda527eb6 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -707,6 +707,67 @@ static CPUCacheInfo legacy_l3_cache = { + .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }; + ++/* ++ * Only used for the CPU models with CPUID level < 4. ++ * These CPUs (CPUID level < 4) only use CPUID leaf 2 to present ++ * cache information. ++ * ++ * Note: This cache model is just a default one, and is not ++ * guaranteed to match real hardwares. ++ */ ++static const CPUCaches legacy_intel_cpuid2_cache_info = { ++ .l1d_cache = &(CPUCacheInfo) { ++ .type = DATA_CACHE, ++ .level = 1, ++ .size = 32 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 8, ++ .sets = 64, ++ .partitions = 1, ++ .no_invd_sharing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l1i_cache = &(CPUCacheInfo) { ++ .type = INSTRUCTION_CACHE, ++ .level = 1, ++ .size = 32 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 8, ++ .sets = 64, ++ .partitions = 1, ++ .no_invd_sharing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l2_cache = &(CPUCacheInfo) { ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .size = 2 * MiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 8, ++ .sets = 4096, ++ .partitions = 1, ++ .no_invd_sharing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l3_cache = &(CPUCacheInfo) { ++ .type = UNIFIED_CACHE, ++ .level = 3, ++ .size = 16 * MiB, ++ .line_size = 64, ++ .associativity = 16, ++ .sets = 16384, ++ .partitions = 1, ++ .lines_per_tag = 1, ++ .self_init = true, ++ .inclusive = true, ++ .complex_indexing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, ++ }, ++}; ++ + /* TLB definitions: */ + + #define L1_DTLB_2M_ASSOC 1 +@@ -2757,6 +2818,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { + I486_FEATURES, + .xlevel = 0, + .model_id = "", ++ .cache_info = &legacy_intel_cpuid2_cache_info, + }, + { + .name = "pentium", +@@ -2769,6 +2831,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { + PENTIUM_FEATURES, + .xlevel = 0, + .model_id = "", ++ .cache_info = &legacy_intel_cpuid2_cache_info, + }, + { + .name = "pentium2", +@@ -2781,6 +2844,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { + PENTIUM2_FEATURES, + .xlevel = 0, + .model_id = "", ++ .cache_info = &legacy_intel_cpuid2_cache_info, + }, + { + .name = "pentium3", +@@ -2793,6 +2857,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { + PENTIUM3_FEATURES, + .xlevel = 0, + .model_id = "", ++ .cache_info = &legacy_intel_cpuid2_cache_info, + }, + { + .name = "athlon", +-- +2.47.3 + diff --git a/1232-i386-cpu-Present-same-cache-model-in-CPUID-0x2-0x4.patch b/1232-i386-cpu-Present-same-cache-model-in-CPUID-0x2-0x4.patch new file mode 100644 index 0000000000000000000000000000000000000000..d172f67362350ab738568dabea2d1058560240c1 --- /dev/null +++ b/1232-i386-cpu-Present-same-cache-model-in-CPUID-0x2-0x4.patch @@ -0,0 +1,125 @@ +From bf18bec892e8ccccf35ddd5422616ecd59d4eeeb Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:29 +0800 +Subject: [PATCH 54/83] i386/cpu: Present same cache model in CPUID 0x2 & 0x4 + +commit 6699e5dc864b0793e4fd90ef8038f6c71fcd0d47 upstream. + +For a long time, the default cache models used in CPUID 0x2 and +0x4 were inconsistent and had a FIXME note from Eduardo at commit +5e891bf8fd50 ("target-i386: Use #defines instead of magic numbers for +CPUID cache info"): + +"/*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */". + +This difference is wrong, in principle, both 0x2 and 0x4 are used for +Intel's cache description. 0x2 leaf is used for ancient machines while +0x4 leaf is a subsequent addition, and both should be based on the same +cache model. Furthermore, on real hardware, 0x4 leaf should be used in +preference to 0x2 when it is available. + +Revisiting the git history, that difference occurred much earlier. + +Current legacy_l2_cache_cpuid2 (hardcode: "0x2c307d"), which is used for +CPUID 0x2 leaf, is introduced in commit d8134d91d9b7 ("Intel cache info, +by Filip Navara."). Its commit message didn't said anything, but its +patch [1] mentioned the cache model chosen is "closest to the ones +reported in the AMD registers". Now it is not possible to check which +AMD generation this cache model is based on (unfortunately, AMD does not +use 0x2 leaf), but at least it is close to the Pentium 4. + +In fact, the patch description of commit d8134d91d9b7 is also a bit +wrong, the original cache model in leaf 2 is from Pentium Pro, and its +cache descriptor had specified the cache line size ad 32 byte by default, +while the updated cache model in commit d8134d91d9b7 has 64 byte line +size. But after so many years, such judgments are no longer meaningful. + +On the other hand, for legacy_l2_cache, which is used in CPUID 0x4 leaf, +is based on Intel Core Duo (patch [2]) and Core2 Duo (commit e737b32a3688 +("Core 2 Duo specification (Alexander Graf).") + +The patches of Core Duo and Core 2 Duo add the cache model for CPUID +0x4, but did not update CPUID 0x2 encoding. This is the reason that +Intel Guests use two cache models in 0x2 and 0x4 all the time. + +Of course, while no Core Duo or Core 2 Duo machines have been found for +double checking, this still makes no sense to encode different cache +models on a single machine. + +Referring to the SDM and the real hardware available, 0x2 leaf can be +directly encoded 0xFF to instruct software to go to 0x4 leaf to get the +cache information, when 0x4 is available. + +Therefore, it's time to clean up Intel's default cache models. As the +first step, add "x-consistent-cache" compat option to allow newer +machines (v10.1 and newer) to have the consistent cache model in CPUID +0x2 and 0x4 leaves. + +This doesn't affect the CPU models with CPUID level < 4 ("486", +"pentium", "pentium2" and "pentium3"), because they have already had the +special default cache model - legacy_intel_cpuid2_cache_info. + +[1]: https://lore.kernel.org/qemu-devel/5b31733c0709081227w3e5f1036odbc649edfdc8c79b@mail.gmail.com/ +[2]: https://lore.kernel.org/qemu-devel/478B65C8.2080602@csgraf.de/ + +Intel-SIG: commit 6699e5dc864b i386/cpu: Present same cache model in CPUID 0x2 & 0x4. +CPU new topology backporting + +Cc: Alexander Graf +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-5-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 7 ++++++- + target/i386/cpu.h | 7 +++++++ + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 14cda527eb6..e7254209104 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -8436,7 +8436,11 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + /* Build legacy cache information */ + env->cache_info_cpuid2.l1d_cache = &legacy_l1d_cache; + env->cache_info_cpuid2.l1i_cache = &legacy_l1i_cache; +- env->cache_info_cpuid2.l2_cache = &legacy_l2_cache_cpuid2; ++ if (!cpu->consistent_cache) { ++ env->cache_info_cpuid2.l2_cache = &legacy_l2_cache_cpuid2; ++ } else { ++ env->cache_info_cpuid2.l2_cache = &legacy_l2_cache; ++ } + env->cache_info_cpuid2.l3_cache = &legacy_l3_cache; + + env->cache_info_cpuid4.l1d_cache = &legacy_l1d_cache; +@@ -8954,6 +8958,7 @@ static Property x86_cpu_properties[] = { + * own cache information (see x86_cpu_load_def()). + */ + DEFINE_PROP_BOOL("legacy-cache", X86CPU, legacy_cache, true), ++ DEFINE_PROP_BOOL("x-consistent-cache", X86CPU, consistent_cache, true), + DEFINE_PROP_BOOL("xen-vapic", X86CPU, xen_vapic, false), + + /* +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 1eddd7ea2d1..85a7998730b 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2102,6 +2102,13 @@ struct ArchCPU { + */ + bool legacy_cache; + ++ /* ++ * Compatibility bits for old machine types. ++ * If true, use the same cache model in CPUID leaf 0x2 ++ * and 0x4. ++ */ ++ bool consistent_cache; ++ + /* Compatibility bits for old machine types: */ + bool enable_cpuid_0xb; + +-- +2.47.3 + diff --git a/1233-i386-cpu-Consolidate-CPUID-0x4-leaf.patch b/1233-i386-cpu-Consolidate-CPUID-0x4-leaf.patch new file mode 100644 index 0000000000000000000000000000000000000000..c3c1538e6d1fcb4b8877ce74517a81ccecf3ad88 --- /dev/null +++ b/1233-i386-cpu-Consolidate-CPUID-0x4-leaf.patch @@ -0,0 +1,116 @@ +From 445073b171e0d9a477310d65eb8afafd1acc9459 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:30 +0800 +Subject: [PATCH 55/83] i386/cpu: Consolidate CPUID 0x4 leaf + +commit fe77a78149359485459db26814af436cfc873afe upstream. + +Modern Intel CPUs use CPUID 0x4 leaf to describe cache information +and leave space in 0x2 for prefetch and TLBs (even TLB has its own leaf +CPUID 0x18). + +And 0x2 leaf provides a descriptor 0xFF to instruct software to check +cache information in 0x4 leaf instead. + +Therefore, follow this behavior to encode 0xFF when Intel CPU has 0x4 +leaf with "x-consistent-cache=true" for compatibility. + +In addition, for older CPUs without 0x4 leaf, still enumerate the cache +descriptor in 0x2 leaf, except the case that there's no descriptor +matching the cache model, then directly encode 0xFF in 0x2 leaf. This +makes sense, as in the 0x2 leaf era, all supported caches should have +the corresponding descriptor. + +Intel-SIG: commit fe77a7814935 i386/cpu: Consolidate CPUID 0x4 leaf. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-6-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 48 ++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 37 insertions(+), 11 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index e7254209104..93beaac1ac4 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -221,7 +221,7 @@ struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = { + * Return a CPUID 2 cache descriptor for a given cache. + * If no known descriptor is found, return CACHE_DESCRIPTOR_UNAVAILABLE + */ +-static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache) ++static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache, bool *unmacthed) + { + int i; + +@@ -238,9 +238,44 @@ static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache) + } + } + ++ *unmacthed |= true; + return CACHE_DESCRIPTOR_UNAVAILABLE; + } + ++/* Encode cache info for CPUID[2] */ ++static void encode_cache_cpuid2(X86CPU *cpu, ++ uint32_t *eax, uint32_t *ebx, ++ uint32_t *ecx, uint32_t *edx) ++{ ++ CPUX86State *env = &cpu->env; ++ CPUCaches *caches = &env->cache_info_cpuid2; ++ int l1d, l1i, l2, l3; ++ bool unmatched = false; ++ ++ *eax = 1; /* Number of CPUID[EAX=2] calls required */ ++ *ebx = *ecx = *edx = 0; ++ ++ l1d = cpuid2_cache_descriptor(caches->l1d_cache, &unmatched); ++ l1i = cpuid2_cache_descriptor(caches->l1i_cache, &unmatched); ++ l2 = cpuid2_cache_descriptor(caches->l2_cache, &unmatched); ++ l3 = cpuid2_cache_descriptor(caches->l3_cache, &unmatched); ++ ++ if (!cpu->consistent_cache || ++ (env->cpuid_min_level < 0x4 && !unmatched)) { ++ /* ++ * Though SDM defines code 0x40 for cases with no L2 or L3. It's ++ * also valid to just ignore l3's code if there's no l2. ++ */ ++ if (cpu->enable_l3_cache) { ++ *ecx = l3; ++ } ++ *edx = (l1d << 16) | (l1i << 8) | l2; ++ } else { ++ *ecx = 0; ++ *edx = CACHE_DESCRIPTOR_UNAVAILABLE; ++ } ++} ++ + /* CPUID Leaf 4 constants: */ + + /* EAX: */ +@@ -6963,16 +6998,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *eax = *ebx = *ecx = *edx = 0; + break; + } +- *eax = 1; /* Number of CPUID[EAX=2] calls required */ +- *ebx = 0; +- if (!cpu->enable_l3_cache) { +- *ecx = 0; +- } else { +- *ecx = cpuid2_cache_descriptor(env->cache_info_cpuid2.l3_cache); +- } +- *edx = (cpuid2_cache_descriptor(env->cache_info_cpuid2.l1d_cache) << 16) | +- (cpuid2_cache_descriptor(env->cache_info_cpuid2.l1i_cache) << 8) | +- (cpuid2_cache_descriptor(env->cache_info_cpuid2.l2_cache)); ++ encode_cache_cpuid2(cpu, eax, ebx, ecx, edx); + break; + case 4: + /* cache info: needed for Core compatibility */ +-- +2.47.3 + diff --git a/1234-i386-cpu-Drop-CPUID-0x2-specific-cache-info-in-X86CP.patch b/1234-i386-cpu-Drop-CPUID-0x2-specific-cache-info-in-X86CP.patch new file mode 100644 index 0000000000000000000000000000000000000000..678483d2cb8ea715504df1bf9c235c35c9099847 --- /dev/null +++ b/1234-i386-cpu-Drop-CPUID-0x2-specific-cache-info-in-X86CP.patch @@ -0,0 +1,119 @@ +From a4e4e0253723435610733e62931f9811f2671bd0 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:31 +0800 +Subject: [PATCH 56/83] i386/cpu: Drop CPUID 0x2 specific cache info in + X86CPUState + +commit c416411c28a2b21e590943f300ce0336f109abb5 upstream. + +With the pre-defined cache model legacy_intel_cpuid2_cache_info, +for X86CPUState there's no need to cache special cache information +for CPUID 0x2 leaf. + +Drop the cache_info_cpuid2 field of X86CPUState and use the +legacy_intel_cpuid2_cache_info directly. + +Intel-SIG: commit c416411c28a2 i386/cpu: Drop CPUID 0x2 specific cache info in X86CPUState. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-7-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 31 +++++++++++-------------------- + target/i386/cpu.h | 3 ++- + 2 files changed, 13 insertions(+), 21 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 93beaac1ac4..0095afcc94a 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -242,19 +242,27 @@ static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache, bool *unmacthed) + return CACHE_DESCRIPTOR_UNAVAILABLE; + } + ++static const CPUCaches legacy_intel_cpuid2_cache_info; ++ + /* Encode cache info for CPUID[2] */ + static void encode_cache_cpuid2(X86CPU *cpu, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) + { + CPUX86State *env = &cpu->env; +- CPUCaches *caches = &env->cache_info_cpuid2; ++ const CPUCaches *caches; + int l1d, l1i, l2, l3; + bool unmatched = false; + + *eax = 1; /* Number of CPUID[EAX=2] calls required */ + *ebx = *ecx = *edx = 0; + ++ if (env->enable_legacy_cpuid2_cache) { ++ caches = &legacy_intel_cpuid2_cache_info; ++ } else { ++ caches = &env->cache_info_cpuid4; ++ } ++ + l1d = cpuid2_cache_descriptor(caches->l1d_cache, &unmatched); + l1i = cpuid2_cache_descriptor(caches->l1i_cache, &unmatched); + l2 = cpuid2_cache_descriptor(caches->l2_cache, &unmatched); +@@ -702,17 +710,6 @@ static CPUCacheInfo legacy_l2_cache = { + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + +-/*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */ +-static CPUCacheInfo legacy_l2_cache_cpuid2 = { +- .type = UNIFIED_CACHE, +- .level = 2, +- .size = 2 * MiB, +- .line_size = 64, +- .associativity = 8, +- .share_level = CPU_TOPOLOGY_LEVEL_INVALID, +-}; +- +- + /*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */ + static CPUCacheInfo legacy_l2_cache_amd = { + .type = UNIFIED_CACHE, +@@ -8456,18 +8453,12 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + "CPU model '%s' doesn't support legacy-cache=off", name); + return; + } +- env->cache_info_cpuid2 = env->cache_info_cpuid4 = env->cache_info_amd = +- *cache_info; ++ env->cache_info_cpuid4 = env->cache_info_amd = *cache_info; + } else { + /* Build legacy cache information */ +- env->cache_info_cpuid2.l1d_cache = &legacy_l1d_cache; +- env->cache_info_cpuid2.l1i_cache = &legacy_l1i_cache; + if (!cpu->consistent_cache) { +- env->cache_info_cpuid2.l2_cache = &legacy_l2_cache_cpuid2; +- } else { +- env->cache_info_cpuid2.l2_cache = &legacy_l2_cache; ++ env->enable_legacy_cpuid2_cache = true; + } +- env->cache_info_cpuid2.l3_cache = &legacy_l3_cache; + + env->cache_info_cpuid4.l1d_cache = &legacy_l1d_cache; + env->cache_info_cpuid4.l1i_cache = &legacy_l1i_cache; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 85a7998730b..e8e7a7226b1 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1918,7 +1918,8 @@ typedef struct CPUArchState { + * on each CPUID leaf will be different, because we keep compatibility + * with old QEMU versions. + */ +- CPUCaches cache_info_cpuid2, cache_info_cpuid4, cache_info_amd; ++ CPUCaches cache_info_cpuid4, cache_info_amd; ++ bool enable_legacy_cpuid2_cache; + + /* MTRRs */ + uint64_t mtrr_fixed[11]; +-- +2.47.3 + diff --git a/1235-i386-cpu-Add-x-vendor-cpuid-only-v2-option-for-compa.patch b/1235-i386-cpu-Add-x-vendor-cpuid-only-v2-option-for-compa.patch new file mode 100644 index 0000000000000000000000000000000000000000..b30b291cbb5f910eedf568e4aadfb9dc4d2ae1b8 --- /dev/null +++ b/1235-i386-cpu-Add-x-vendor-cpuid-only-v2-option-for-compa.patch @@ -0,0 +1,92 @@ +From bca612566549934c201ed46686a250e05688b759 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:32 +0800 +Subject: [PATCH 57/83] i386/cpu: Add x-vendor-cpuid-only-v2 option for + compatibility + +commit 216d9bb6d77162a93a0f09d72fdabfd252d941ce upstream. + +Add a compat property "x-vendor-cpuid-only-v2" (for PC machine v10.0 +and older) to keep the original behavior. This property will be used +to adjust vendor specific CPUID fields. + +Make x-vendor-cpuid-only-v2 depend on x-vendor-cpuid-only. Although +x-vendor-cpuid-only and v2 should be initernal only, QEMU doesn't +support "internal" property. To avoid any other unexpected issues, check +the dependency. + +Intel-SIG: commit 216d9bb6d771 i386/cpu: Add x-vendor-cpuid-only-v2 option for compatibility. +CPU new topology backporting + +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-8-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + hw/i386/pc.c | 1 + + target/i386/cpu.c | 10 ++++++++++ + target/i386/cpu.h | 11 ++++++++++- + 3 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/pc.c b/hw/i386/pc.c +index a1b4b0360fb..36338cbf735 100644 +--- a/hw/i386/pc.c ++++ b/hw/i386/pc.c +@@ -83,6 +83,7 @@ const size_t pc_compat_8_1_len = G_N_ELEMENTS(pc_compat_8_1); + + GlobalProperty pc_compat_8_0[] = { + { "virtio-mem", "unplugged-inaccessible", "auto" }, ++ { TYPE_X86_CPU, "x-vendor-cpuid-only-v2", "false" }, + }; + const size_t pc_compat_8_0_len = G_N_ELEMENTS(pc_compat_8_0); + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 0095afcc94a..53b2111f6e1 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -8248,6 +8248,16 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + cs->tcg_cflags |= CF_PCREL; + #endif + ++ /* ++ * x-vendor-cpuid-only and v2 should be initernal only. But ++ * QEMU doesn't support "internal" property. ++ */ ++ if (!cpu->vendor_cpuid_only && cpu->vendor_cpuid_only_v2) { ++ error_setg(errp, "x-vendor-cpuid-only-v2 property " ++ "depends on x-vendor-cpuid-only"); ++ return; ++ } ++ + if (cpu->apic_id == UNASSIGNED_APIC_ID) { + error_setg(errp, "apic-id property was not initialized properly"); + return; +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index e8e7a7226b1..9e8c62b2a8c 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -2119,9 +2119,18 @@ struct ArchCPU { + /* Enable auto level-increase for all CPUID leaves */ + bool full_cpuid_auto_level; + +- /* Only advertise CPUID leaves defined by the vendor */ ++ /* ++ * Compatibility bits for old machine types (PC machine v6.0 and older). ++ * Only advertise CPUID leaves defined by the vendor. ++ */ + bool vendor_cpuid_only; + ++ /* ++ * Compatibility bits for old machine types (PC machine v10.0 and older). ++ * Only advertise CPUID leaves defined by the vendor. ++ */ ++ bool vendor_cpuid_only_v2; ++ + /* Enable auto level-increase for Intel Processor Trace leave */ + bool intel_pt_auto_level; + +-- +2.47.3 + diff --git a/1236-i386-cpu-Mark-CPUID-0x80000005-as-reserved-for-Intel.patch b/1236-i386-cpu-Mark-CPUID-0x80000005-as-reserved-for-Intel.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d78997129a1361b6a2dea20109a80e16f779bd1 --- /dev/null +++ b/1236-i386-cpu-Mark-CPUID-0x80000005-as-reserved-for-Intel.patch @@ -0,0 +1,99 @@ +From b1cf829cc9c29c47b2e0142206d8a4d64047426d Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:33 +0800 +Subject: [PATCH 58/83] i386/cpu: Mark CPUID[0x80000005] as reserved for Intel + +commit 225aad5a7b78b3dc017996ab5b5e1b9249c036a0 upstream. + +Per SDM, 0x80000005 leaf is reserved for Intel CPU, and its current +"assert" check blocks adding new cache model for non-AMD CPUs. + +And please note, although Zhaoxin mostly follows Intel behavior, +this leaf is an exception [1]. + +So, with the compat property "x-vendor-cpuid-only-v2", for the machine +since v10.1, check the vendor and encode this leaf as all-0 only for +Intel CPU. In addition, drop lines_per_tag assertion in +encode_cache_cpuid80000005(), since Zhaoxin will use legacy Intel cache +model in this leaf - which doesn't have this field. + +This fix also resolves 2 FIXMEs of legacy_l1d_cache_amd and +legacy_l1i_cache_amd: + +/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ + +In addition, per AMD's APM, update the comment of CPUID[0x80000005]. + +[1]: https://lore.kernel.org/qemu-devel/fa16f7a8-4917-4731-9d9f-7d4c10977168@zhaoxin.com/ + +Intel-SIG: commit 225aad5a7b78 i386/cpu: Mark CPUID[0x80000005] as reserved for Intel. +CPU new topology backporting + +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-9-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 53b2111f6e1..33a7d365f75 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -495,7 +495,6 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count, + static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache) + { + assert(cache->size % 1024 == 0); +- assert(cache->lines_per_tag > 0); + assert(cache->associativity > 0); + assert(cache->line_size > 0); + return ((cache->size / 1024) << 24) | (cache->associativity << 16) | +@@ -652,7 +651,6 @@ static CPUCacheInfo legacy_l1d_cache = { + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + +-/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ + static CPUCacheInfo legacy_l1d_cache_amd = { + .type = DATA_CACHE, + .level = 1, +@@ -681,7 +679,6 @@ static CPUCacheInfo legacy_l1i_cache = { + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + +-/*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ + static CPUCacheInfo legacy_l1i_cache_amd = { + .type = INSTRUCTION_CACHE, + .level = 1, +@@ -7416,11 +7413,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *edx = env->cpuid_model[(index - 0x80000002) * 4 + 3]; + break; + case 0x80000005: +- /* cache info (L1 cache) */ ++ /* cache info (L1 cache/TLB Associativity Field) */ + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); + break; + } ++ ++ if (cpu->vendor_cpuid_only_v2 && IS_INTEL_CPU(env)) { ++ *eax = *ebx = *ecx = *edx = 0; ++ break; ++ } ++ + *eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) | + (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); + *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | +@@ -8970,6 +8973,7 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor), + DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), + DEFINE_PROP_BOOL("x-vendor-cpuid-only", X86CPU, vendor_cpuid_only, true), ++ DEFINE_PROP_BOOL("x-vendor-cpuid-only-v2", X86CPU, vendor_cpuid_only_v2, true), + DEFINE_PROP_BOOL("lmce", X86CPU, enable_lmce, false), + DEFINE_PROP_BOOL("l3-cache", X86CPU, enable_l3_cache, true), + DEFINE_PROP_BOOL("kvm-no-smi-migration", X86CPU, kvm_no_smi_migration, +-- +2.47.3 + diff --git a/1237-i386-cpu-Rename-AMD_ENC_ASSOC-to-X86_ENC_ASSOC.patch b/1237-i386-cpu-Rename-AMD_ENC_ASSOC-to-X86_ENC_ASSOC.patch new file mode 100644 index 0000000000000000000000000000000000000000..dafbbb988aa4d24821646f28d64ea6b26250a979 --- /dev/null +++ b/1237-i386-cpu-Rename-AMD_ENC_ASSOC-to-X86_ENC_ASSOC.patch @@ -0,0 +1,82 @@ +From e2ece97a6a0b3f61a2c9cd17887118cbcab4425e Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:34 +0800 +Subject: [PATCH 59/83] i386/cpu: Rename AMD_ENC_ASSOC to X86_ENC_ASSOC + +commit 3275a379c8ff0862550910a97e8c0c9b056643cd upstream. + +Rename AMD_ENC_ASSOC to X86_ENC_ASSOC since Intel also uses the same +rules. + +While there are some slight differences between the rules in AMD APM +v4.07 no.40332 and Intel. But considerring the needs of current QEMU, +generally they are consistent and current AMD_ENC_ASSOC can be applied +for Intel CPUs.. + +Intel-SIG: commit 3275a379c8ff i386/cpu: Rename AMD_ENC_ASSOC to X86_ENC_ASSOC. +CPU new topology backporting + +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-10-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 33a7d365f75..3d34f39eab4 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -503,8 +503,8 @@ static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache) + + #define ASSOC_FULL 0xFF + +-/* AMD associativity encoding used on CPUID Leaf 0x80000006: */ +-#define AMD_ENC_ASSOC(a) (a <= 1 ? a : \ ++/* x86 associativity encoding used on CPUID Leaf 0x80000006: */ ++#define X86_ENC_ASSOC(a) (a <= 1 ? a : \ + a == 2 ? 0x2 : \ + a == 4 ? 0x4 : \ + a == 8 ? 0x6 : \ +@@ -530,7 +530,7 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2, + assert(l2->lines_per_tag > 0); + assert(l2->line_size > 0); + *ecx = ((l2->size / 1024) << 16) | +- (AMD_ENC_ASSOC(l2->associativity) << 12) | ++ (X86_ENC_ASSOC(l2->associativity) << 12) | + (l2->lines_per_tag << 8) | (l2->line_size); + + if (l3) { +@@ -539,7 +539,7 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2, + assert(l3->lines_per_tag > 0); + assert(l3->line_size > 0); + *edx = ((l3->size / (512 * 1024)) << 18) | +- (AMD_ENC_ASSOC(l3->associativity) << 12) | ++ (X86_ENC_ASSOC(l3->associativity) << 12) | + (l3->lines_per_tag << 8) | (l3->line_size); + } else { + *edx = 0; +@@ -7437,13 +7437,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); + break; + } +- *eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | ++ *eax = (X86_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | + (L2_DTLB_2M_ENTRIES << 16) | +- (AMD_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | ++ (X86_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | + (L2_ITLB_2M_ENTRIES); +- *ebx = (AMD_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | ++ *ebx = (X86_ENC_ASSOC(L2_DTLB_4K_ASSOC) << 28) | + (L2_DTLB_4K_ENTRIES << 16) | +- (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | ++ (X86_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | + (L2_ITLB_4K_ENTRIES); + encode_cache_cpuid80000006(env->cache_info_amd.l2_cache, + cpu->enable_l3_cache ? +-- +2.47.3 + diff --git a/1238-i386-cpu-Fix-CPUID-0x80000006-for-Intel-CPU.patch b/1238-i386-cpu-Fix-CPUID-0x80000006-for-Intel-CPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..45131f94aac67c98c0cba05dbd53d6d6808a4774 --- /dev/null +++ b/1238-i386-cpu-Fix-CPUID-0x80000006-for-Intel-CPU.patch @@ -0,0 +1,103 @@ +From 8c15e31abd53016385015fee0977a8ad0b8a8f35 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:35 +0800 +Subject: [PATCH 60/83] i386/cpu: Fix CPUID[0x80000006] for Intel CPU + +commit 63dc9f52f63475f61404a7f5a010aa352ead8763 upstream. + +Per SDM, Intel supports CPUID[0x80000006]. But only L2 information is +encoded in ECX (note that L2 associativity field encodings rules +consistent with AMD are used), all other fields are reserved. + +Therefore, make the following changes to CPUID[0x80000006]: + * Check the vendor in CPUID[0x80000006] and just encode L2 to ECX for + Intel. + * Drop the lines_per_tag assertion, since AMD supports this field but + Intel doesn't. And this field can be easily checked via cpuid tool + in Guest. + * Apply the encoding change of Intel for Zhaoxin as well [1]. + +This fix also resolves the FIXME of legacy_l2_cache_amd: + +/*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */ + +In addition, per AMD's APM, update the comment of CPUID[0x80000006]. + +[1]: https://lore.kernel.org/qemu-devel/c522ebb5-04d5-49c6-9ad8-d755b8998988@zhaoxin.com/ + +Intel-SIG: commit 63dc9f52f634 i386/cpu: Fix CPUID[0x80000006] for Intel CPU. +CPU new topology backporting + +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-11-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 3d34f39eab4..1a391f64cba 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -527,16 +527,15 @@ static void encode_cache_cpuid80000006(CPUCacheInfo *l2, + { + assert(l2->size % 1024 == 0); + assert(l2->associativity > 0); +- assert(l2->lines_per_tag > 0); + assert(l2->line_size > 0); + *ecx = ((l2->size / 1024) << 16) | + (X86_ENC_ASSOC(l2->associativity) << 12) | + (l2->lines_per_tag << 8) | (l2->line_size); + ++ /* For Intel, EDX is reserved. */ + if (l3) { + assert(l3->size % (512 * 1024) == 0); + assert(l3->associativity > 0); +- assert(l3->lines_per_tag > 0); + assert(l3->line_size > 0); + *edx = ((l3->size / (512 * 1024)) << 18) | + (X86_ENC_ASSOC(l3->associativity) << 12) | +@@ -707,7 +706,6 @@ static CPUCacheInfo legacy_l2_cache = { + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + +-/*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */ + static CPUCacheInfo legacy_l2_cache_amd = { + .type = UNIFIED_CACHE, + .level = 2, +@@ -7432,11 +7430,20 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *edx = encode_cache_cpuid80000005(env->cache_info_amd.l1i_cache); + break; + case 0x80000006: +- /* cache info (L2 cache) */ ++ /* cache info (L2 cache/TLB/L3 cache) */ + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); + break; + } ++ ++ if (cpu->vendor_cpuid_only_v2 && ++ (IS_INTEL_CPU(env))) { ++ *eax = *ebx = 0; ++ encode_cache_cpuid80000006(env->cache_info_cpuid4.l2_cache, ++ NULL, ecx, edx); ++ break; ++ } ++ + *eax = (X86_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) | + (L2_DTLB_2M_ENTRIES << 16) | + (X86_ENC_ASSOC(L2_ITLB_2M_ASSOC) << 12) | +@@ -7445,6 +7452,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (L2_DTLB_4K_ENTRIES << 16) | + (X86_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | + (L2_ITLB_4K_ENTRIES); ++ + encode_cache_cpuid80000006(env->cache_info_amd.l2_cache, + cpu->enable_l3_cache ? + env->cache_info_amd.l3_cache : NULL, +-- +2.47.3 + diff --git a/1239-i386-cpu-Add-legacy_intel_cache_info-cache-model.patch b/1239-i386-cpu-Add-legacy_intel_cache_info-cache-model.patch new file mode 100644 index 0000000000000000000000000000000000000000..d0543604d08885d52ae04b096b01cf432dd4f986 --- /dev/null +++ b/1239-i386-cpu-Add-legacy_intel_cache_info-cache-model.patch @@ -0,0 +1,170 @@ +From c6a3e2f339a68bded810084f9f3c6eac980a3788 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:36 +0800 +Subject: [PATCH 61/83] i386/cpu: Add legacy_intel_cache_info cache model + +commit a9b6cca2df62ab3b0ba03edb3229a0eda385f65b upstream. + +Based on legacy_l1d_cache, legacy_l1i_cache, legacy_l2_cache and +legacy_l3_cache, build a complete legacy intel cache model, which can +clarify the purpose of these trivial legacy cache models, simplify the +initialization of cache info in X86CPUState, and make it easier to +handle compatibility later. + +Intel-SIG: commit a9b6cca2df62 i386/cpu: Add legacy_intel_cache_info cache model. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-12-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 101 +++++++++++++++++++++++++--------------------- + 1 file changed, 54 insertions(+), 47 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 1a391f64cba..b4f1ce7bc4c 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -635,21 +635,6 @@ static void encode_topo_cpuid8000001e(X86CPU *cpu, X86CPUTopoInfo *topo_info, + * These are legacy cache values. If there is a need to change any + * of these values please use builtin_x86_defs + */ +- +-/* L1 data cache: */ +-static CPUCacheInfo legacy_l1d_cache = { +- .type = DATA_CACHE, +- .level = 1, +- .size = 32 * KiB, +- .self_init = 1, +- .line_size = 64, +- .associativity = 8, +- .sets = 64, +- .partitions = 1, +- .no_invd_sharing = true, +- .share_level = CPU_TOPOLOGY_LEVEL_CORE, +-}; +- + static CPUCacheInfo legacy_l1d_cache_amd = { + .type = DATA_CACHE, + .level = 1, +@@ -664,20 +649,6 @@ static CPUCacheInfo legacy_l1d_cache_amd = { + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + +-/* L1 instruction cache: */ +-static CPUCacheInfo legacy_l1i_cache = { +- .type = INSTRUCTION_CACHE, +- .level = 1, +- .size = 32 * KiB, +- .self_init = 1, +- .line_size = 64, +- .associativity = 8, +- .sets = 64, +- .partitions = 1, +- .no_invd_sharing = true, +- .share_level = CPU_TOPOLOGY_LEVEL_CORE, +-}; +- + static CPUCacheInfo legacy_l1i_cache_amd = { + .type = INSTRUCTION_CACHE, + .level = 1, +@@ -692,20 +663,6 @@ static CPUCacheInfo legacy_l1i_cache_amd = { + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }; + +-/* Level 2 unified cache: */ +-static CPUCacheInfo legacy_l2_cache = { +- .type = UNIFIED_CACHE, +- .level = 2, +- .size = 4 * MiB, +- .self_init = 1, +- .line_size = 64, +- .associativity = 16, +- .sets = 4096, +- .partitions = 1, +- .no_invd_sharing = true, +- .share_level = CPU_TOPOLOGY_LEVEL_CORE, +-}; +- + static CPUCacheInfo legacy_l2_cache_amd = { + .type = UNIFIED_CACHE, + .level = 2, +@@ -795,6 +752,59 @@ static const CPUCaches legacy_intel_cpuid2_cache_info = { + }, + }; + ++static const CPUCaches legacy_intel_cache_info = { ++ .l1d_cache = &(CPUCacheInfo) { ++ .type = DATA_CACHE, ++ .level = 1, ++ .size = 32 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 8, ++ .sets = 64, ++ .partitions = 1, ++ .no_invd_sharing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l1i_cache = &(CPUCacheInfo) { ++ .type = INSTRUCTION_CACHE, ++ .level = 1, ++ .size = 32 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 8, ++ .sets = 64, ++ .partitions = 1, ++ .no_invd_sharing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l2_cache = &(CPUCacheInfo) { ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .size = 4 * MiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 16, ++ .sets = 4096, ++ .partitions = 1, ++ .no_invd_sharing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l3_cache = &(CPUCacheInfo) { ++ .type = UNIFIED_CACHE, ++ .level = 3, ++ .size = 16 * MiB, ++ .line_size = 64, ++ .associativity = 16, ++ .sets = 16384, ++ .partitions = 1, ++ .lines_per_tag = 1, ++ .self_init = true, ++ .inclusive = true, ++ .complex_indexing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, ++ }, ++}; ++ + /* TLB definitions: */ + + #define L1_DTLB_2M_ASSOC 1 +@@ -8481,10 +8491,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + env->enable_legacy_cpuid2_cache = true; + } + +- env->cache_info_cpuid4.l1d_cache = &legacy_l1d_cache; +- env->cache_info_cpuid4.l1i_cache = &legacy_l1i_cache; +- env->cache_info_cpuid4.l2_cache = &legacy_l2_cache; +- env->cache_info_cpuid4.l3_cache = &legacy_l3_cache; ++ env->cache_info_cpuid4 = legacy_intel_cache_info; + + env->cache_info_amd.l1d_cache = &legacy_l1d_cache_amd; + env->cache_info_amd.l1i_cache = &legacy_l1i_cache_amd; +-- +2.47.3 + diff --git a/1240-i386-cpu-Add-legacy_amd_cache_info-cache-model.patch b/1240-i386-cpu-Add-legacy_amd_cache_info-cache-model.patch new file mode 100644 index 0000000000000000000000000000000000000000..e4999126e7498112ecc23df8a45baf2e8cdb441e --- /dev/null +++ b/1240-i386-cpu-Add-legacy_amd_cache_info-cache-model.patch @@ -0,0 +1,160 @@ +From c0d14f34958500073bdc42fb6be33ea8eb7558f3 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:37 +0800 +Subject: [PATCH 62/83] i386/cpu: Add legacy_amd_cache_info cache model + +commit dcec3c18f9daed23bfb38786edfbd2c0c6ee71c6 upstream. + +Based on legacy_l1d_cachei_amd, legacy_l1i_cache_amd, legacy_l2_cache_amd +and legacy_l3_cache, build a complete legacy AMD cache model, which can +clarify the purpose of these trivial legacy cache models, simplify the +initialization of cache info in X86CPUState, and make it easier to +handle compatibility later. + +Intel-SIG: commit dcec3c18f9da i386/cpu: Add legacy_amd_cache_info cache model. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-13-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 112 ++++++++++++++++++++++------------------------ + 1 file changed, 53 insertions(+), 59 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index b4f1ce7bc4c..fb616ebc959 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -635,60 +635,58 @@ static void encode_topo_cpuid8000001e(X86CPU *cpu, X86CPUTopoInfo *topo_info, + * These are legacy cache values. If there is a need to change any + * of these values please use builtin_x86_defs + */ +-static CPUCacheInfo legacy_l1d_cache_amd = { +- .type = DATA_CACHE, +- .level = 1, +- .size = 64 * KiB, +- .self_init = 1, +- .line_size = 64, +- .associativity = 2, +- .sets = 512, +- .partitions = 1, +- .lines_per_tag = 1, +- .no_invd_sharing = true, +- .share_level = CPU_TOPOLOGY_LEVEL_CORE, +-}; +- +-static CPUCacheInfo legacy_l1i_cache_amd = { +- .type = INSTRUCTION_CACHE, +- .level = 1, +- .size = 64 * KiB, +- .self_init = 1, +- .line_size = 64, +- .associativity = 2, +- .sets = 512, +- .partitions = 1, +- .lines_per_tag = 1, +- .no_invd_sharing = true, +- .share_level = CPU_TOPOLOGY_LEVEL_CORE, +-}; +- +-static CPUCacheInfo legacy_l2_cache_amd = { +- .type = UNIFIED_CACHE, +- .level = 2, +- .size = 512 * KiB, +- .line_size = 64, +- .lines_per_tag = 1, +- .associativity = 16, +- .sets = 512, +- .partitions = 1, +- .share_level = CPU_TOPOLOGY_LEVEL_CORE, +-}; +- +-/* Level 3 unified cache: */ +-static CPUCacheInfo legacy_l3_cache = { +- .type = UNIFIED_CACHE, +- .level = 3, +- .size = 16 * MiB, +- .line_size = 64, +- .associativity = 16, +- .sets = 16384, +- .partitions = 1, +- .lines_per_tag = 1, +- .self_init = true, +- .inclusive = true, +- .complex_indexing = true, +- .share_level = CPU_TOPOLOGY_LEVEL_DIE, ++static const CPUCaches legacy_amd_cache_info = { ++ .l1d_cache = &(CPUCacheInfo) { ++ .type = DATA_CACHE, ++ .level = 1, ++ .size = 64 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 2, ++ .sets = 512, ++ .partitions = 1, ++ .lines_per_tag = 1, ++ .no_invd_sharing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l1i_cache = &(CPUCacheInfo) { ++ .type = INSTRUCTION_CACHE, ++ .level = 1, ++ .size = 64 * KiB, ++ .self_init = 1, ++ .line_size = 64, ++ .associativity = 2, ++ .sets = 512, ++ .partitions = 1, ++ .lines_per_tag = 1, ++ .no_invd_sharing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l2_cache = &(CPUCacheInfo) { ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .size = 512 * KiB, ++ .line_size = 64, ++ .lines_per_tag = 1, ++ .associativity = 16, ++ .sets = 512, ++ .partitions = 1, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l3_cache = &(CPUCacheInfo) { ++ .type = UNIFIED_CACHE, ++ .level = 3, ++ .size = 16 * MiB, ++ .line_size = 64, ++ .associativity = 16, ++ .sets = 16384, ++ .partitions = 1, ++ .lines_per_tag = 1, ++ .self_init = true, ++ .inclusive = true, ++ .complex_indexing = true, ++ .share_level = CPU_TOPOLOGY_LEVEL_DIE, ++ }, + }; + + /* +@@ -8492,11 +8490,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + } + + env->cache_info_cpuid4 = legacy_intel_cache_info; +- +- env->cache_info_amd.l1d_cache = &legacy_l1d_cache_amd; +- env->cache_info_amd.l1i_cache = &legacy_l1i_cache_amd; +- env->cache_info_amd.l2_cache = &legacy_l2_cache_amd; +- env->cache_info_amd.l3_cache = &legacy_l3_cache; ++ env->cache_info_amd = legacy_amd_cache_info; + } + + #ifndef CONFIG_USER_ONLY +-- +2.47.3 + diff --git a/1241-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch b/1241-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..a1da0a1c4b0471887095593c0b4dfeb4cb564090 --- /dev/null +++ b/1241-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch @@ -0,0 +1,199 @@ +From 48d3916c5b40ed025c9658937312067f59dacb7a Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:38 +0800 +Subject: [PATCH 63/83] i386/cpu: Select legacy cache model based on vendor in + CPUID 0x2 + +commit 2f5b76bce5c9aa71b35bbe5fb666343eed7478f1 upstream. + +As preparation for merging cache_info_cpuid4 and cache_info_amd in +X86CPUState, set legacy cache model based on vendor in the CPUID 0x2 +leaf. For AMD CPU, select legacy AMD cache model (in cache_info_amd) as +the default cache model, otherwise, select legacy Intel cache model (in +cache_info_cpuid4) as before. + +To ensure compatibility is not broken, add an enable_legacy_vendor_cache +flag based on x-vendor-only-v2 to indicate cases where the legacy cache +model should be used regardless of the vendor. For CPUID 0x2 leaf, +enable_legacy_vendor_cache flag indicates to pick legacy Intel cache +model, which is for compatibility with the behavior of PC machine v10.0 +and older. + +The following explains how current vendor-based default legacy cache +model ensures correctness without breaking compatibility. + +* For the PC machine v6.0 and older, vendor_cpuid_only=false, and + vendor_cpuid_only_v2=false. + + - If the named CPU model has its own cache model, and doesn't use + legacy cache model (legacy_cache=false), then cache_info_cpuid4 and + cache_info_amd are same, so 0x2 leaf uses its own cache model + regardless of the vendor. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is true, they will use legacy Intel cache + model just like their previous behavior. + +* For the PC machine v10.0 and older (to v6.1), vendor_cpuid_only=true, + and vendor_cpuid_only_v2=false. + + - If the named CPU model has its own cache model (legacy_cache=false), + then cache_info_cpuid4 & cache_info_amd both equal to its own cache + model, so it uses its own cache model in 0x2 leaf regardless of the + vendor. Only AMD CPUs have all-0 leaf due to vendor_cpuid_only=true, + and this is exactly the behavior of these old machines. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is true, they will use legacy Intel cache + model. Similarly, only AMD CPUs have all-0 leaf, and this is exactly + the behavior of these old machines. + +* For the PC machine v10.1 and newer, vendor_cpuid_only=true, and + vendor_cpuid_only_v2=true. + + - If the named CPU model has its own cache model (legacy_cache=false), + then cache_info_cpuid4 & cache_info_amd both equal to its own cache + model, so it uses its own cache model in 0x2 leaf regardless of the + vendor. And AMD CPUs have all-0 leaf. Nothing will change. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is false, the legacy cache model is + selected based on vendor. + + For AMD CPU, it will use legacy AMD cache but still get all-0 leaf + due to vendor_cpuid_only=true. + + For non-AMD (Intel/Zhaoxin) CPU, it will use legacy Intel cache as + expected. + + Here, selecting the legacy cache model based on the vendor does not + change the previous (before the change) behavior. + +Therefore, the above analysis proves that, with the help of the flag +enable_legacy_vendor_cache, it is acceptable to select the default +legacy cache model based on the vendor. + +For the CPUID 0x2 leaf, in X86CPUState, a unified cache_info is enough. +It only needs to be initialized and configured with the corresponding +legacy cache model based on the vendor. + +Intel-SIG: commit 2f5b76bce5c9 i386/cpu: Select legacy cache model based on vendor in CPUID 0x2. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-14-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 47 +++++++++++++++++++++++++++++++++++++---------- + target/i386/cpu.h | 1 + + 2 files changed, 38 insertions(+), 10 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index fb616ebc959..49ca5550bf1 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -246,23 +246,17 @@ static const CPUCaches legacy_intel_cpuid2_cache_info; + + /* Encode cache info for CPUID[2] */ + static void encode_cache_cpuid2(X86CPU *cpu, ++ const CPUCaches *caches, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) + { + CPUX86State *env = &cpu->env; +- const CPUCaches *caches; + int l1d, l1i, l2, l3; + bool unmatched = false; + + *eax = 1; /* Number of CPUID[EAX=2] calls required */ + *ebx = *ecx = *edx = 0; + +- if (env->enable_legacy_cpuid2_cache) { +- caches = &legacy_intel_cpuid2_cache_info; +- } else { +- caches = &env->cache_info_cpuid4; +- } +- + l1d = cpuid2_cache_descriptor(caches->l1d_cache, &unmatched); + l1i = cpuid2_cache_descriptor(caches->l1i_cache, &unmatched); + l2 = cpuid2_cache_descriptor(caches->l2_cache, &unmatched); +@@ -6989,8 +6983,37 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *ecx &= ~CPUID_EXT_PDCM; + } + break; +- case 2: +- /* cache info: needed for Pentium Pro compatibility */ ++ case 2: { /* cache info: needed for Pentium Pro compatibility */ ++ const CPUCaches *caches; ++ ++ if (env->enable_legacy_cpuid2_cache) { ++ caches = &legacy_intel_cpuid2_cache_info; ++ } else if (env->enable_legacy_vendor_cache) { ++ caches = &legacy_intel_cache_info; ++ } else { ++ /* ++ * FIXME: Temporarily select cache info model here based on ++ * vendor, and merge these 2 cache info models later. ++ * ++ * This condition covers the following cases (with ++ * enable_legacy_vendor_cache=false): ++ * - When CPU model has its own cache model and doesn't use legacy ++ * cache model (legacy_model=off). Then cache_info_amd and ++ * cache_info_cpuid4 are the same. ++ * ++ * - For v10.1 and newer machines, when CPU model uses legacy cache ++ * model. Non-AMD CPUs use cache_info_cpuid4 like before and AMD ++ * CPU will use cache_info_amd. But this doesn't matter for AMD ++ * CPU, because this leaf encodes all-0 for AMD whatever its cache ++ * model is. ++ */ ++ if (IS_AMD_CPU(env)) { ++ caches = &env->cache_info_amd; ++ } else { ++ caches = &env->cache_info_cpuid4; ++ } ++ } ++ + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); + break; +@@ -6998,8 +7021,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *eax = *ebx = *ecx = *edx = 0; + break; + } +- encode_cache_cpuid2(cpu, eax, ebx, ecx, edx); ++ encode_cache_cpuid2(cpu, caches, eax, ebx, ecx, edx); + break; ++ } + case 4: + /* cache info: needed for Core compatibility */ + if (cpu->cache_info_passthrough) { +@@ -8489,6 +8513,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + env->enable_legacy_cpuid2_cache = true; + } + ++ if (!cpu->vendor_cpuid_only_v2) { ++ env->enable_legacy_vendor_cache = true; ++ } + env->cache_info_cpuid4 = legacy_intel_cache_info; + env->cache_info_amd = legacy_amd_cache_info; + } +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 9e8c62b2a8c..9bfecca6383 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1920,6 +1920,7 @@ typedef struct CPUArchState { + */ + CPUCaches cache_info_cpuid4, cache_info_amd; + bool enable_legacy_cpuid2_cache; ++ bool enable_legacy_vendor_cache; + + /* MTRRs */ + uint64_t mtrr_fixed[11]; +-- +2.47.3 + diff --git a/1242-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch b/1242-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..ff1796eacf6f9c7481282cd558ced4918b42d6b6 --- /dev/null +++ b/1242-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch @@ -0,0 +1,180 @@ +From 10460821d09f4dfa564f2cc44ecdd3a26512efd2 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:39 +0800 +Subject: [PATCH 64/83] i386/cpu: Select legacy cache model based on vendor in + CPUID 0x4 + +commit 69fe18ff9ced6e9cac3e4f3f3b94452603f2006e upstream. + +As preparation for merging cache_info_cpuid4 and cache_info_amd in +X86CPUState, set legacy cache model based on vendor in the CPUID 0x4 +leaf. For AMD CPU, select legacy AMD cache model (in cache_info_amd) as +the default cache model, otherwise, select legacy Intel cache model (in +cache_info_cpuid4) as before. + +To ensure compatibility is not broken, add an enable_legacy_vendor_cache +flag based on x-vendor-only-v2 to indicate cases where the legacy cache +model should be used regardless of the vendor. For CPUID 0x4 leaf, +enable_legacy_vendor_cache flag indicates to pick legacy Intel cache +model, which is for compatibility with the behavior of PC machine v10.0 +and older. + +The following explains how current vendor-based default legacy cache +model ensures correctness without breaking compatibility. + +* For the PC machine v6.0 and older, vendor_cpuid_only=false, and + vendor_cpuid_only_v2=false. + + - If the named CPU model has its own cache model, and doesn't use + legacy cache model (legacy_cache=false), then cache_info_cpuid4 and + cache_info_amd are same, so 0x4 leaf uses its own cache model + regardless of the vendor. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is true, they will use legacy Intel cache + model just like their previous behavior. + +* For the PC machine v10.0 and older (to v6.1), vendor_cpuid_only=true, + and vendor_cpuid_only_v2=false. + + - If the named CPU model has its own cache model (legacy_cache=false), + then cache_info_cpuid4 & cache_info_amd both equal to its own cache + model, so it uses its own cache model in 0x4 leaf regardless of the + vendor. Only AMD CPUs have all-0 leaf due to vendor_cpuid_only=true, + and this is exactly the behavior of these old machines. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is true, they will use legacy Intel cache + model. Similarly, only AMD CPUs have all-0 leaf, and this is exactly + the behavior of these old machines. + +* For the PC machine v10.1 and newer, vendor_cpuid_only=true, and + vendor_cpuid_only_v2=true. + + - If the named CPU model has its own cache model (legacy_cache=false), + then cache_info_cpuid4 & cache_info_amd both equal to its own cache + model, so it uses its own cache model in 0x4 leaf regardless of the + vendor. And AMD CPUs have all-0 leaf. Nothing will change. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is false, the legacy cache model is + selected based on vendor. + + For AMD CPU, it will use legacy AMD cache but still get all-0 leaf + due to vendor_cpuid_only=true. + + For non-AMD (Intel/Zhaoxin) CPU, it will use legacy Intel cache as + expected. + + Here, selecting the legacy cache model based on the vendor does not + change the previous (before the change) behavior. + +Therefore, the above analysis proves that, with the help of the flag +enable_legacy_vendor_cache, it is acceptable to select the default +legacy cache model based on the vendor. + +For the CPUID 0x4 leaf, in X86CPUState, a unified cache_info is enough. +It only needs to be initialized and configured with the corresponding +legacy cache model based on the vendor. + +Intel-SIG: commit 69fe18ff9ced i386/cpu: Select legacy cache model based on vendor in CPUID 0x4. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-15-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 43 ++++++++++++++++++++++++++++++++++--------- + 1 file changed, 34 insertions(+), 9 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 49ca5550bf1..d334232e6f6 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7024,7 +7024,35 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + encode_cache_cpuid2(cpu, caches, eax, ebx, ecx, edx); + break; + } +- case 4: ++ case 4: { ++ const CPUCaches *caches; ++ ++ if (env->enable_legacy_vendor_cache) { ++ caches = &legacy_intel_cache_info; ++ } else { ++ /* ++ * FIXME: Temporarily select cache info model here based on ++ * vendor, and merge these 2 cache info models later. ++ * ++ * This condition covers the following cases (with ++ * enable_legacy_vendor_cache=false): ++ * - When CPU model has its own cache model and doesn't use legacy ++ * cache model (legacy_model=off). Then cache_info_amd and ++ * cache_info_cpuid4 are the same. ++ * ++ * - For v10.1 and newer machines, when CPU model uses legacy cache ++ * model. Non-AMD CPUs use cache_info_cpuid4 like before and AMD ++ * CPU will use cache_info_amd. But this doesn't matter for AMD ++ * CPU, because this leaf encodes all-0 for AMD whatever its cache ++ * model is. ++ */ ++ if (IS_AMD_CPU(env)) { ++ caches = &env->cache_info_amd; ++ } else { ++ caches = &env->cache_info_cpuid4; ++ } ++ } ++ + /* cache info: needed for Core compatibility */ + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); +@@ -7052,30 +7080,26 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + + switch (count) { + case 0: /* L1 dcache info */ +- encode_cache_cpuid4(env->cache_info_cpuid4.l1d_cache, +- topo_info, ++ encode_cache_cpuid4(caches->l1d_cache, topo_info, + eax, ebx, ecx, edx); + if (!cpu->l1_cache_per_core) { + *eax &= ~MAKE_64BIT_MASK(14, 12); + } + break; + case 1: /* L1 icache info */ +- encode_cache_cpuid4(env->cache_info_cpuid4.l1i_cache, +- topo_info, ++ encode_cache_cpuid4(caches->l1i_cache, topo_info, + eax, ebx, ecx, edx); + if (!cpu->l1_cache_per_core) { + *eax &= ~MAKE_64BIT_MASK(14, 12); + } + break; + case 2: /* L2 cache info */ +- encode_cache_cpuid4(env->cache_info_cpuid4.l2_cache, +- topo_info, ++ encode_cache_cpuid4(caches->l2_cache, topo_info, + eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ + if (cpu->enable_l3_cache) { +- encode_cache_cpuid4(env->cache_info_cpuid4.l3_cache, +- topo_info, ++ encode_cache_cpuid4(caches->l3_cache, topo_info, + eax, ebx, ecx, edx); + break; + } +@@ -7086,6 +7110,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + } + break; ++ } + case 5: + /* MONITOR/MWAIT Leaf */ + *eax = cpu->mwait.eax; /* Smallest monitor-line size in bytes */ +-- +2.47.3 + diff --git a/1243-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch b/1243-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..156c7f377fd6388c9fb7ae9bab210d720d43aa44 --- /dev/null +++ b/1243-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch @@ -0,0 +1,148 @@ +From 2592459089ef007992f9c8f83e2bf216d5a541cf Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:40 +0800 +Subject: [PATCH 65/83] i386/cpu: Select legacy cache model based on vendor in + CPUID 0x80000005 + +commit d4a8c66de8cb1f90ef9c23db8fb0ccf668c3518b upstream. + +As preparation for merging cache_info_cpuid4 and cache_info_amd in +X86CPUState, set legacy cache model based on vendor in the CPUID +0x80000005 leaf. For AMD CPU, select legacy AMD cache model (in +cache_info_amd) as the default cache model like before, otherwise, +select legacy Intel cache model (in cache_info_cpuid4). + +To ensure compatibility is not broken, add an enable_legacy_vendor_cache +flag based on x-vendor-only-v2 to indicate cases where the legacy cache +model should be used regardless of the vendor. For CPUID 0x80000005 +leaf, enable_legacy_vendor_cache flag indicates to pick legacy AMD cache +model, which is for compatibility with the behavior of PC machine v10.0 +and older. + +The following explains how current vendor-based default legacy cache +model ensures correctness without breaking compatibility. + +* For the PC machine v6.0 and older, vendor_cpuid_only=false, and + vendor_cpuid_only_v2=false. + + - If the named CPU model has its own cache model, and doesn't use + legacy cache model (legacy_cache=false), then cache_info_cpuid4 and + cache_info_amd are same, so 0x80000005 leaf uses its own cache model + regardless of the vendor. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is true, they will use legacy AMD cache + model just like their previous behavior. + +* For the PC machine v10.0 and older (to v6.1), vendor_cpuid_only=true, + and vendor_cpuid_only_v2=false. + + - No change, since this leaf doesn't aware vendor_cpuid_only. + +* For the PC machine v10.1 and newer, vendor_cpuid_only=true, and + vendor_cpuid_only_v2=true. + + - If the named CPU model has its own cache model (legacy_cache=false), + then cache_info_cpuid4 & cache_info_amd both equal to its own cache + model, so it uses its own cache model in 0x80000005 leaf regardless + of the vendor. Only Intel CPUs have all-0 leaf due to + vendor_cpuid_only_2=true, and this is exactly the expected behavior. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is false, the legacy cache model is + selected based on vendor. + + For AMD CPU, it will use legacy AMD cache as expected. + + For Intel CPU, it will use legacy Intel cache but still get all-0 + leaf due to vendor_cpuid_only_2=true as expected. + + (Note) And for Zhaoxin CPU, it will use legacy Intel cache model + instead of AMD's. This is the difference brought by this change! But + it's correct since then Zhaoxin could have the consistent cache info + in CPUID 0x2, 0x4 and 0x80000005 leaves. + + Here, except Zhaoxin, selecting the legacy cache model based on the + vendor does not change the previous (before the change) behavior. + And the change for Zhaoxin is also a good improvement. + +Therefore, the above analysis proves that, with the help of the flag +enable_legacy_vendor_cache, it is acceptable to select the default +legacy cache model based on the vendor. + +For the CPUID 0x80000005 leaf, in X86CPUState, a unified cache_info is +enough. It only needs to be initialized and configured with the +corresponding legacy cache model based on the vendor. + +Intel-SIG: commit d4a8c66de8cb i386/cpu: Select legacy cache model based on vendor in CPUID 0x80000005. +CPU new topology backporting + +Cc: EwanHai +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-16-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 35 ++++++++++++++++++++++++++++++++--- + 1 file changed, 32 insertions(+), 3 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index d334232e6f6..56fa897cfac 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7467,8 +7467,36 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *ecx = env->cpuid_model[(index - 0x80000002) * 4 + 2]; + *edx = env->cpuid_model[(index - 0x80000002) * 4 + 3]; + break; +- case 0x80000005: ++ case 0x80000005: { + /* cache info (L1 cache/TLB Associativity Field) */ ++ const CPUCaches *caches; ++ ++ if (env->enable_legacy_vendor_cache) { ++ caches = &legacy_amd_cache_info; ++ } else { ++ /* ++ * FIXME: Temporarily select cache info model here based on ++ * vendor, and merge these 2 cache info models later. ++ * ++ * This condition covers the following cases (with ++ * enable_legacy_vendor_cache=false): ++ * - When CPU model has its own cache model and doesn't uses legacy ++ * cache model (legacy_model=off). Then cache_info_amd and ++ * cache_info_cpuid4 are the same. ++ * ++ * - For v10.1 and newer machines, when CPU model uses legacy cache ++ * model. AMD CPUs use cache_info_amd like before and non-AMD ++ * CPU will use cache_info_cpuid4. But this doesn't matter, ++ * because for Intel CPU, it will get all-0 leaf, and Zhaoxin CPU ++ * will get correct cache info. Both are expected. ++ */ ++ if (IS_AMD_CPU(env)) { ++ caches = &env->cache_info_amd; ++ } else { ++ caches = &env->cache_info_cpuid4; ++ } ++ } ++ + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); + break; +@@ -7483,9 +7511,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); + *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | + (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); +- *ecx = encode_cache_cpuid80000005(env->cache_info_amd.l1d_cache); +- *edx = encode_cache_cpuid80000005(env->cache_info_amd.l1i_cache); ++ *ecx = encode_cache_cpuid80000005(caches->l1d_cache); ++ *edx = encode_cache_cpuid80000005(caches->l1i_cache); + break; ++ } + case 0x80000006: + /* cache info (L2 cache/TLB/L3 cache) */ + if (cpu->cache_info_passthrough) { +-- +2.47.3 + diff --git a/1244-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch b/1244-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..b9dfc67e65c2a5e84f1ac46f08771032213fb954 --- /dev/null +++ b/1244-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch @@ -0,0 +1,151 @@ +From 8ba48fda0240adf15f6684c65d245c3344045480 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:41 +0800 +Subject: [PATCH 66/83] i386/cpu: Select legacy cache model based on vendor in + CPUID 0x80000006 + +commit 00fa96c96a864e133c22a5f3793b468bb8a121a5 upstream. + +As preparation for merging cache_info_cpuid4 and cache_info_amd in +X86CPUState, set legacy cache model based on vendor in the CPUID +0x80000006 leaf. For AMD CPU, select legacy AMD cache model (in +cache_info_amd) as the default cache model like before, otherwise, +select legacy Intel cache model (in cache_info_cpuid4). + +To ensure compatibility is not broken, add an enable_legacy_vendor_cache +flag based on x-vendor-only-v2 to indicate cases where the legacy cache +model should be used regardless of the vendor. For CPUID 0x80000006 leaf, +enable_legacy_vendor_cache flag indicates to pick legacy Intel cache +model, which is for compatibility with the behavior of PC machine v10.0 +and older. + +The following explains how current vendor-based default legacy cache +model ensures correctness without breaking compatibility. + +* For the PC machine v6.0 and older, vendor_cpuid_only=false, and + vendor_cpuid_only_v2=false. + + - If the named CPU model has its own cache model, and doesn't use + legacy cache model (legacy_cache=false), then cache_info_cpuid4 and + cache_info_amd are same, so 0x80000006 leaf uses its own cache model + regardless of the vendor. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is true, they will use legacy AMD cache + model just like their previous behavior. + +* For the PC machine v10.0 and older (to v6.1), vendor_cpuid_only=true, + and vendor_cpuid_only_v2=false. + + - No change, since this leaf doesn't aware vendor_cpuid_only. + +* For the PC machine v10.1 and newer, vendor_cpuid_only=true, and + vendor_cpuid_only_v2=true. + + - If the named CPU model has its own cache model (legacy_cache=false), + then cache_info_cpuid4 & cache_info_amd both equal to its own cache + model, so it uses its own cache model in 0x80000006 leaf regardless + of the vendor. Intel and Zhaoxin CPUs have their special encoding + based on SDM, which is the expected behavior and no different from + before. + + - For max/host/named CPU (without its own cache model), then the flag + enable_legacy_vendor_cache is false, the legacy cache model is + selected based on vendor. + + For AMD CPU, it will use legacy AMD cache as before. + + For non-AMD (Intel/Zhaoxin) CPU, it will use legacy Intel cache and + be encoded based on SDM as expected. + + Here, selecting the legacy cache model based on the vendor does not + change the previous (before the change) behavior. + +Therefore, the above analysis proves that, with the help of the flag +enable_legacy_vendor_cache, it is acceptable to select the default +legacy cache model based on the vendor. + +For the CPUID 0x80000006 leaf, in X86CPUState, a unified cache_info is +enough. It only needs to be initialized and configured with the +corresponding legacy cache model based on the vendor. + +Intel-SIG: commit 00fa96c96a86 i386/cpu: Select legacy cache model based on vendor in CPUID 0x80000006. +CPU new topology backporting + +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-17-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 36 +++++++++++++++++++++++++++++++----- + 1 file changed, 31 insertions(+), 5 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 56fa897cfac..8f0be66b36f 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7515,8 +7515,33 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *edx = encode_cache_cpuid80000005(caches->l1i_cache); + break; + } +- case 0x80000006: +- /* cache info (L2 cache/TLB/L3 cache) */ ++ case 0x80000006: { /* cache info (L2 cache/TLB/L3 cache) */ ++ const CPUCaches *caches; ++ ++ if (env->enable_legacy_vendor_cache) { ++ caches = &legacy_amd_cache_info; ++ } else { ++ /* ++ * FIXME: Temporarily select cache info model here based on ++ * vendor, and merge these 2 cache info models later. ++ * ++ * This condition covers the following cases (with ++ * enable_legacy_vendor_cache=false): ++ * - When CPU model has its own cache model and doesn't uses legacy ++ * cache model (legacy_model=off). Then cache_info_amd and ++ * cache_info_cpuid4 are the same. ++ * ++ * - For v10.1 and newer machines, when CPU model uses legacy cache ++ * model. AMD CPUs use cache_info_amd like before and non-AMD ++ * CPU (Intel & Zhaoxin) will use cache_info_cpuid4 as expected. ++ */ ++ if (IS_AMD_CPU(env)) { ++ caches = &env->cache_info_amd; ++ } else { ++ caches = &env->cache_info_cpuid4; ++ } ++ } ++ + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx); + break; +@@ -7525,7 +7550,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (cpu->vendor_cpuid_only_v2 && + (IS_INTEL_CPU(env))) { + *eax = *ebx = 0; +- encode_cache_cpuid80000006(env->cache_info_cpuid4.l2_cache, ++ encode_cache_cpuid80000006(caches->l2_cache, + NULL, ecx, edx); + break; + } +@@ -7539,11 +7564,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + (X86_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | + (L2_ITLB_4K_ENTRIES); + +- encode_cache_cpuid80000006(env->cache_info_amd.l2_cache, ++ encode_cache_cpuid80000006(caches->l2_cache, + cpu->enable_l3_cache ? +- env->cache_info_amd.l3_cache : NULL, ++ caches->l3_cache : NULL, + ecx, edx); + break; ++ } + case 0x80000007: + *eax = 0; + *ebx = env->features[FEAT_8000_0007_EBX]; +-- +2.47.3 + diff --git a/1245-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch b/1245-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..24569fb5583df5b7d0e00470deb6f3dc2dc8989d --- /dev/null +++ b/1245-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch @@ -0,0 +1,108 @@ +From e9df5a4731b7f697864735adfd7ad8ff59ebf0af Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:42 +0800 +Subject: [PATCH 67/83] i386/cpu: Select legacy cache model based on vendor in + CPUID 0x8000001D + +commit 25acae4c6e7635ff0f0d36945548de4c0dc70608 upstream. + +As preparation for merging cache_info_cpuid4 and cache_info_amd in +X86CPUState, set legacy cache model based on vendor in the CPUID +0x8000001D leaf. For AMD CPU, select legacy AMD cache model (in +cache_info_amd) as the default cache model like before, otherwise, +select legacy Intel cache model (in cache_info_cpuid4). + +In fact, for Intel (and Zhaoxin) CPU, this change is safe because the +extended CPUID level supported by Intel is up to 0x80000008. So Intel +Guest doesn't have this 0x8000001D leaf. + +Although someone could bump "xlevel" up to 0x8000001D for Intel Guest, +it's meaningless and this is undefined behavior. This leaf should be +considered reserved, but the SDM does not explicitly state this. So, +there's no need to specifically use vendor_cpuid_only_v2 to fix +anything, as it doesn't even qualify as a fix since nothing is +currently broken. + +Therefore, it is acceptable to select the default legacy cache model +based on the vendor. + +For the CPUID 0x8000001D leaf, in X86CPUState, a unified cache_info is +enough. It only needs to be initialized and configured with the +corresponding legacy cache model based on the vendor. + +Intel-SIG: commit 25acae4c6e76 i386/cpu: Select legacy cache model based on vendor in CPUID 0x8000001D. +CPU new topology backporting + +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-18-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 26 +++++++++++++++++++++----- + 1 file changed, 21 insertions(+), 5 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 8f0be66b36f..0c9a4d3d020 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7612,7 +7612,22 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *edx = 0; + } + break; +- case 0x8000001D: ++ case 0x8000001D: { ++ const CPUCaches *caches; ++ ++ /* ++ * FIXME: Temporarily select cache info model here based on ++ * vendor, and merge these 2 cache info models later. ++ * ++ * Intel doesn't support this leaf so that Intel Guests don't ++ * have this leaf. This change is harmless to Intel CPUs. ++ */ ++ if (IS_AMD_CPU(env)) { ++ caches = &env->cache_info_amd; ++ } else { ++ caches = &env->cache_info_cpuid4; ++ } ++ + *eax = 0; + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); +@@ -7620,19 +7635,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + switch (count) { + case 0: /* L1 dcache info */ +- encode_cache_cpuid8000001d(env->cache_info_amd.l1d_cache, ++ encode_cache_cpuid8000001d(caches->l1d_cache, + topo_info, eax, ebx, ecx, edx); + break; + case 1: /* L1 icache info */ +- encode_cache_cpuid8000001d(env->cache_info_amd.l1i_cache, ++ encode_cache_cpuid8000001d(caches->l1i_cache, + topo_info, eax, ebx, ecx, edx); + break; + case 2: /* L2 cache info */ +- encode_cache_cpuid8000001d(env->cache_info_amd.l2_cache, ++ encode_cache_cpuid8000001d(caches->l2_cache, + topo_info, eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ +- encode_cache_cpuid8000001d(env->cache_info_amd.l3_cache, ++ encode_cache_cpuid8000001d(caches->l3_cache, + topo_info, eax, ebx, ecx, edx); + break; + default: /* end of info */ +@@ -7640,6 +7655,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + } + break; ++ } + case 0x8000001E: + if (cpu->core_id <= 255) { + encode_topo_cpuid8000001e(cpu, topo_info, eax, ebx, ecx, edx); +-- +2.47.3 + diff --git a/1246-i386-cpu-Use-a-unified-cache_info-in-X86CPUState.patch b/1246-i386-cpu-Use-a-unified-cache_info-in-X86CPUState.patch new file mode 100644 index 0000000000000000000000000000000000000000..6cdf4a90fa014498eb12fe2d3d921365aef338a6 --- /dev/null +++ b/1246-i386-cpu-Use-a-unified-cache_info-in-X86CPUState.patch @@ -0,0 +1,305 @@ +From cafa27f41c6d861fd19192364160e741f004762b Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:21:43 +0800 +Subject: [PATCH 68/83] i386/cpu: Use a unified cache_info in X86CPUState + +commit 2141898bb9b7f3d426871eaa6e98b4c77a1f81e8 upstream. + +At present, all cases using the cache model (CPUID 0x2, 0x4, 0x80000005, +0x80000006 and 0x8000001D leaves) have been verified to be able to +select either cache_info_intel or cache_info_amd based on the vendor. + +Therefore, further merge cache_info_intel and cache_info_amd into a +unified cache_info in X86CPUState, and during its initialization, set +different legacy cache models based on the vendor. + +Intel-SIG: commit 2141898bb9b7 i386/cpu: Use a unified cache_info in X86CPUState. +CPU new topology backporting + +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711102143.1622339-19-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 150 ++++++++-------------------------------------- + target/i386/cpu.h | 5 +- + 2 files changed, 27 insertions(+), 128 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 0c9a4d3d020..85239637255 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -6991,27 +6991,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } else if (env->enable_legacy_vendor_cache) { + caches = &legacy_intel_cache_info; + } else { +- /* +- * FIXME: Temporarily select cache info model here based on +- * vendor, and merge these 2 cache info models later. +- * +- * This condition covers the following cases (with +- * enable_legacy_vendor_cache=false): +- * - When CPU model has its own cache model and doesn't use legacy +- * cache model (legacy_model=off). Then cache_info_amd and +- * cache_info_cpuid4 are the same. +- * +- * - For v10.1 and newer machines, when CPU model uses legacy cache +- * model. Non-AMD CPUs use cache_info_cpuid4 like before and AMD +- * CPU will use cache_info_amd. But this doesn't matter for AMD +- * CPU, because this leaf encodes all-0 for AMD whatever its cache +- * model is. +- */ +- if (IS_AMD_CPU(env)) { +- caches = &env->cache_info_amd; +- } else { +- caches = &env->cache_info_cpuid4; +- } ++ caches = &env->cache_info; + } + + if (cpu->cache_info_passthrough) { +@@ -7030,27 +7010,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (env->enable_legacy_vendor_cache) { + caches = &legacy_intel_cache_info; + } else { +- /* +- * FIXME: Temporarily select cache info model here based on +- * vendor, and merge these 2 cache info models later. +- * +- * This condition covers the following cases (with +- * enable_legacy_vendor_cache=false): +- * - When CPU model has its own cache model and doesn't use legacy +- * cache model (legacy_model=off). Then cache_info_amd and +- * cache_info_cpuid4 are the same. +- * +- * - For v10.1 and newer machines, when CPU model uses legacy cache +- * model. Non-AMD CPUs use cache_info_cpuid4 like before and AMD +- * CPU will use cache_info_amd. But this doesn't matter for AMD +- * CPU, because this leaf encodes all-0 for AMD whatever its cache +- * model is. +- */ +- if (IS_AMD_CPU(env)) { +- caches = &env->cache_info_amd; +- } else { +- caches = &env->cache_info_cpuid4; +- } ++ caches = &env->cache_info; + } + + /* cache info: needed for Core compatibility */ +@@ -7474,27 +7434,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (env->enable_legacy_vendor_cache) { + caches = &legacy_amd_cache_info; + } else { +- /* +- * FIXME: Temporarily select cache info model here based on +- * vendor, and merge these 2 cache info models later. +- * +- * This condition covers the following cases (with +- * enable_legacy_vendor_cache=false): +- * - When CPU model has its own cache model and doesn't uses legacy +- * cache model (legacy_model=off). Then cache_info_amd and +- * cache_info_cpuid4 are the same. +- * +- * - For v10.1 and newer machines, when CPU model uses legacy cache +- * model. AMD CPUs use cache_info_amd like before and non-AMD +- * CPU will use cache_info_cpuid4. But this doesn't matter, +- * because for Intel CPU, it will get all-0 leaf, and Zhaoxin CPU +- * will get correct cache info. Both are expected. +- */ +- if (IS_AMD_CPU(env)) { +- caches = &env->cache_info_amd; +- } else { +- caches = &env->cache_info_cpuid4; +- } ++ caches = &env->cache_info; + } + + if (cpu->cache_info_passthrough) { +@@ -7521,25 +7461,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (env->enable_legacy_vendor_cache) { + caches = &legacy_amd_cache_info; + } else { +- /* +- * FIXME: Temporarily select cache info model here based on +- * vendor, and merge these 2 cache info models later. +- * +- * This condition covers the following cases (with +- * enable_legacy_vendor_cache=false): +- * - When CPU model has its own cache model and doesn't uses legacy +- * cache model (legacy_model=off). Then cache_info_amd and +- * cache_info_cpuid4 are the same. +- * +- * - For v10.1 and newer machines, when CPU model uses legacy cache +- * model. AMD CPUs use cache_info_amd like before and non-AMD +- * CPU (Intel & Zhaoxin) will use cache_info_cpuid4 as expected. +- */ +- if (IS_AMD_CPU(env)) { +- caches = &env->cache_info_amd; +- } else { +- caches = &env->cache_info_cpuid4; +- } ++ caches = &env->cache_info; + } + + if (cpu->cache_info_passthrough) { +@@ -7612,22 +7534,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *edx = 0; + } + break; +- case 0x8000001D: { +- const CPUCaches *caches; +- +- /* +- * FIXME: Temporarily select cache info model here based on +- * vendor, and merge these 2 cache info models later. +- * +- * Intel doesn't support this leaf so that Intel Guests don't +- * have this leaf. This change is harmless to Intel CPUs. +- */ +- if (IS_AMD_CPU(env)) { +- caches = &env->cache_info_amd; +- } else { +- caches = &env->cache_info_cpuid4; +- } +- ++ case 0x8000001D: + *eax = 0; + if (cpu->cache_info_passthrough) { + x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx); +@@ -7635,19 +7542,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + switch (count) { + case 0: /* L1 dcache info */ +- encode_cache_cpuid8000001d(caches->l1d_cache, ++ encode_cache_cpuid8000001d(env->cache_info.l1d_cache, + topo_info, eax, ebx, ecx, edx); + break; + case 1: /* L1 icache info */ +- encode_cache_cpuid8000001d(caches->l1i_cache, ++ encode_cache_cpuid8000001d(env->cache_info.l1i_cache, + topo_info, eax, ebx, ecx, edx); + break; + case 2: /* L2 cache info */ +- encode_cache_cpuid8000001d(caches->l2_cache, ++ encode_cache_cpuid8000001d(env->cache_info.l2_cache, + topo_info, eax, ebx, ecx, edx); + break; + case 3: /* L3 cache info */ +- encode_cache_cpuid8000001d(caches->l3_cache, ++ encode_cache_cpuid8000001d(env->cache_info.l3_cache, + topo_info, eax, ebx, ecx, edx); + break; + default: /* end of info */ +@@ -7655,7 +7562,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + } + break; +- } + case 0x8000001E: + if (cpu->core_id <= 255) { + encode_topo_cpuid8000001e(cpu, topo_info, eax, ebx, ecx, edx); +@@ -8323,46 +8229,34 @@ static bool x86_cpu_update_smp_cache_topo(MachineState *ms, X86CPU *cpu, + + level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D); + if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) { +- env->cache_info_cpuid4.l1d_cache->share_level = level; +- env->cache_info_amd.l1d_cache->share_level = level; ++ env->cache_info.l1d_cache->share_level = level; + } else { + machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D, +- env->cache_info_cpuid4.l1d_cache->share_level); +- machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D, +- env->cache_info_amd.l1d_cache->share_level); ++ env->cache_info.l1d_cache->share_level); + } + + level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I); + if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) { +- env->cache_info_cpuid4.l1i_cache->share_level = level; +- env->cache_info_amd.l1i_cache->share_level = level; ++ env->cache_info.l1i_cache->share_level = level; + } else { + machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I, +- env->cache_info_cpuid4.l1i_cache->share_level); +- machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I, +- env->cache_info_amd.l1i_cache->share_level); ++ env->cache_info.l1i_cache->share_level); + } + + level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2); + if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) { +- env->cache_info_cpuid4.l2_cache->share_level = level; +- env->cache_info_amd.l2_cache->share_level = level; ++ env->cache_info.l2_cache->share_level = level; + } else { + machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2, +- env->cache_info_cpuid4.l2_cache->share_level); +- machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2, +- env->cache_info_amd.l2_cache->share_level); ++ env->cache_info.l2_cache->share_level); + } + + level = machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3); + if (level != CPU_TOPOLOGY_LEVEL_DEFAULT) { +- env->cache_info_cpuid4.l3_cache->share_level = level; +- env->cache_info_amd.l3_cache->share_level = level; ++ env->cache_info.l3_cache->share_level = level; + } else { + machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3, +- env->cache_info_cpuid4.l3_cache->share_level); +- machine_set_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3, +- env->cache_info_amd.l3_cache->share_level); ++ env->cache_info.l3_cache->share_level); + } + + if (!machine_check_smp_cache(ms, errp)) { +@@ -8602,7 +8496,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + "CPU model '%s' doesn't support legacy-cache=off", name); + return; + } +- env->cache_info_cpuid4 = env->cache_info_amd = *cache_info; ++ env->cache_info = *cache_info; + } else { + /* Build legacy cache information */ + if (!cpu->consistent_cache) { +@@ -8612,8 +8506,12 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + if (!cpu->vendor_cpuid_only_v2) { + env->enable_legacy_vendor_cache = true; + } +- env->cache_info_cpuid4 = legacy_intel_cache_info; +- env->cache_info_amd = legacy_amd_cache_info; ++ ++ if (IS_AMD_CPU(env)) { ++ env->cache_info = legacy_amd_cache_info; ++ } else { ++ env->cache_info = legacy_intel_cache_info; ++ } + } + + #ifndef CONFIG_USER_ONLY +diff --git a/target/i386/cpu.h b/target/i386/cpu.h +index 9bfecca6383..2813cffc893 100644 +--- a/target/i386/cpu.h ++++ b/target/i386/cpu.h +@@ -1914,11 +1914,12 @@ typedef struct CPUArchState { + /* Features that were explicitly enabled/disabled */ + FeatureWordArray user_features; + uint32_t cpuid_model[12]; +- /* Cache information for CPUID. When legacy-cache=on, the cache data ++ /* ++ * Cache information for CPUID. When legacy-cache=on, the cache data + * on each CPUID leaf will be different, because we keep compatibility + * with old QEMU versions. + */ +- CPUCaches cache_info_cpuid4, cache_info_amd; ++ CPUCaches cache_info; + bool enable_legacy_cpuid2_cache; + bool enable_legacy_vendor_cache; + +-- +2.47.3 + diff --git a/1247-i386-cpu-Introduce-cache-model-for-SierraForest.patch b/1247-i386-cpu-Introduce-cache-model-for-SierraForest.patch new file mode 100644 index 0000000000000000000000000000000000000000..fce10a0ec03ecc0920913428e6952590a1607ae8 --- /dev/null +++ b/1247-i386-cpu-Introduce-cache-model-for-SierraForest.patch @@ -0,0 +1,217 @@ +From cf119b632bf44bcacead050c920303d3598340e6 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:45:55 +0800 +Subject: [PATCH 69/83] i386/cpu: Introduce cache model for SierraForest +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 1f0a9ce6c0c934507eed076b1b9a2774b7c81de4 upstream. + +Add the cache model to SierraForest (v3) to better emulate its +environment. + +The cache model is based on SierraForest-SP (Scalable Performance): + + --- cache 0 --- + cache type = data cache (1) + cache level = 0x1 (1) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x0 (0) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0x8 (8) + number of sets = 0x40 (64) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 64 + (size synth) = 32768 (32 KB) + --- cache 1 --- + cache type = instruction cache (2) + cache level = 0x1 (1) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x0 (0) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0x8 (8) + number of sets = 0x80 (128) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 128 + (size synth) = 65536 (64 KB) + --- cache 2 --- + cache type = unified cache (3) + cache level = 0x2 (2) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x7 (7) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0x10 (16) + number of sets = 0x1000 (4096) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 4096 + (size synth) = 4194304 (4 MB) + --- cache 3 --- + cache type = unified cache (3) + cache level = 0x3 (3) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x1ff (511) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0xc (12) + number of sets = 0x24000 (147456) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = true + number of sets (s) = 147456 + (size synth) = 113246208 (108 MB) + --- cache 4 --- + cache type = no more caches (0) + +Intel-SIG: commit 1f0a9ce6c0c9 i386/cpu: Introduce cache model for SierraForest. +CPU new topology backporting + +Suggested-by: Tejus GK +Suggested-by: Jason Zeng +Suggested-by: "Daniel P . Berrangé" +Reviewed-by: Dapeng Mi +Reviewed-by: Tao Su +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711104603.1634832-2-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 85239637255..9f28fbc9da7 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -2592,6 +2592,97 @@ static const CPUCaches dharma_cache_info = { + .self_init = true, + .inclusive = true, + .complex_indexing = true, ++ } ++}; ++ ++static const CPUCaches xeon_srf_cache_info = { ++ .l1d_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x0.EAX */ ++ .type = DATA_CACHE, ++ .level = 1, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x0.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 8, ++ ++ /* CPUID 0x4.0x0.ECX */ ++ .sets = 64, ++ ++ /* CPUID 0x4.0x0.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 32 * KiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l1i_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x1.EAX */ ++ .type = INSTRUCTION_CACHE, ++ .level = 1, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x1.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 8, ++ ++ /* CPUID 0x4.0x1.ECX */ ++ .sets = 128, ++ ++ /* CPUID 0x4.0x1.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 64 * KiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l2_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x2.EAX */ ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x2.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 16, ++ ++ /* CPUID 0x4.0x2.ECX */ ++ .sets = 4096, ++ ++ /* CPUID 0x4.0x2.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 4 * MiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_MODULE, ++ }, ++ .l3_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x3.EAX */ ++ .type = UNIFIED_CACHE, ++ .level = 3, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x3.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 12, ++ ++ /* CPUID 0x4.0x3.ECX */ ++ .sets = 147456, ++ ++ /* CPUID 0x4.0x3.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = true, ++ ++ .size = 108 * MiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_SOCKET, + }, + }; + +@@ -4717,6 +4808,11 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + } + }, ++ { ++ .version = 3, ++ .note = "with srf-sp cache model", ++ .cache_info = &xeon_srf_cache_info, ++ }, + { /* end of list */ }, + }, + }, +-- +2.47.3 + diff --git a/1248-i386-cpu-Introduce-cache-model-for-GraniteRapids.patch b/1248-i386-cpu-Introduce-cache-model-for-GraniteRapids.patch new file mode 100644 index 0000000000000000000000000000000000000000..dc07f4d3f220ccd07665f18ef67353920868677f --- /dev/null +++ b/1248-i386-cpu-Introduce-cache-model-for-GraniteRapids.patch @@ -0,0 +1,217 @@ +From a7c14db2eed568c7dd4fcca2c78b98395146994c Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:45:56 +0800 +Subject: [PATCH 70/83] i386/cpu: Introduce cache model for GraniteRapids +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 23fb57838ddfa9271f8ebf8b7a74ed7ba3359cd3 upstream. + +Add the cache model to GraniteRapids (v3) to better emulate its +environment. + +The cache model is based on GraniteRapids-SP (Scalable Performance): + + --- cache 0 --- + cache type = data cache (1) + cache level = 0x1 (1) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x1 (1) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0xc (12) + number of sets = 0x40 (64) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 64 + (size synth) = 49152 (48 KB) + --- cache 1 --- + cache type = instruction cache (2) + cache level = 0x1 (1) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x1 (1) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0x10 (16) + number of sets = 0x40 (64) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 64 + (size synth) = 65536 (64 KB) + --- cache 2 --- + cache type = unified cache (3) + cache level = 0x2 (2) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x1 (1) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0x10 (16) + number of sets = 0x800 (2048) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 2048 + (size synth) = 2097152 (2 MB) + --- cache 3 --- + cache type = unified cache (3) + cache level = 0x3 (3) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0xff (255) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0x10 (16) + number of sets = 0x48000 (294912) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = true + number of sets (s) = 294912 + (size synth) = 301989888 (288 MB) + --- cache 4 --- + cache type = no more caches (0) + +Intel-SIG: commit 23fb57838ddf i386/cpu: Introduce cache model for GraniteRapids. +CPU new topology backporting + +Suggested-by: Tejus GK +Suggested-by: Jason Zeng +Suggested-by: "Daniel P . Berrangé" +Reviewed-by: Dapeng Mi +Reviewed-by: Tao Su +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711104603.1634832-3-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 9f28fbc9da7..ec5b1f41ac1 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -2595,6 +2595,97 @@ static const CPUCaches dharma_cache_info = { + } + }; + ++static const CPUCaches xeon_gnr_cache_info = { ++ .l1d_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x0.EAX */ ++ .type = DATA_CACHE, ++ .level = 1, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x0.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 12, ++ ++ /* CPUID 0x4.0x0.ECX */ ++ .sets = 64, ++ ++ /* CPUID 0x4.0x0.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 48 * KiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l1i_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x1.EAX */ ++ .type = INSTRUCTION_CACHE, ++ .level = 1, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x1.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 16, ++ ++ /* CPUID 0x4.0x1.ECX */ ++ .sets = 64, ++ ++ /* CPUID 0x4.0x1.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 64 * KiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l2_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x2.EAX */ ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x2.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 16, ++ ++ /* CPUID 0x4.0x2.ECX */ ++ .sets = 2048, ++ ++ /* CPUID 0x4.0x2.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 2 * MiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l3_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x3.EAX */ ++ .type = UNIFIED_CACHE, ++ .level = 3, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x3.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 16, ++ ++ /* CPUID 0x4.0x3.ECX */ ++ .sets = 294912, ++ ++ /* CPUID 0x4.0x3.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = true, ++ ++ .size = 288 * MiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_SOCKET, ++ }, ++}; ++ + static const CPUCaches xeon_srf_cache_info = { + .l1d_cache = &(CPUCacheInfo) { + /* CPUID 0x4.0x0.EAX */ +@@ -4663,6 +4754,11 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + } + }, ++ { ++ .version = 3, ++ .note = "with gnr-sp cache model", ++ .cache_info = &xeon_gnr_cache_info, ++ }, + { /* end of list */ }, + }, + }, +-- +2.47.3 + diff --git a/1249-i386-cpu-Introduce-cache-model-for-SapphireRapids.patch b/1249-i386-cpu-Introduce-cache-model-for-SapphireRapids.patch new file mode 100644 index 0000000000000000000000000000000000000000..40050fd3e19e753150f3126a3f2ebc58004716de --- /dev/null +++ b/1249-i386-cpu-Introduce-cache-model-for-SapphireRapids.patch @@ -0,0 +1,217 @@ +From 00d3b7ddf0bd112a32090b59c8a19c135d724910 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:45:57 +0800 +Subject: [PATCH 71/83] i386/cpu: Introduce cache model for SapphireRapids +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 8d69fc2158edc83517622bd862beb29ffc6bbf02 upstream. + +Add the cache model to SapphireRapids (v4) to better emulate its +environment. + +The cache model is based on SapphireRapids-SP (Scalable Performance): + + --- cache 0 --- + cache type = data cache (1) + cache level = 0x1 (1) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x1 (1) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0xc (12) + number of sets = 0x40 (64) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 64 + (size synth) = 49152 (48 KB) + --- cache 1 --- + cache type = instruction cache (2) + cache level = 0x1 (1) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x1 (1) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0x8 (8) + number of sets = 0x40 (64) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 64 + (size synth) = 32768 (32 KB) + --- cache 2 --- + cache type = unified cache (3) + cache level = 0x2 (2) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x1 (1) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0x10 (16) + number of sets = 0x800 (2048) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = false + number of sets (s) = 2048 + (size synth) = 2097152 (2 MB) + --- cache 3 --- + cache type = unified cache (3) + cache level = 0x3 (3) + self-initializing cache level = true + fully associative cache = false + maximum IDs for CPUs sharing cache = 0x7f (127) + maximum IDs for cores in pkg = 0x3f (63) + system coherency line size = 0x40 (64) + physical line partitions = 0x1 (1) + ways of associativity = 0xf (15) + number of sets = 0x10000 (65536) + WBINVD/INVD acts on lower caches = false + inclusive to lower caches = false + complex cache indexing = true + number of sets (s) = 65536 + (size synth) = 62914560 (60 MB) + --- cache 4 --- + cache type = no more caches (0) + +Intel-SIG: commit 8d69fc2158ed i386/cpu: Introduce cache model for SapphireRapids. +CPU new topology backporting + +Suggested-by: Tejus GK +Suggested-by: Jason Zeng +Suggested-by: "Daniel P . Berrangé" +Reviewed-by: Dapeng Mi +Reviewed-by: Tao Su +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711104603.1634832-4-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index ec5b1f41ac1..42afe6748bb 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -2595,6 +2595,97 @@ static const CPUCaches dharma_cache_info = { + } + }; + ++static const CPUCaches xeon_spr_cache_info = { ++ .l1d_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x0.EAX */ ++ .type = DATA_CACHE, ++ .level = 1, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x0.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 12, ++ ++ /* CPUID 0x4.0x0.ECX */ ++ .sets = 64, ++ ++ /* CPUID 0x4.0x0.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 48 * KiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l1i_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x1.EAX */ ++ .type = INSTRUCTION_CACHE, ++ .level = 1, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x1.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 8, ++ ++ /* CPUID 0x4.0x1.ECX */ ++ .sets = 64, ++ ++ /* CPUID 0x4.0x1.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 32 * KiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l2_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x2.EAX */ ++ .type = UNIFIED_CACHE, ++ .level = 2, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x2.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 16, ++ ++ /* CPUID 0x4.0x2.ECX */ ++ .sets = 2048, ++ ++ /* CPUID 0x4.0x2.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = false, ++ ++ .size = 2 * MiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_CORE, ++ }, ++ .l3_cache = &(CPUCacheInfo) { ++ /* CPUID 0x4.0x3.EAX */ ++ .type = UNIFIED_CACHE, ++ .level = 3, ++ .self_init = true, ++ ++ /* CPUID 0x4.0x3.EBX */ ++ .line_size = 64, ++ .partitions = 1, ++ .associativity = 15, ++ ++ /* CPUID 0x4.0x3.ECX */ ++ .sets = 65536, ++ ++ /* CPUID 0x4.0x3.EDX */ ++ .no_invd_sharing = false, ++ .inclusive = false, ++ .complex_indexing = true, ++ ++ .size = 60 * MiB, ++ .share_level = CPU_TOPOLOGY_LEVEL_SOCKET, ++ }, ++}; ++ + static const CPUCaches xeon_gnr_cache_info = { + .l1d_cache = &(CPUCacheInfo) { + /* CPUID 0x4.0x0.EAX */ +@@ -4601,6 +4692,11 @@ static const X86CPUDefinition builtin_x86_defs[] = { + { /* end of list */ } + } + }, ++ { ++ .version = 4, ++ .note = "with spr-sp cache model", ++ .cache_info = &xeon_spr_cache_info, ++ }, + { /* end of list */ } + } + }, +-- +2.47.3 + diff --git a/1250-i386-cpu-Add-a-x-force-cpuid-0x1f-property.patch b/1250-i386-cpu-Add-a-x-force-cpuid-0x1f-property.patch new file mode 100644 index 0000000000000000000000000000000000000000..a591927ce29eb9809aca16383bcc93c414b58ac7 --- /dev/null +++ b/1250-i386-cpu-Add-a-x-force-cpuid-0x1f-property.patch @@ -0,0 +1,59 @@ +From aaddeb1fc45e59b52a77aacec370b779b4fdb04d Mon Sep 17 00:00:00 2001 +From: Manish Mishra +Date: Fri, 11 Jul 2025 18:45:59 +0800 +Subject: [PATCH 72/83] i386/cpu: Add a "x-force-cpuid-0x1f" property + +commit bf4032561447a518e9cc4af308ef1a15023bc4c6 upstream. + +Add a "x-force-cpuid-0x1f" property so that CPU models can enable it and +have 0x1f CPUID leaf natually as the Host CPU. + +The advantage is that when the CPU model's cache model is already +consistent with the Host CPU, for example, SRF defaults to l2 per +module & l3 per package, 0x1f can better help users identify the +topology in the VM. + +Adding 0x1f for specific CPU models should not cause any trouble in +principle. This property is only enabled for CPU models that already +have 0x1f leaf on the Host, so software that originally runs normally on +the Host won't encounter issues in the Guest with corresponding CPU +model. Conversely, some software that relies on checking 0x1f might +have problems in the Guest due to the lack of 0x1f [*]. In +summary, adding 0x1f is also intended to further emulate the Host CPU +environment. + +[*]: https://lore.kernel.org/qemu-devel/PH0PR02MB738410511BF51B12DB09BE6CF6AC2@PH0PR02MB7384.namprd02.prod.outlook.com/ + +Intel-SIG: commit bf4032561447 i386/cpu: Add a "x-force-cpuid-0x1f" property. +CPU new topology backporting + +Signed-off-by: Manish Mishra +Co-authored-by: Xiaoyao Li +Signed-off-by: Xiaoyao Li +[Integrated and rebased 2 previous patches (ordered by post time)] +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711104603.1634832-6-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 42afe6748bb..58343b91fb5 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -9328,6 +9328,7 @@ static Property x86_cpu_properties[] = { + DEFINE_PROP_BOOL("x-intel-pt-auto-level", X86CPU, intel_pt_auto_level, + true), + DEFINE_PROP_BOOL("x-l1-cache-per-thread", X86CPU, l1_cache_per_core, true), ++ DEFINE_PROP_BOOL("x-force-cpuid-0x1f", X86CPU, force_cpuid_0x1f, false), + DEFINE_PROP_END_OF_LIST() + }; + +-- +2.47.3 + diff --git a/1251-i386-cpu-Enable-0x1f-leaf-for-SierraForest-by-defaul.patch b/1251-i386-cpu-Enable-0x1f-leaf-for-SierraForest-by-defaul.patch new file mode 100644 index 0000000000000000000000000000000000000000..a298b5c8cc629ab47d46b99482ff56788bbef3bd --- /dev/null +++ b/1251-i386-cpu-Enable-0x1f-leaf-for-SierraForest-by-defaul.patch @@ -0,0 +1,45 @@ +From c7a5e6fed24f08c967f3d5387dc7dbe613674c97 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:46:00 +0800 +Subject: [PATCH 73/83] i386/cpu: Enable 0x1f leaf for SierraForest by default + +commit e468c5e44435f5cbe1dd61099e6991a66c25988f upstream. + +Host SierraForest CPU has 0x1f leaf by default, so that enable it for +Guest CPU by default as well. + +Intel-SIG: commit e468c5e44435 i386/cpu: Enable 0x1f leaf for SierraForest by default. +CPU new topology backporting + +Suggested-by: Igor Mammedov +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711104603.1634832-7-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 58343b91fb5..97561f3b0ee 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5002,8 +5002,11 @@ static const X86CPUDefinition builtin_x86_defs[] = { + }, + { + .version = 3, +- .note = "with srf-sp cache model", ++ .note = "with srf-sp cache model and 0x1f leaf", + .cache_info = &xeon_srf_cache_info, ++ .props = (PropValue[]) { ++ { "x-force-cpuid-0x1f", "on" }, ++ } + }, + { /* end of list */ }, + }, +-- +2.47.3 + diff --git a/1252-i386-cpu-Enable-0x1f-leaf-for-SierraForest-by-defaul.patch b/1252-i386-cpu-Enable-0x1f-leaf-for-SierraForest-by-defaul.patch new file mode 100644 index 0000000000000000000000000000000000000000..559fbb8ac73e49403aa987e04c5689b148b90f71 --- /dev/null +++ b/1252-i386-cpu-Enable-0x1f-leaf-for-SierraForest-by-defaul.patch @@ -0,0 +1,40 @@ +From 83f12b12c07a943878f565170d438c404bb23900 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:46:00 +0800 +Subject: [PATCH 74/83] i386/cpu: Enable 0x1f leaf for SierraForest by default + +commit af62bd3db0fde8aa132dd2a0d7dc620827ba1361 upstream. + +Host SierraForest CPU has 0x1f leaf by default, so that enable it for +Guest CPU by default as well. + +Intel-SIG: commit af62bd3db0fd i386/cpu: Enable 0x1f leaf for SierraForest by default. +CPU new topology backporting + +Suggested-by: Igor Mammedov +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711104603.1634832-7-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 97561f3b0ee..5a4794f4243 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -5006,6 +5006,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { + .cache_info = &xeon_srf_cache_info, + .props = (PropValue[]) { + { "x-force-cpuid-0x1f", "on" }, ++ { /* end of list */ }, + } + }, + { /* end of list */ }, +-- +2.47.3 + diff --git a/1253-i386-cpu-Enable-0x1f-leaf-for-GraniteRapids-by-defau.patch b/1253-i386-cpu-Enable-0x1f-leaf-for-GraniteRapids-by-defau.patch new file mode 100644 index 0000000000000000000000000000000000000000..b52eeaa9a178c4437fbcfca75b12426e286348d8 --- /dev/null +++ b/1253-i386-cpu-Enable-0x1f-leaf-for-GraniteRapids-by-defau.patch @@ -0,0 +1,46 @@ +From 58a18899217d9f2b462650f175f66eafa799c284 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:46:01 +0800 +Subject: [PATCH 75/83] i386/cpu: Enable 0x1f leaf for GraniteRapids by default + +commit 5dbdcdce06d9421598e84fa77692810ccc5c3a81 upstream. + +Host GraniteRapids CPU has 0x1f leaf by default, so that enable it for +Guest CPU by default as well. + +Intel-SIG: commit 5dbdcdce06d9 i386/cpu: Enable 0x1f leaf for GraniteRapids by default. +CPU new topology backporting + +Suggested-by: Igor Mammedov +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711104603.1634832-8-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 5a4794f4243..da520aad2ee 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4852,8 +4852,12 @@ static const X86CPUDefinition builtin_x86_defs[] = { + }, + { + .version = 3, +- .note = "with gnr-sp cache model", ++ .note = "with gnr-sp cache model and 0x1f leaf", + .cache_info = &xeon_gnr_cache_info, ++ .props = (PropValue[]) { ++ { "x-force-cpuid-0x1f", "on" }, ++ { /* end of list */ }, ++ } + }, + { /* end of list */ }, + }, +-- +2.47.3 + diff --git a/1254-i386-cpu-Enable-0x1f-leaf-for-SapphireRapids-by-defa.patch b/1254-i386-cpu-Enable-0x1f-leaf-for-SapphireRapids-by-defa.patch new file mode 100644 index 0000000000000000000000000000000000000000..8b13c3876a75ce152737cc43fc3e5fd698d9993e --- /dev/null +++ b/1254-i386-cpu-Enable-0x1f-leaf-for-SapphireRapids-by-defa.patch @@ -0,0 +1,47 @@ +From 5fa2edfc71229f315eb3ce82c8f3d5296b8536b4 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 11 Jul 2025 18:46:02 +0800 +Subject: [PATCH 76/83] i386/cpu: Enable 0x1f leaf for SapphireRapids by + default + +commit 1bf465f3e0a786bf3267931461c0c15fe6232bc8 upstream. + +Host SapphireRapids CPU has 0x1f leaf by default, so that enable it for +Guest CPU by default as well. + +Intel-SIG: commit 1bf465f3e0a7 i386/cpu: Enable 0x1f leaf for SapphireRapids by default. +CPU new topology backporting + +Suggested-by: Igor Mammedov +Reviewed-by: Dapeng Mi +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250711104603.1634832-9-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index da520aad2ee..d47313afea3 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -4694,8 +4694,12 @@ static const X86CPUDefinition builtin_x86_defs[] = { + }, + { + .version = 4, +- .note = "with spr-sp cache model", ++ .note = "with spr-sp cache model and 0x1f leaf", + .cache_info = &xeon_spr_cache_info, ++ .props = (PropValue[]) { ++ { "x-force-cpuid-0x1f", "on" }, ++ { /* end of list */ }, ++ } + }, + { /* end of list */ } + } +-- +2.47.3 + diff --git a/1255-i386-cpu-Mark-EBX-ECX-EDX-in-CPUID-0x80000000-leaf-a.patch b/1255-i386-cpu-Mark-EBX-ECX-EDX-in-CPUID-0x80000000-leaf-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..e5ce0186199ed09b477372a2dbea4858209a1612 --- /dev/null +++ b/1255-i386-cpu-Mark-EBX-ECX-EDX-in-CPUID-0x80000000-leaf-a.patch @@ -0,0 +1,57 @@ +From 5cab4ac043b8472c6a8919e345e128c05fc1b998 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 27 Jun 2025 11:51:26 +0800 +Subject: [PATCH 77/83] i386/cpu: Mark EBX/ECX/EDX in CPUID 0x80000000 leaf as + reserved for Intel + +commit a539cd26145c726fddd19eb0e2c20332960b0245 upstream. + +Per SDM, + +80000000H EAX Maximum Input Value for Extended Function CPUID Information. + EBX Reserved. + ECX Reserved. + EDX Reserved. + +EBX/ECX/EDX in CPUID 0x80000000 leaf are reserved. Intel is using 0x0 +leaf to encode vendor. + +Intel-SIG: commit a539cd26145c i386/cpu: Mark EBX/ECX/EDX in CPUID 0x80000000 leaf as reserved for Intel. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Tao Su +Link: https://lore.kernel.org/r/20250627035129.2755537-2-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index d47313afea3..178c2738ef1 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7704,9 +7704,15 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 0x80000000: + *eax = env->cpuid_xlevel; +- *ebx = env->cpuid_vendor1; +- *edx = env->cpuid_vendor2; +- *ecx = env->cpuid_vendor3; ++ ++ if (cpu->vendor_cpuid_only_v2 && ++ (IS_INTEL_CPU(env))) { ++ *ebx = *ecx = *edx = 0; ++ } else { ++ *ebx = env->cpuid_vendor1; ++ *edx = env->cpuid_vendor2; ++ *ecx = env->cpuid_vendor3; ++ } + break; + case 0x80000001: + *eax = env->cpuid_version; +-- +2.47.3 + diff --git a/1256-i386-cpu-Mark-CPUID-0x80000007-EBX-as-reserved-for-I.patch b/1256-i386-cpu-Mark-CPUID-0x80000007-EBX-as-reserved-for-I.patch new file mode 100644 index 0000000000000000000000000000000000000000..8c48e3c7236f6757fa4769d7244b04d823032f6c --- /dev/null +++ b/1256-i386-cpu-Mark-CPUID-0x80000007-EBX-as-reserved-for-I.patch @@ -0,0 +1,57 @@ +From 5e228a6b655f9b0dd27f5aa4d0aa949c7b947161 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 27 Jun 2025 11:51:27 +0800 +Subject: [PATCH 78/83] i386/cpu: Mark CPUID 0x80000007[EBX] as reserved for + Intel + +commit 1c52c470baba1a2cc2d96e14c9f845ec3d2ea8c4 upstream. + +Per SDM, + +80000007H EAX Reserved = 0. + EBX Reserved = 0. + ECX Reserved = 0. + EDX Bits 07-00: Reserved = 0. + Bit 08: Invariant TSC available if 1. + Bits 31-09: Reserved = 0. + +EAX/EBX/ECX in CPUID 0x80000007 leaf are reserved for Intel. + +At present, EAX is reserved for AMD, too. And AMD hasn't used ECX in +QEMU. So these 2 registers are both left as 0. + +Therefore, only fix the EBX and excode it as 0 for Intel. + +Intel-SIG: commit 1c52c470baba i386/cpu: Mark CPUID 0x80000007[EBX] as reserved for Intel. +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Tao Su +Link: https://lore.kernel.org/r/20250627035129.2755537-3-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 178c2738ef1..5737657f02b 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7800,7 +7800,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + case 0x80000007: + *eax = 0; +- *ebx = env->features[FEAT_8000_0007_EBX]; ++ if (cpu->vendor_cpuid_only_v2 && IS_INTEL_CPU(env)) { ++ *ebx = 0; ++ } else { ++ *ebx = env->features[FEAT_8000_0007_EBX]; ++ } + *ecx = 0; + *edx = env->features[FEAT_8000_0007_EDX]; + break; +-- +2.47.3 + diff --git a/1257-i386-cpu-Mark-CPUID-0x80000008-ECX-bits-0-7-12-15-as.patch b/1257-i386-cpu-Mark-CPUID-0x80000008-ECX-bits-0-7-12-15-as.patch new file mode 100644 index 0000000000000000000000000000000000000000..1a28341fd0077a991160317596ed68fbb1c0f0c3 --- /dev/null +++ b/1257-i386-cpu-Mark-CPUID-0x80000008-ECX-bits-0-7-12-15-as.patch @@ -0,0 +1,71 @@ +From 4ca970fde734af7d84b0af7e7b93e9cb3c32e827 Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 27 Jun 2025 11:51:28 +0800 +Subject: [PATCH 79/83] i386/cpu: Mark CPUID 0x80000008 ECX bits[0:7] & [12:15] + as reserved for Intel/Zhaoxin + +commit da84c011544b808b9ea3dface2292437dd29d053 upstream. + +Per SDM, + +80000008H EAX Linear/Physical Address size. + Bits 07-00: #Physical Address Bits*. + Bits 15-08: #Linear Address Bits. + Bits 31-16: Reserved = 0. + EBX Bits 08-00: Reserved = 0. + Bit 09: WBNOINVD is available if 1. + Bits 31-10: Reserved = 0. + ECX Reserved = 0. + EDX Reserved = 0. + +ECX/EDX in CPUID 0x80000008 leaf are reserved. + +Currently, in QEMU, only ECX bits[0:7] and ECX bits[12:15] are encoded, +and both are emulated in QEMU. + +Considering that Intel and Zhaoxin are already using the 0x1f leaf to +describe CPU topology, which includes similar information, Intel and +Zhaoxin will not implement ECX bits[0:7] and bits[12:15] of 0x80000008. + +Therefore, mark these two fields as reserved and clear them for Intel +and Zhaoxin guests. + +Intel-SIG: commit da84c011544b i386/cpu: Mark CPUID 0x80000008 ECX bits[0:7] & [12:15] as reserved for Intel/Zhaoxin. +CPU new topology backporting + +Reviewed-by: Tao Su +Tested-by: Yi Lai +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250714080859.1960104-3-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 5737657f02b..550ee05eab5 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7817,6 +7817,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *eax |= (cpu->guest_phys_bits << 16); + } + *ebx = env->features[FEAT_8000_0008_EBX]; ++ ++ /* ++ * Don't emulate Bits [7:0] & Bits [15:12] for Intel/Zhaoxin, since ++ * they're using 0x1f leaf. ++ */ ++ if (cpu->vendor_cpuid_only_v2 && ++ (IS_INTEL_CPU(env))) { ++ *ecx = *edx = 0; ++ break; ++ } ++ + if (threads_per_pkg > 1) { + /* + * Bits 15:12 is "The number of bits in the initial +-- +2.47.3 + diff --git a/1258-i386-cpu-Fix-number-of-addressable-IDs-field-for-CPU.patch b/1258-i386-cpu-Fix-number-of-addressable-IDs-field-for-CPU.patch new file mode 100644 index 0000000000000000000000000000000000000000..bd71f33aab0d5aaa5127f8a64831a2960eb642d5 --- /dev/null +++ b/1258-i386-cpu-Fix-number-of-addressable-IDs-field-for-CPU.patch @@ -0,0 +1,82 @@ +From 22aaff3ea5acd79102aa15f6c3d0b3d47506244e Mon Sep 17 00:00:00 2001 +From: Chuang Xu +Date: Mon, 14 Jul 2025 16:08:56 +0800 +Subject: [PATCH 80/83] i386/cpu: Fix number of addressable IDs field for + CPUID.01H.EBX[23:16] + +commit f985a1195ba2d9c6f6f33e83fe2e419a7e8acb60 upstream. + +When QEMU is started with: +-cpu host,migratable=on,host-cache-info=on,l3-cache=off +-smp 180,sockets=2,dies=1,cores=45,threads=2 + +On Intel platform: +CPUID.01H.EBX[23:16] is defined as "max number of addressable IDs for +logical processors in the physical package". + +When executing "cpuid -1 -l 1 -r" in the guest, we obtain a value of 90 for +CPUID.01H.EBX[23:16], whereas the expected value is 128. Additionally, +executing "cpuid -1 -l 4 -r" in the guest yields a value of 63 for +CPUID.04H.EAX[31:26], which matches the expected result. + +As (1+CPUID.04H.EAX[31:26]) rounds up to the nearest power-of-2 integer, +it's necessary to round up CPUID.01H.EBX[23:16] to the nearest power-of-2 +integer too. Otherwise there would be unexpected results in guest with +older kernel. + +For example, when QEMU is started with CLI above and xtopology is disabled, +guest kernel 5.15.120 uses CPUID.01H.EBX[23:16]/(1+CPUID.04H.EAX[31:26]) to +calculate threads-per-core in detect_ht(). Then guest will get "90/(1+63)=1" +as the result, even though threads-per-core should actually be 2. + +And on AMD platform: +CPUID.01H.EBX[23:16] is defined as "Logical processor count". Current +result meets our expectation. + +So round up CPUID.01H.EBX[23:16] to the nearest power-of-2 integer only +for Intel platform to solve the unexpected result. + +Use the "x-vendor-cpuid-only-v2" compat option to fix this issue. + +Intel-SIG: commit f985a1195ba2 i386/cpu: Fix number of addressable IDs field for CPUID.01H.EBX[23:16]. +CPU new topology backporting + +Reviewed-by: Zhao Liu +Signed-off-by: Guixiong Wei +Signed-off-by: Yipeng Yin +Signed-off-by: Chuang Xu +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250714080859.1960104-5-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 550ee05eab5..bd494cce580 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7277,7 +7277,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + *edx = env->features[FEAT_1_EDX]; + if (threads_per_pkg > 1) { +- *ebx |= threads_per_pkg << 16; ++ /* ++ * For CPUID.01H.EBX[Bits 23-16], AMD requires logical processor ++ * count, but Intel needs maximum number of addressable IDs for ++ * logical processors per package. ++ */ ++ if (cpu->vendor_cpuid_only_v2 && ++ (IS_INTEL_CPU(env))) { ++ *ebx |= 1 << apicid_pkg_offset(topo_info) << 16; ++ } else { ++ *ebx |= threads_per_pkg << 16; ++ } + } + if (!cpu->enable_pmu) { + *ecx &= ~CPUID_EXT_PDCM; +-- +2.47.3 + diff --git a/1259-i386-cpu-Fix-cpu-number-overflow-in-CPUID.01H.EBX-23.patch b/1259-i386-cpu-Fix-cpu-number-overflow-in-CPUID.01H.EBX-23.patch new file mode 100644 index 0000000000000000000000000000000000000000..36c372f28cc93fa1f33f18c0cae98559f6d6c7df --- /dev/null +++ b/1259-i386-cpu-Fix-cpu-number-overflow-in-CPUID.01H.EBX-23.patch @@ -0,0 +1,86 @@ +From ef72be1ee9b6b5b705f9380fa8063ab43b77635a Mon Sep 17 00:00:00 2001 +From: Qian Wen +Date: Mon, 14 Jul 2025 16:08:57 +0800 +Subject: [PATCH 81/83] i386/cpu: Fix cpu number overflow in + CPUID.01H.EBX[23:16] + +commit a62fef58299562aae6667b8d8552247423e886b3 upstream. + +The legacy topology enumerated by CPUID.1.EBX[23:16] is defined in SDM +Vol2: + +Bits 23-16: Maximum number of addressable IDs for logical processors in +this physical package. + +When threads_per_socket > 255, it will 1) overwrite bits[31:24] which is +apic_id, 2) bits [23:16] get truncated. + +Specifically, if launching the VM with -smp 256, the value written to +EBX[23:16] is 0 because of data overflow. If the guest only supports +legacy topology, without V2 Extended Topology enumerated by CPUID.0x1f +or Extended Topology enumerated by CPUID.0x0b to support over 255 CPUs, +the return of the kernel invoking cpu_smt_allowed() is false and APs +(application processors) will fail to bring up. Then only CPU 0 is online, +and others are offline. + +For example, launch VM via: +qemu-system-x86_64 -M q35,accel=kvm,kernel-irqchip=split \ + -cpu qemu64,cpuid-0xb=off -smp 256 -m 32G \ + -drive file=guest.img,if=none,id=virtio-disk0,format=raw \ + -device virtio-blk-pci,drive=virtio-disk0,bootindex=1 --nographic + +The guest shows: + CPU(s): 256 + On-line CPU(s) list: 0 + Off-line CPU(s) list: 1-255 + +To avoid this issue caused by overflow, limit the max value written to +EBX[23:16] to 255 as the HW does. + +Intel-SIG: commit a62fef582995 i386/cpu: Fix cpu number overflow in CPUID.01H.EBX[23:16]. +CPU new topology backporting + +Cc: qemu-stable@nongnu.org +Reviewed-by: Xiaoyao Li +Signed-off-by: Qian Wen +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250714080859.1960104-6-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index bd494cce580..4e309912862 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7277,6 +7277,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + *edx = env->features[FEAT_1_EDX]; + if (threads_per_pkg > 1) { ++ uint32_t num; ++ + /* + * For CPUID.01H.EBX[Bits 23-16], AMD requires logical processor + * count, but Intel needs maximum number of addressable IDs for +@@ -7284,10 +7286,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + */ + if (cpu->vendor_cpuid_only_v2 && + (IS_INTEL_CPU(env))) { +- *ebx |= 1 << apicid_pkg_offset(topo_info) << 16; ++ num = 1 << apicid_pkg_offset(topo_info); + } else { +- *ebx |= threads_per_pkg << 16; ++ num = threads_per_pkg; + } ++ ++ /* Fixup overflow: max value for bits 23-16 is 255. */ ++ *ebx |= MIN(num, 255) << 16; + } + if (!cpu->enable_pmu) { + *ecx &= ~CPUID_EXT_PDCM; +-- +2.47.3 + diff --git a/1260-i386-cpu-Honor-maximum-value-for-CPUID.8000001DH.EAX.patch b/1260-i386-cpu-Honor-maximum-value-for-CPUID.8000001DH.EAX.patch new file mode 100644 index 0000000000000000000000000000000000000000..18d8d6e78e3b3b9944c962027df597808e11e81d --- /dev/null +++ b/1260-i386-cpu-Honor-maximum-value-for-CPUID.8000001DH.EAX.patch @@ -0,0 +1,49 @@ +From 5528a28604cef3f31c4f409ff62a0205786dcb0d Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Mon, 14 Jul 2025 16:08:59 +0800 +Subject: [PATCH 82/83] i386/cpu: Honor maximum value for + CPUID.8000001DH.EAX[25:14] + +commit 5d21ee453ad8e3f95f75e542cb3b35c5bb7cf23a upstream. + +CPUID.8000001DH:EAX[25:14] is "NumSharingCache", and the number of +logical processors sharing this cache is the value of this field +incremented by 1. Because of its width limitation, the maximum value +currently supported is 4095. + +Though at present Q35 supports up to 4096 CPUs, by constructing a +specific topology, the width of the APIC ID can be extended beyond 12 +bits. For example, using `-smp threads=33,cores=9,modules=9` results in +a die level offset of 6 + 4 + 4 = 14 bits, which can also cause +overflow. Check and honor the maximum value as CPUID.04H did. + +Intel-SIG: commit 5d21ee453ad8 i386/cpu: Honor maximum value for CPUID.8000001DH.EAX[25:14]. +CPU new topology backporting + +Cc: Babu Moger +Signed-off-by: Zhao Liu +Link: https://lore.kernel.org/r/20250714080859.1960104-8-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 4e309912862..3a01795d33f 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -550,7 +550,8 @@ static void encode_cache_cpuid8000001d(CPUCacheInfo *cache, + + *eax = CACHE_TYPE(cache->type) | CACHE_LEVEL(cache->level) | + (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0); +- *eax |= max_thread_ids_for_cache(topo_info, cache->share_level) << 14; ++ /* Bits 25:14 - NumSharingCache: maximum 4095. */ ++ *eax |= MIN(max_thread_ids_for_cache(topo_info, cache->share_level), 4095) << 14; + + assert(cache->line_size > 0); + assert(cache->partitions > 0); +-- +2.47.3 + diff --git a/1261-i386-cpu-Reorder-CPUID-leaves-in-cpu_x86_cpuid.patch b/1261-i386-cpu-Reorder-CPUID-leaves-in-cpu_x86_cpuid.patch new file mode 100644 index 0000000000000000000000000000000000000000..f73e6a09c59c806b0884a831851284e9715b890e --- /dev/null +++ b/1261-i386-cpu-Reorder-CPUID-leaves-in-cpu_x86_cpuid.patch @@ -0,0 +1,123 @@ +From e5b97ea2a7074337a9a51080461477df1828c2cf Mon Sep 17 00:00:00 2001 +From: Zhao Liu +Date: Fri, 27 Jun 2025 11:51:29 +0800 +Subject: [PATCH 83/83] i386/cpu: Reorder CPUID leaves in cpu_x86_cpuid() + +commit 075e91a4a42dad834d6488cd8141fa29c7b218bd upstream. + +Sort the CPUID leaves strictly by index to facilitate checking and +changing. + +Intel-SIG: commit 075e91a4a42d i386/cpu: Reorder CPUID leaves in cpu_x86_cpuid(). +CPU new topology backporting + +Signed-off-by: Zhao Liu +Reviewed-by: Tao Su +Link: https://lore.kernel.org/r/20250627035129.2755537-5-zhao1.liu@intel.com +Signed-off-by: Paolo Bonzini +[ Quanxian Wang: amend commit log ] +Signed-off-by: Quanxian Wang +--- + target/i386/cpu.c | 58 +++++++++++++++++++++++------------------------ + 1 file changed, 29 insertions(+), 29 deletions(-) + +diff --git a/target/i386/cpu.c b/target/i386/cpu.c +index 3a01795d33f..e96257cd7e9 100644 +--- a/target/i386/cpu.c ++++ b/target/i386/cpu.c +@@ -7496,21 +7496,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + assert(!(*eax & ~0x1f)); + *ebx &= 0xffff; /* The count doesn't need to be reliable. */ + break; +- case 0x1C: +- if (cpu->enable_pmu && (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { +- x86_cpu_get_supported_cpuid(0x1C, 0, eax, ebx, ecx, edx); +- *edx = 0; +- } +- break; +- case 0x1F: +- /* V2 Extended Topology Enumeration Leaf */ +- if (!x86_has_cpuid_0x1f(cpu)) { +- *eax = *ebx = *ecx = *edx = 0; +- break; +- } +- +- encode_topo_cpuid1f(env, count, topo_info, eax, ebx, ecx, edx); +- break; + case 0xD: { + /* Processor Extended State */ + *eax = 0; +@@ -7647,6 +7632,12 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + break; + } ++ case 0x1C: ++ if (cpu->enable_pmu && (env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_ARCH_LBR)) { ++ x86_cpu_get_supported_cpuid(0x1C, 0, eax, ebx, ecx, edx); ++ *edx = 0; ++ } ++ break; + case 0x1D: { + /* AMX TILE, for now hardcoded for Sapphire Rapids*/ + *eax = 0; +@@ -7684,6 +7675,15 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + } + break; + } ++ case 0x1F: ++ /* V2 Extended Topology Enumeration Leaf */ ++ if (!x86_has_cpuid_0x1f(cpu)) { ++ *eax = *ebx = *ecx = *edx = 0; ++ break; ++ } ++ ++ encode_topo_cpuid1f(env, count, topo_info, eax, ebx, ecx, edx); ++ break; + case 0x24: { + *eax = 0; + *ebx = 0; +@@ -7909,6 +7909,20 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *edx = 0; + } + break; ++ case 0x8000001F: ++ *eax = *ebx = *ecx = *edx = 0; ++ if (sev_enabled()) { ++ *eax = 0x2; ++ *eax |= sev_es_enabled() ? 0x8 : 0; ++ *eax |= csv3_enabled() ? 0x40000000 : 0; /* bit 30 for CSV3 */ ++ *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */ ++ *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */ ++ } ++ break; ++ case 0x80000021: ++ *eax = env->features[FEAT_8000_0021_EAX]; ++ *ebx = *ecx = *edx = 0; ++ break; + case 0xC0000000: + *eax = env->cpuid_xlevel2; + *ebx = 0; +@@ -7931,20 +7945,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *ecx = 0; + *edx = 0; + break; +- case 0x8000001F: +- *eax = *ebx = *ecx = *edx = 0; +- if (sev_enabled()) { +- *eax = 0x2; +- *eax |= sev_es_enabled() ? 0x8 : 0; +- *eax |= csv3_enabled() ? 0x40000000 : 0; /* bit 30 for CSV3 */ +- *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */ +- *ebx |= (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */ +- } +- break; +- case 0x80000021: +- *eax = env->features[FEAT_8000_0021_EAX]; +- *ebx = *ecx = *edx = 0; +- break; + default: + /* reserved values: zero */ + *eax = 0; +-- +2.47.3 + diff --git a/qemu.spec b/qemu.spec index f6bd5422fcd3501b35a3ca8ca87cd868cb206052..b3f16d363c6fe6e8b2dac5ede4befe5ca0868b79 100644 --- a/qemu.spec +++ b/qemu.spec @@ -136,7 +136,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 8.2.2 -Release: 49%{?dist} +Release: 50%{?dist} License: GPLv2 and BSD and MIT and CC-BY URL: http://www.qemu.org/ Source0: https://download.qemu.org/%{name}-%{version}.tar.xz @@ -532,6 +532,90 @@ Patch1176: 1176-target-i386-Add-tsc-adjust-to-Hygon-Chengdu-v2.patch Patch1177: 1177-target-i386-Add-avx512-vp2intersect-to-Chengdu-v2.patch # CVE-2026-3842 Patch1178: qemu-8.2.2-CVE-2026-3842.patch +# Support Intel new topology including module level enabling and Cache topology support +Patch1179: 1179-hw-core-machine-smp-Deprecate-unsupported-parameter-.patch +Patch1180: 1180-hw-core-machine-smp-Calculate-total-CPUs-once-in-mac.patch +Patch1181: 1181-hw-core-machine-Introduce-the-module-as-a-CPU-topolo.patch +Patch1182: 1182-hw-core-Introduce-module-id-as-the-topology-subindex.patch +Patch1183: 1183-hw-core-machine-Support-modules-in-smp.patch +Patch1184: 1184-hw-core-Support-module-id-in-numa-configuration.patch +Patch1185: 1185-hw-i386-split-x86.c-in-multiple-parts.patch +Patch1186: 1186-i386-cpu-Fix-i-d-cache-topology-to-core-level-for-In.patch +Patch1187: 1187-i386-cpu-Use-APIC-ID-info-to-encode-cache-topo-in-CP.patch +Patch1188: 1188-i386-cpu-Use-APIC-ID-info-get-NumSharingCache-for-CP.patch +Patch1189: 1189-i386-cpu-Consolidate-the-use-of-topo_info-in-cpu_x86.patch +Patch1190: 1190-i386-cpu-Introduce-bitmap-to-cache-available-CPU-top.patch +Patch1191: 1191-i386-Split-topology-types-of-CPUID-0x1F-from-the-def.patch +Patch1192: 1192-i386-cpu-Decouple-CPUID-0x1F-subleaf-with-specific-t.patch +Patch1193: 1193-i386-Introduce-module-level-cpu-topology-to-CPUX86St.patch +Patch1194: 1194-i386-Support-modules_per_die-in-X86CPUTopoInfo.patch +Patch1195: 1195-i386-Expose-module-level-in-CPUID-0x1F.patch +Patch1196: 1196-i386-Support-module_id-in-X86CPUTopoIDs.patch +Patch1197: 1197-i386-cpu-Introduce-module-id-to-X86CPU.patch +Patch1198: 1198-tests-Add-test-case-of-APIC-ID-for-module-level-pars.patch +Patch1199: 1199-hw-i386-pc-Support-smp.modules-for-x86-PC-machine.patch +Patch1200: 1200-i386-Add-cache-topology-info-in-CPUCacheInfo.patch +Patch1201: 1201-i386-cpu-Use-CPUCacheInfo.share_level-to-encode-CPUI.patch +Patch1202: 1202-i386-cpu-Use-CPUCacheInfo.share_level-to-encode-CPUI.patch +Patch1203: 1203-i386-Add-support-for-SUCCOR-feature.patch +Patch1204: 1204-i386-cpu-fixup-number-of-addressable-IDs-for-process.patch +Patch1205: 1205-i386-cpu-Don-t-enumerate-the-invalid-CPU-topology-le.patch +Patch1206: 1206-hw-core-Make-CPU-topology-enumeration-arch-agnostic.patch +Patch1207: 1207-qapi-qom-Define-cache-enumeration-and-properties-for.patch +Patch1208: 1208-hw-core-Check-smp-cache-topology-support-for-machine.patch +Patch1209: 1209-hw-core-Add-a-helper-to-check-the-cache-topology-lev.patch +Patch1210: 1210-hw-core-machine-smp-Initialize-caches_bitmap-before-.patch +Patch1211: 1211-hw-core-machine-smp-Fix-error-message-parameter.patch +Patch1212: 1212-i386-cpu-Extract-a-common-fucntion-to-setup-value-of.patch +Patch1213: 1213-i386-cpu-Drop-the-variable-smp_cores-and-smp_threads.patch +Patch1214: 1214-i386-cpu-Drop-cores_per_pkg-in-cpu_x86_cpuid.patch +Patch1215: 1215-i386-topology-Update-the-comment-of-x86_apicid_from_.patch +Patch1216: 1216-i386-topology-Introduce-helpers-for-various-topology.patch +Patch1217: 1217-i386-cpu-Track-a-X86CPUTopoInfo-directly-in-CPUX86St.patch +Patch1218: 1218-i386-cpu-Hoist-check-of-CPUID_EXT3_TOPOEXT-against-t.patch +Patch1219: 1219-cpu-Remove-nr_cores-from-struct-CPUState.patch +Patch1220: 1220-i386-cpu-Set-up-CPUID_HT-in-x86_cpu_expand_features-.patch +Patch1221: 1221-i386-cpu-Set-and-track-CPUID_EXT3_CMP_LEG-in-env-fea.patch +Patch1222: 1222-hw-core-machine-Reject-thread-level-cache.patch +Patch1223: 1223-i386-pc-Support-cache-topology-in-machine-for-PC-mac.patch +Patch1224: 1224-i386-cpu-Update-cache-topology-with-machine-s-config.patch +Patch1225: 1225-i386-cpu-add-has_caches-flag-to-check-smp_cache-conf.patch +Patch1226: 1226-i386-cpu-Support-module-level-cache-topology.patch +Patch1227: 1227-i386-cpu-Introduce-enable_cpuid_0x1f-to-force-exposi.patch +Patch1228: 1228-i386-cpu-Rename-enable_cpuid_0x1f-to-force_cpuid_0x1.patch +Patch1229: 1229-i386-cpu-Refine-comment-of-CPUID2CacheDescriptorInfo.patch +Patch1230: 1230-i386-cpu-Add-descriptor-0x49-for-CPUID-0x2-encoding.patch +Patch1231: 1231-i386-cpu-Add-default-cache-model-for-Intel-CPUs-with.patch +Patch1232: 1232-i386-cpu-Present-same-cache-model-in-CPUID-0x2-0x4.patch +Patch1233: 1233-i386-cpu-Consolidate-CPUID-0x4-leaf.patch +Patch1234: 1234-i386-cpu-Drop-CPUID-0x2-specific-cache-info-in-X86CP.patch +Patch1235: 1235-i386-cpu-Add-x-vendor-cpuid-only-v2-option-for-compa.patch +Patch1236: 1236-i386-cpu-Mark-CPUID-0x80000005-as-reserved-for-Intel.patch +Patch1237: 1237-i386-cpu-Rename-AMD_ENC_ASSOC-to-X86_ENC_ASSOC.patch +Patch1238: 1238-i386-cpu-Fix-CPUID-0x80000006-for-Intel-CPU.patch +Patch1239: 1239-i386-cpu-Add-legacy_intel_cache_info-cache-model.patch +Patch1240: 1240-i386-cpu-Add-legacy_amd_cache_info-cache-model.patch +Patch1241: 1241-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch +Patch1242: 1242-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch +Patch1243: 1243-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch +Patch1244: 1244-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch +Patch1245: 1245-i386-cpu-Select-legacy-cache-model-based-on-vendor-i.patch +Patch1246: 1246-i386-cpu-Use-a-unified-cache_info-in-X86CPUState.patch +Patch1247: 1247-i386-cpu-Introduce-cache-model-for-SierraForest.patch +Patch1248: 1248-i386-cpu-Introduce-cache-model-for-GraniteRapids.patch +Patch1249: 1249-i386-cpu-Introduce-cache-model-for-SapphireRapids.patch +Patch1250: 1250-i386-cpu-Add-a-x-force-cpuid-0x1f-property.patch +Patch1251: 1251-i386-cpu-Enable-0x1f-leaf-for-SierraForest-by-defaul.patch +Patch1252: 1252-i386-cpu-Enable-0x1f-leaf-for-SierraForest-by-defaul.patch +Patch1253: 1253-i386-cpu-Enable-0x1f-leaf-for-GraniteRapids-by-defau.patch +Patch1254: 1254-i386-cpu-Enable-0x1f-leaf-for-SapphireRapids-by-defa.patch +Patch1255: 1255-i386-cpu-Mark-EBX-ECX-EDX-in-CPUID-0x80000000-leaf-a.patch +Patch1256: 1256-i386-cpu-Mark-CPUID-0x80000007-EBX-as-reserved-for-I.patch +Patch1257: 1257-i386-cpu-Mark-CPUID-0x80000008-ECX-bits-0-7-12-15-as.patch +Patch1258: 1258-i386-cpu-Fix-number-of-addressable-IDs-field-for-CPU.patch +Patch1259: 1259-i386-cpu-Fix-cpu-number-overflow-in-CPUID.01H.EBX-23.patch +Patch1260: 1260-i386-cpu-Honor-maximum-value-for-CPUID.8000001DH.EAX.patch +Patch1261: 1261-i386-cpu-Reorder-CPUID-leaves-in-cpu_x86_cpuid.patch BuildRequires: meson >= %{meson_version} BuildRequires: zlib-devel @@ -2238,6 +2322,10 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %changelog +* Mon Apr 20 2026 Quanxian Wang - 8.2.2-50 +- [Type] other +- [DESC] Support Intel new topology including module level enabling and Cache topology support + * Thu Apr 16 2026 PkgAgent Robot - 8.2.2-49 - [Type] security - [DESC] Fix CVE-2026-3842 vulnerability in Hyper-V Synthetic Debugging device