Misc HW patch queue
- Script to compare machines compat_props[] (Maksim) - Introduce 'module' CPU topology level (Zhao) - Various cleanups (Thomas, Zhao, Inès, Bernhard) -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmYqN3wACgkQ4+MsLN6t wN4hTw/9FHsItnEkme/864DRPSP7A9mCGa+JfzJmsL8oUb9fBjXXKm+lNchMLu3B uvzfXB2Ea24yf5vyrldo0XlU3i/4GDvqXTI6YFYqBvitGICauYBu+6n2NZh2Y/Pn zZCcVo167o0q7dHu2WSrZ6cSUchsF2C80HjuS07QaN2YZ7QMuN1+uqTjCQ/JHQWA MH4xHh7cXdfCbbv8iNhMWn6sa+Bw/UyfRcc2W6w9cF5Q5cuuTshgDyd0JBOzkM1i Mcul7TuKrSiLUeeeqfTjwtw3rtbNfkelV3ycgvgECFAlzPSjF5a6d/EGdO2zo3T/ aFZnQBYrb4U0SzsmfXFHW7cSylIc1Jn2CCuZZBIvdVcu8TGDD5XsgZbGoCfKdWxp l67qbQJy1Mp3LrRzygJIaxDOfE8fhhRrcIxfK/GoTHaCkqeFRkGjTeiDTVBqAES2 zs6kUYZyG/xGaa2tsMu+HbtSO5EEqPC2QCdHayY3deW42Kwjj/HFV50Ya8YgYSVp gEAjTDOle2dDjlkYud+ymTJz7LnGb3G7q0EZRI9DWolx/bu+uZGQqTSRRre4qFQY SgN576hsFGN4NdM7tyJWiiqD/OC9ZeqUx3gGBtmI52Q6obBCE9hcow0fPs55Tk95 1YzPrt/3IoPI5ZptCoA8DFiysQ46OLtpIsQO9YcrpJmxWyLDSr0= =tm+U -----END PGP SIGNATURE----- Merge tag 'hw-misc-20240425' of https://github.com/philmd/qemu into staging Misc HW patch queue - Script to compare machines compat_props[] (Maksim) - Introduce 'module' CPU topology level (Zhao) - Various cleanups (Thomas, Zhao, Inès, Bernhard) # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmYqN3wACgkQ4+MsLN6t # wN4hTw/9FHsItnEkme/864DRPSP7A9mCGa+JfzJmsL8oUb9fBjXXKm+lNchMLu3B # uvzfXB2Ea24yf5vyrldo0XlU3i/4GDvqXTI6YFYqBvitGICauYBu+6n2NZh2Y/Pn # zZCcVo167o0q7dHu2WSrZ6cSUchsF2C80HjuS07QaN2YZ7QMuN1+uqTjCQ/JHQWA # MH4xHh7cXdfCbbv8iNhMWn6sa+Bw/UyfRcc2W6w9cF5Q5cuuTshgDyd0JBOzkM1i # Mcul7TuKrSiLUeeeqfTjwtw3rtbNfkelV3ycgvgECFAlzPSjF5a6d/EGdO2zo3T/ # aFZnQBYrb4U0SzsmfXFHW7cSylIc1Jn2CCuZZBIvdVcu8TGDD5XsgZbGoCfKdWxp # l67qbQJy1Mp3LrRzygJIaxDOfE8fhhRrcIxfK/GoTHaCkqeFRkGjTeiDTVBqAES2 # zs6kUYZyG/xGaa2tsMu+HbtSO5EEqPC2QCdHayY3deW42Kwjj/HFV50Ya8YgYSVp # gEAjTDOle2dDjlkYud+ymTJz7LnGb3G7q0EZRI9DWolx/bu+uZGQqTSRRre4qFQY # SgN576hsFGN4NdM7tyJWiiqD/OC9ZeqUx3gGBtmI52Q6obBCE9hcow0fPs55Tk95 # 1YzPrt/3IoPI5ZptCoA8DFiysQ46OLtpIsQO9YcrpJmxWyLDSr0= # =tm+U # -----END PGP SIGNATURE----- # gpg: Signature made Thu 25 Apr 2024 03:59:08 AM PDT # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] * tag 'hw-misc-20240425' of https://github.com/philmd/qemu: (22 commits) hw/core: Support module-id in numa configuration hw/core: Introduce module-id as the topology subindex hw/core/machine: Support modules in -smp hw/core/machine: Introduce the module as a CPU topology level hw/i386/pc_sysfw: Remove unused parameter from pc_isa_bios_init() hw/misc : Correct 5 spaces indents in stm32l4x5_exti hw/xtensa: Include missing 'exec/cpu-common.h' in 'bootparam.h' hw/elf_ops: Rename elf_ops.h -> elf_ops.h.inc hw/cxl/cxl-cdat: Make cxl_doe_cdat_init() return boolean hw/cxl/cxl-cdat: Make ct3_build_cdat() return boolean hw/cxl/cxl-cdat: Make ct3_load_cdat() return boolean hw: Add a Kconfig switch for the TYPE_CPU_CLUSTER device hw: Fix problem with the A*MPCORE switches in the Kconfig files hw/riscv/virt: Replace sprintf by g_strdup_printf hw/misc/imx: Replace sprintf() by snprintf() hw/misc/applesmc: Simplify DeviceReset handler target/i386: Move APIC related code to cpu-apic.c hw/core: Remove check on NEED_CPU_H in tcg-cpu-ops.h scripts: add script to compare compatibility properties python/qemu/machine: add method to retrieve QEMUMachine::binary field ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
a118c4aff4
@ -4230,3 +4230,8 @@ Code Coverage Tools
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
S: Odd Fixes
|
||||
F: scripts/coverage/
|
||||
|
||||
Machine development tool
|
||||
M: Maksim Davydov <davydov-max@yandex-team.ru>
|
||||
S: Supported
|
||||
F: scripts/compare-machine-types.py
|
||||
|
@ -383,7 +383,7 @@ static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
|
||||
return "";
|
||||
}
|
||||
|
||||
/* FIXME: This should use elf_ops.h */
|
||||
/* FIXME: This should use elf_ops.h.inc */
|
||||
static int symcmp(const void *s0, const void *s1)
|
||||
{
|
||||
struct elf_sym *sym0 = (struct elf_sym *)s0;
|
||||
|
@ -47,6 +47,7 @@ source watchdog/Kconfig
|
||||
|
||||
# arch Kconfig
|
||||
source arm/Kconfig
|
||||
source cpu/Kconfig
|
||||
source alpha/Kconfig
|
||||
source avr/Kconfig
|
||||
source cris/Kconfig
|
||||
|
@ -486,6 +486,7 @@ config XLNX_ZYNQMP_ARM
|
||||
select AHCI
|
||||
select ARM_GIC
|
||||
select CADENCE
|
||||
select CPU_CLUSTER
|
||||
select DDC
|
||||
select DPCD
|
||||
select SDHCI
|
||||
@ -504,6 +505,7 @@ config XLNX_VERSAL
|
||||
default y
|
||||
depends on TCG && AARCH64
|
||||
select ARM_GIC
|
||||
select CPU_CLUSTER
|
||||
select PL011
|
||||
select CADENCE
|
||||
select VIRTIO_MMIO
|
||||
@ -679,21 +681,6 @@ config ZAURUS
|
||||
select NAND
|
||||
select ECC
|
||||
|
||||
config A9MPCORE
|
||||
bool
|
||||
select A9_GTIMER
|
||||
select A9SCU # snoop control unit
|
||||
select ARM_GIC
|
||||
select ARM_MPTIMER
|
||||
|
||||
config A15MPCORE
|
||||
bool
|
||||
select ARM_GIC
|
||||
|
||||
config ARM11MPCORE
|
||||
bool
|
||||
select ARM11SCU
|
||||
|
||||
config ARMSSE
|
||||
bool
|
||||
select ARM_V7M
|
||||
@ -704,6 +691,7 @@ config ARMSSE
|
||||
select CMSDK_APB_DUALTIMER
|
||||
select CMSDK_APB_UART
|
||||
select CMSDK_APB_WATCHDOG
|
||||
select CPU_CLUSTER
|
||||
select IOTKIT_SECCTL
|
||||
select IOTKIT_SYSCTL
|
||||
select IOTKIT_SYSINFO
|
||||
|
@ -305,7 +305,7 @@ static void *load_at(int fd, off_t offset, size_t size)
|
||||
#define elf_word uint32_t
|
||||
#define elf_sword int32_t
|
||||
#define bswapSZs bswap32s
|
||||
#include "hw/elf_ops.h"
|
||||
#include "hw/elf_ops.h.inc"
|
||||
|
||||
#undef elfhdr
|
||||
#undef elf_phdr
|
||||
@ -327,7 +327,7 @@ static void *load_at(int fd, off_t offset, size_t size)
|
||||
#define elf_sword int64_t
|
||||
#define bswapSZs bswap64s
|
||||
#define SZ 64
|
||||
#include "hw/elf_ops.h"
|
||||
#include "hw/elf_ops.h.inc"
|
||||
|
||||
const char *load_elf_strerror(ssize_t error)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
|
||||
return head;
|
||||
}
|
||||
|
||||
MachineInfoList *qmp_query_machines(Error **errp)
|
||||
MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
|
||||
Error **errp)
|
||||
{
|
||||
GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);
|
||||
MachineInfoList *mach_list = NULL;
|
||||
@ -96,6 +97,26 @@ MachineInfoList *qmp_query_machines(Error **errp)
|
||||
info->default_ram_id = g_strdup(mc->default_ram_id);
|
||||
}
|
||||
|
||||
if (compat_props && mc->compat_props) {
|
||||
int i;
|
||||
info->compat_props = NULL;
|
||||
CompatPropertyList **tail = &(info->compat_props);
|
||||
info->has_compat_props = true;
|
||||
|
||||
for (i = 0; i < mc->compat_props->len; i++) {
|
||||
GlobalProperty *mt_prop = g_ptr_array_index(mc->compat_props,
|
||||
i);
|
||||
CompatProperty *prop;
|
||||
|
||||
prop = g_malloc0(sizeof(*prop));
|
||||
prop->qom_type = g_strdup(mt_prop->driver);
|
||||
prop->property = g_strdup(mt_prop->property);
|
||||
prop->value = g_strdup(mt_prop->value);
|
||||
|
||||
QAPI_LIST_APPEND(tail, prop);
|
||||
}
|
||||
}
|
||||
|
||||
QAPI_LIST_PREPEND(mach_list, info);
|
||||
}
|
||||
|
||||
|
@ -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)) {
|
||||
@ -115,6 +121,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 "
|
||||
@ -185,11 +205,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 */
|
||||
@ -197,22 +219,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;
|
||||
|
||||
@ -222,6 +248,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;
|
||||
@ -266,7 +293,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)
|
||||
|
@ -800,6 +800,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;
|
||||
@ -824,6 +829,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;
|
||||
@ -881,6 +891,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,
|
||||
@ -1157,6 +1168,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;
|
||||
|
||||
@ -1224,6 +1236,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, ", ");
|
||||
|
@ -1,8 +1,17 @@
|
||||
config ARM11MPCORE
|
||||
bool
|
||||
|
||||
config A9MPCORE
|
||||
bool
|
||||
select A9_GTIMER
|
||||
select A9SCU # snoop control unit
|
||||
select ARM_GIC
|
||||
select ARM_MPTIMER
|
||||
|
||||
config A15MPCORE
|
||||
bool
|
||||
select ARM_GIC
|
||||
|
||||
config ARM11MPCORE
|
||||
bool
|
||||
select ARM11SCU
|
||||
|
||||
config CPU_CLUSTER
|
||||
bool
|
||||
|
@ -1,4 +1,5 @@
|
||||
system_ss.add(files('core.c', 'cluster.c'))
|
||||
system_ss.add(files('core.c'))
|
||||
system_ss.add(when: 'CONFIG_CPU_CLUSTER', if_true: files('cluster.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_ARM11MPCORE', if_true: files('arm11mpcore.c'))
|
||||
system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_mpcore.c'))
|
||||
|
@ -44,7 +44,7 @@ static void cdat_len_check(CDATSubHeader *hdr, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void ct3_build_cdat(CDATObject *cdat, Error **errp)
|
||||
static bool ct3_build_cdat(CDATObject *cdat, Error **errp)
|
||||
{
|
||||
g_autofree CDATTableHeader *cdat_header = NULL;
|
||||
g_autofree CDATEntry *cdat_st = NULL;
|
||||
@ -58,7 +58,7 @@ static void ct3_build_cdat(CDATObject *cdat, Error **errp)
|
||||
cdat_header = g_malloc0(sizeof(*cdat_header));
|
||||
if (!cdat_header) {
|
||||
error_setg(errp, "Failed to allocate CDAT header");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
cdat->built_buf_len = cdat->build_cdat_table(&cdat->built_buf,
|
||||
@ -67,14 +67,14 @@ static void ct3_build_cdat(CDATObject *cdat, Error **errp)
|
||||
if (cdat->built_buf_len <= 0) {
|
||||
/* Build later as not all data available yet */
|
||||
cdat->to_update = true;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
cdat->to_update = false;
|
||||
|
||||
cdat_st = g_malloc0(sizeof(*cdat_st) * (cdat->built_buf_len + 1));
|
||||
if (!cdat_st) {
|
||||
error_setg(errp, "Failed to allocate CDAT entry array");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Entry 0 for CDAT header, starts with Entry 1 */
|
||||
@ -109,9 +109,10 @@ static void ct3_build_cdat(CDATObject *cdat, Error **errp)
|
||||
cdat_st[0].length = sizeof(*cdat_header);
|
||||
cdat->entry_len = 1 + cdat->built_buf_len;
|
||||
cdat->entry = g_steal_pointer(&cdat_st);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ct3_load_cdat(CDATObject *cdat, Error **errp)
|
||||
static bool ct3_load_cdat(CDATObject *cdat, Error **errp)
|
||||
{
|
||||
g_autofree CDATEntry *cdat_st = NULL;
|
||||
g_autofree uint8_t *buf = NULL;
|
||||
@ -127,11 +128,11 @@ static void ct3_load_cdat(CDATObject *cdat, Error **errp)
|
||||
&file_size, &error)) {
|
||||
error_setg(errp, "CDAT: File read failed: %s", error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (file_size < sizeof(CDATTableHeader)) {
|
||||
error_setg(errp, "CDAT: File too short");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
i = sizeof(CDATTableHeader);
|
||||
num_ent = 1;
|
||||
@ -139,19 +140,19 @@ static void ct3_load_cdat(CDATObject *cdat, Error **errp)
|
||||
hdr = (CDATSubHeader *)(buf + i);
|
||||
if (i + sizeof(CDATSubHeader) > file_size) {
|
||||
error_setg(errp, "CDAT: Truncated table");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
cdat_len_check(hdr, errp);
|
||||
i += hdr->length;
|
||||
if (i > file_size) {
|
||||
error_setg(errp, "CDAT: Truncated table");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
num_ent++;
|
||||
}
|
||||
if (i != file_size) {
|
||||
error_setg(errp, "CDAT: File length mismatch");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
cdat_st = g_new0(CDATEntry, num_ent);
|
||||
@ -185,16 +186,17 @@ static void ct3_load_cdat(CDATObject *cdat, Error **errp)
|
||||
cdat->entry_len = num_ent;
|
||||
cdat->entry = g_steal_pointer(&cdat_st);
|
||||
cdat->buf = g_steal_pointer(&buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp)
|
||||
bool cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp)
|
||||
{
|
||||
CDATObject *cdat = &cxl_cstate->cdat;
|
||||
|
||||
if (cdat->filename) {
|
||||
ct3_load_cdat(cdat, errp);
|
||||
return ct3_load_cdat(cdat, errp);
|
||||
} else {
|
||||
ct3_build_cdat(cdat, errp);
|
||||
return ct3_build_cdat(cdat, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,7 @@
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
|
||||
static void pc_isa_bios_init(MemoryRegion *rom_memory,
|
||||
MemoryRegion *flash_mem,
|
||||
int ram_size)
|
||||
MemoryRegion *flash_mem)
|
||||
{
|
||||
int isa_bios_size;
|
||||
MemoryRegion *isa_bios;
|
||||
@ -186,7 +185,7 @@ static void pc_system_flash_map(PCMachineState *pcms,
|
||||
|
||||
if (i == 0) {
|
||||
flash_mem = pflash_cfi01_get_memory(system_flash);
|
||||
pc_isa_bios_init(rom_memory, flash_mem, size);
|
||||
pc_isa_bios_init(rom_memory, flash_mem);
|
||||
|
||||
/* Encrypt the pflash boot ROM */
|
||||
if (sev_enabled()) {
|
||||
|
@ -705,8 +705,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
|
||||
cxl_cstate->cdat.build_cdat_table = ct3_build_cdat_table;
|
||||
cxl_cstate->cdat.free_cdat_table = ct3_free_cdat_table;
|
||||
cxl_cstate->cdat.private = ct3d;
|
||||
cxl_doe_cdat_init(cxl_cstate, errp);
|
||||
if (*errp) {
|
||||
if (!cxl_doe_cdat_init(cxl_cstate, errp)) {
|
||||
goto err_free_special_ops;
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ static void applesmc_io_cmd_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
s->data_pos = 0;
|
||||
}
|
||||
|
||||
static struct AppleSMCData *applesmc_find_key(AppleSMCState *s)
|
||||
static const struct AppleSMCData *applesmc_find_key(AppleSMCState *s)
|
||||
{
|
||||
struct AppleSMCData *d;
|
||||
|
||||
@ -161,7 +161,7 @@ static void applesmc_io_data_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
AppleSMCState *s = opaque;
|
||||
struct AppleSMCData *d;
|
||||
const struct AppleSMCData *d;
|
||||
|
||||
smc_debug("DATA received: 0x%02x\n", (uint8_t)val);
|
||||
switch (s->cmd) {
|
||||
@ -269,23 +269,10 @@ static void applesmc_add_key(AppleSMCState *s, const char *key,
|
||||
static void qdev_applesmc_isa_reset(DeviceState *dev)
|
||||
{
|
||||
AppleSMCState *s = APPLE_SMC(dev);
|
||||
struct AppleSMCData *d, *next;
|
||||
|
||||
/* Remove existing entries */
|
||||
QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
|
||||
QLIST_REMOVE(d, node);
|
||||
g_free(d);
|
||||
}
|
||||
s->status = 0x00;
|
||||
s->status_1e = 0x00;
|
||||
s->last_ret = 0x00;
|
||||
|
||||
applesmc_add_key(s, "REV ", 6, "\x01\x13\x0f\x00\x00\x03");
|
||||
applesmc_add_key(s, "OSK0", 32, s->osk);
|
||||
applesmc_add_key(s, "OSK1", 32, s->osk + 32);
|
||||
applesmc_add_key(s, "NATJ", 1, "\0");
|
||||
applesmc_add_key(s, "MSSP", 1, "\0");
|
||||
applesmc_add_key(s, "MSSD", 1, "\0x3");
|
||||
}
|
||||
|
||||
static const MemoryRegionOps applesmc_data_io_ops = {
|
||||
@ -343,6 +330,24 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
QLIST_INIT(&s->data_def);
|
||||
applesmc_add_key(s, "REV ", 6, "\x01\x13\x0f\x00\x00\x03");
|
||||
applesmc_add_key(s, "OSK0", 32, s->osk);
|
||||
applesmc_add_key(s, "OSK1", 32, s->osk + 32);
|
||||
applesmc_add_key(s, "NATJ", 1, "\0");
|
||||
applesmc_add_key(s, "MSSP", 1, "\0");
|
||||
applesmc_add_key(s, "MSSD", 1, "\0x3");
|
||||
}
|
||||
|
||||
static void applesmc_unrealize(DeviceState *dev)
|
||||
{
|
||||
AppleSMCState *s = APPLE_SMC(dev);
|
||||
struct AppleSMCData *d, *next;
|
||||
|
||||
/* Remove existing entries */
|
||||
QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
|
||||
QLIST_REMOVE(d, node);
|
||||
g_free(d);
|
||||
}
|
||||
}
|
||||
|
||||
static Property applesmc_isa_properties[] = {
|
||||
@ -377,6 +382,7 @@ static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
|
||||
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
|
||||
|
||||
dc->realize = applesmc_isa_realize;
|
||||
dc->unrealize = applesmc_unrealize;
|
||||
dc->reset = qdev_applesmc_isa_reset;
|
||||
device_class_set_props(dc, applesmc_isa_properties);
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
|
@ -91,7 +91,7 @@ static const char *imx25_ccm_reg_name(uint32_t reg)
|
||||
case IMX25_CCM_LPIMR1_REG:
|
||||
return "lpimr1";
|
||||
default:
|
||||
sprintf(unknown, "[%u ?]", reg);
|
||||
snprintf(unknown, sizeof(unknown), "[%u ?]", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ static const char *imx31_ccm_reg_name(uint32_t reg)
|
||||
case IMX31_CCM_PDR2_REG:
|
||||
return "PDR2";
|
||||
default:
|
||||
sprintf(unknown, "[%u ?]", reg);
|
||||
snprintf(unknown, sizeof(unknown), "[%u ?]", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ static const char *imx6_ccm_reg_name(uint32_t reg)
|
||||
case CCM_CMEOR:
|
||||
return "CMEOR";
|
||||
default:
|
||||
sprintf(unknown, "%u ?", reg);
|
||||
snprintf(unknown, sizeof(unknown), "%u ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
@ -224,7 +224,7 @@ static const char *imx6_analog_reg_name(uint32_t reg)
|
||||
case USB_ANALOG_DIGPROG:
|
||||
return "USB_ANALOG_DIGPROG";
|
||||
default:
|
||||
sprintf(unknown, "%u ?", reg);
|
||||
snprintf(unknown, sizeof(unknown), "%u ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ static const char *imx6_src_reg_name(uint32_t reg)
|
||||
case SRC_GPR10:
|
||||
return "SRC_GPR10";
|
||||
default:
|
||||
sprintf(unknown, "%u ?", reg);
|
||||
snprintf(unknown, sizeof(unknown), "%u ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ static const char *imx6ul_ccm_reg_name(uint32_t reg)
|
||||
case CCM_CMEOR:
|
||||
return "CMEOR";
|
||||
default:
|
||||
sprintf(unknown, "%u ?", reg);
|
||||
snprintf(unknown, sizeof(unknown), "%u ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
@ -274,7 +274,7 @@ static const char *imx6ul_analog_reg_name(uint32_t reg)
|
||||
case USB_ANALOG_DIGPROG:
|
||||
return "USB_ANALOG_DIGPROG";
|
||||
default:
|
||||
sprintf(unknown, "%u ?", reg);
|
||||
snprintf(unknown, sizeof(unknown), "%u ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ static const char *imx7_src_reg_name(uint32_t reg)
|
||||
case SRC_GPR10:
|
||||
return "SRC_GPR10";
|
||||
default:
|
||||
sprintf(unknown, "%u ?", reg);
|
||||
snprintf(unknown, sizeof(unknown), "%u ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
@ -59,22 +59,22 @@ static const uint32_t exti_romask[EXTI_NUM_REGISTER] = {
|
||||
|
||||
static unsigned regbank_index_by_irq(unsigned irq)
|
||||
{
|
||||
return irq >= EXTI_MAX_IRQ_PER_BANK ? 1 : 0;
|
||||
return irq >= EXTI_MAX_IRQ_PER_BANK ? 1 : 0;
|
||||
}
|
||||
|
||||
static unsigned regbank_index_by_addr(hwaddr addr)
|
||||
{
|
||||
return addr >= EXTI_IMR2 ? 1 : 0;
|
||||
return addr >= EXTI_IMR2 ? 1 : 0;
|
||||
}
|
||||
|
||||
static unsigned valid_mask(unsigned bank)
|
||||
{
|
||||
return MAKE_64BIT_MASK(0, irqs_per_bank[bank]);
|
||||
return MAKE_64BIT_MASK(0, irqs_per_bank[bank]);
|
||||
}
|
||||
|
||||
static unsigned configurable_mask(unsigned bank)
|
||||
{
|
||||
return valid_mask(bank) & ~exti_romask[bank];
|
||||
return valid_mask(bank) & ~exti_romask[bank];
|
||||
}
|
||||
|
||||
static void stm32l4x5_exti_reset_hold(Object *obj, ResetType type)
|
||||
|
@ -41,7 +41,7 @@
|
||||
static const char *imx_default_reg_name(IMXFECState *s, uint32_t index)
|
||||
{
|
||||
static char tmp[20];
|
||||
sprintf(tmp, "index %d", index);
|
||||
snprintf(tmp, sizeof(tmp), "index %d", index);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -338,8 +338,7 @@ static void cxl_usp_realize(PCIDevice *d, Error **errp)
|
||||
cxl_cstate->cdat.build_cdat_table = build_cdat_table;
|
||||
cxl_cstate->cdat.free_cdat_table = free_default_cdat_table;
|
||||
cxl_cstate->cdat.private = d;
|
||||
cxl_doe_cdat_init(cxl_cstate, errp);
|
||||
if (*errp) {
|
||||
if (!cxl_doe_cdat_init(cxl_cstate, errp)) {
|
||||
goto err_cap;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ config IBEX
|
||||
config MICROCHIP_PFSOC
|
||||
bool
|
||||
select CADENCE_SDHCI
|
||||
select CPU_CLUSTER
|
||||
select MCHP_PFSOC_DMC
|
||||
select MCHP_PFSOC_IOSCB
|
||||
select MCHP_PFSOC_MMUART
|
||||
@ -68,6 +69,7 @@ config SIFIVE_E
|
||||
config SIFIVE_U
|
||||
bool
|
||||
select CADENCE
|
||||
select CPU_CLUSTER
|
||||
select RISCV_ACLINT
|
||||
select SIFIVE_GPIO
|
||||
select SIFIVE_PDMA
|
||||
|
@ -1617,10 +1617,8 @@ static void virt_machine_instance_init(Object *obj)
|
||||
static char *virt_get_aia_guests(Object *obj, Error **errp)
|
||||
{
|
||||
RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
|
||||
char val[32];
|
||||
|
||||
sprintf(val, "%d", s->aia_guests);
|
||||
return g_strdup(val);
|
||||
return g_strdup_printf("%d", s->aia_guests);
|
||||
}
|
||||
|
||||
static void virt_set_aia_guests(Object *obj, const char *val, Error **errp)
|
||||
@ -1741,7 +1739,6 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
|
||||
static void virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
char str[128];
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
||||
|
||||
@ -1767,7 +1764,6 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
|
||||
#endif
|
||||
|
||||
|
||||
object_class_property_add_bool(oc, "aclint", virt_get_aclint,
|
||||
virt_set_aclint);
|
||||
object_class_property_set_description(oc, "aclint",
|
||||
@ -1785,9 +1781,14 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
object_class_property_add_str(oc, "aia-guests",
|
||||
virt_get_aia_guests,
|
||||
virt_set_aia_guests);
|
||||
sprintf(str, "Set number of guest MMIO pages for AIA IMSIC. Valid value "
|
||||
"should be between 0 and %d.", VIRT_IRQCHIP_MAX_GUESTS);
|
||||
object_class_property_set_description(oc, "aia-guests", str);
|
||||
{
|
||||
g_autofree char *str =
|
||||
g_strdup_printf("Set number of guest MMIO pages for AIA IMSIC. "
|
||||
"Valid value should be between 0 and %d.",
|
||||
VIRT_IRQCHIP_MAX_GUESTS);
|
||||
object_class_property_set_description(oc, "aia-guests", str);
|
||||
}
|
||||
|
||||
object_class_property_add(oc, "acpi", "OnOffAuto",
|
||||
virt_get_acpi, virt_set_acpi,
|
||||
NULL, NULL);
|
||||
|
@ -53,7 +53,7 @@ static const char *imx_spi_reg_name(uint32_t reg)
|
||||
case ECSPI_MSGDATA:
|
||||
return "ECSPI_MSGDATA";
|
||||
default:
|
||||
sprintf(unknown, "%u ?", reg);
|
||||
snprintf(unknown, sizeof(unknown), "%u ?", reg);
|
||||
return unknown;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef HW_XTENSA_BOOTPARAM_H
|
||||
#define HW_XTENSA_BOOTPARAM_H
|
||||
|
||||
#include "exec/cpu-common.h"
|
||||
|
||||
#define BP_TAG_COMMAND_LINE 0x1001 /* command line (0-terminated string)*/
|
||||
#define BP_TAG_INITRD 0x1002 /* ramdisk addr and size (bp_meminfo) */
|
||||
#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */
|
||||
|
@ -144,6 +144,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;
|
||||
@ -152,6 +153,7 @@ typedef struct {
|
||||
bool has_clusters;
|
||||
bool books_supported;
|
||||
bool drawers_supported;
|
||||
bool modules_supported;
|
||||
} SMPCompatProps;
|
||||
|
||||
/**
|
||||
@ -339,6 +341,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
|
||||
@ -350,6 +353,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;
|
||||
|
@ -49,7 +49,6 @@ struct TCGCPUOps {
|
||||
/** @debug_excp_handler: Callback for handling debug exceptions */
|
||||
void (*debug_excp_handler)(CPUState *cpu);
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/**
|
||||
* @fake_user_interrupt: Callback for 'fake exception' handling.
|
||||
@ -174,8 +173,6 @@ struct TCGCPUOps {
|
||||
*/
|
||||
bool (*need_replay_interrupt)(int interrupt_request);
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
#endif /* NEED_CPU_H */
|
||||
|
||||
};
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
@ -273,7 +273,7 @@ hwaddr cxl_decode_ig(int ig);
|
||||
CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb);
|
||||
bool cxl_get_hb_passthrough(PCIHostState *hb);
|
||||
|
||||
void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp);
|
||||
bool cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp);
|
||||
void cxl_doe_cdat_release(CXLComponentState *cxl_cstate);
|
||||
void cxl_doe_cdat_update(CXLComponentState *cxl_cstate, Error **errp);
|
||||
|
||||
|
@ -3572,7 +3572,7 @@ static const char *lookup_symbolxx(struct syminfo *s, uint64_t orig_addr)
|
||||
return "";
|
||||
}
|
||||
|
||||
/* FIXME: This should use elf_ops.h */
|
||||
/* FIXME: This should use elf_ops.h.inc */
|
||||
static int symcmp(const void *s0, const void *s1)
|
||||
{
|
||||
struct elf_sym *sym0 = (struct elf_sym *)s0;
|
||||
|
@ -328,6 +328,11 @@ class QEMUMachine:
|
||||
"""Returns the list of arguments given to the QEMU binary."""
|
||||
return self._args
|
||||
|
||||
@property
|
||||
def binary(self) -> str:
|
||||
"""Returns path to the QEMU binary"""
|
||||
return self._binary
|
||||
|
||||
def _pre_launch(self) -> None:
|
||||
if self._qmp_set:
|
||||
if self._monitor_address is None:
|
||||
|
@ -135,6 +135,26 @@
|
||||
##
|
||||
{ 'command': 'query-cpus-fast', 'returns': [ 'CpuInfoFast' ] }
|
||||
|
||||
##
|
||||
# @CompatProperty:
|
||||
#
|
||||
# Property default values specific to a machine type, for use by
|
||||
# scripts/compare-machine-types.
|
||||
#
|
||||
# @qom-type: name of the QOM type to which the default applies
|
||||
#
|
||||
# @property: name of its property to which the default applies
|
||||
#
|
||||
# @value: the default value (machine-specific default can overwrite
|
||||
# the "default" default, to avoid this use -machine none)
|
||||
#
|
||||
# Since: 9.1
|
||||
##
|
||||
{ 'struct': 'CompatProperty',
|
||||
'data': { 'qom-type': 'str',
|
||||
'property': 'str',
|
||||
'value': 'str' } }
|
||||
|
||||
##
|
||||
# @MachineInfo:
|
||||
#
|
||||
@ -166,6 +186,14 @@
|
||||
#
|
||||
# @acpi: machine type supports ACPI (since 8.0)
|
||||
#
|
||||
# @compat-props: The machine type's compatibility properties. Only
|
||||
# present when query-machines argument @compat-props is true.
|
||||
# (since 9.1)
|
||||
#
|
||||
# Features:
|
||||
#
|
||||
# @unstable: Member @compat-props is experimental.
|
||||
#
|
||||
# Since: 1.2
|
||||
##
|
||||
{ 'struct': 'MachineInfo',
|
||||
@ -173,18 +201,53 @@
|
||||
'*is-default': 'bool', 'cpu-max': 'int',
|
||||
'hotpluggable-cpus': 'bool', 'numa-mem-supported': 'bool',
|
||||
'deprecated': 'bool', '*default-cpu-type': 'str',
|
||||
'*default-ram-id': 'str', 'acpi': 'bool' } }
|
||||
'*default-ram-id': 'str', 'acpi': 'bool',
|
||||
'*compat-props': { 'type': ['CompatProperty'],
|
||||
'features': ['unstable'] } } }
|
||||
|
||||
##
|
||||
# @query-machines:
|
||||
#
|
||||
# Return a list of supported machines
|
||||
#
|
||||
# @compat-props: if true, also return compatibility properties.
|
||||
# (default: false) (since 9.1)
|
||||
#
|
||||
# Features:
|
||||
#
|
||||
# @unstable: Argument @compat-props is experimental.
|
||||
#
|
||||
# Returns: a list of MachineInfo
|
||||
#
|
||||
# Since: 1.2
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-machines", "arguments": { "compat-props": true } }
|
||||
# <- { "return": [
|
||||
# {
|
||||
# "hotpluggable-cpus": true,
|
||||
# "name": "pc-q35-6.2",
|
||||
# "compat-props": [
|
||||
# {
|
||||
# "qom-type": "virtio-mem",
|
||||
# "property": "unplugged-inaccessible",
|
||||
# "value": "off"
|
||||
# }
|
||||
# ],
|
||||
# "numa-mem-supported": false,
|
||||
# "default-cpu-type": "qemu64-x86_64-cpu",
|
||||
# "cpu-max": 288,
|
||||
# "deprecated": false,
|
||||
# "default-ram-id": "pc.ram"
|
||||
# },
|
||||
# ...
|
||||
# }
|
||||
##
|
||||
{ 'command': 'query-machines', 'returns': ['MachineInfo'] }
|
||||
{ 'command': 'query-machines',
|
||||
'data': { '*compat-props': { 'type': 'bool',
|
||||
'features': [ 'unstable' ] } },
|
||||
'returns': ['MachineInfo'] }
|
||||
|
||||
##
|
||||
# @CurrentMachineParams:
|
||||
@ -925,6 +988,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
|
||||
#
|
||||
# @thread-id: thread number within the core the CPU belongs to
|
||||
@ -942,6 +1008,7 @@
|
||||
'*socket-id': 'int',
|
||||
'*die-id': 'int',
|
||||
'*cluster-id': 'int',
|
||||
'*module-id': 'int',
|
||||
'*core-id': 'int',
|
||||
'*thread-id': 'int'
|
||||
}
|
||||
@ -1633,6 +1700,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
|
||||
@ -1646,6 +1715,7 @@
|
||||
'*sockets': 'int',
|
||||
'*dies': 'int',
|
||||
'*clusters': 'int',
|
||||
'*modules': 'int',
|
||||
'*cores': 'int',
|
||||
'*threads': 'int',
|
||||
'*maxcpus': 'int' } }
|
||||
|
@ -212,6 +212,7 @@ ObjectPropertyInfoList *qmp_qom_list_properties(const char *typename,
|
||||
info->name = g_strdup(prop->name);
|
||||
info->type = g_strdup(prop->type);
|
||||
info->description = g_strdup(prop->description);
|
||||
info->default_value = qobject_ref(prop->defval);
|
||||
|
||||
QAPI_LIST_PREPEND(prop_list, info);
|
||||
}
|
||||
|
486
scripts/compare-machine-types.py
Executable file
486
scripts/compare-machine-types.py
Executable file
@ -0,0 +1,486 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Script to compare machine type compatible properties (include/hw/boards.h).
|
||||
# compat_props are applied to the driver during initialization to change
|
||||
# default values, for instance, to maintain compatibility.
|
||||
# This script constructs table with machines and values of their compat_props
|
||||
# to compare and to find places for improvements or places with bugs. If
|
||||
# during the comparison, some machine type doesn't have a property (it is in
|
||||
# the comparison table because another machine type has it), then the
|
||||
# appropriate method will be used to obtain the default value of this driver
|
||||
# property via qmp command (e.g. query-cpu-model-expansion for x86_64-cpu).
|
||||
# These methods are defined below in qemu_property_methods.
|
||||
#
|
||||
# Copyright (c) Yandex Technologies LLC, 2023
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
from os import path
|
||||
from argparse import ArgumentParser, RawTextHelpFormatter, Namespace
|
||||
import pandas as pd
|
||||
from contextlib import ExitStack
|
||||
from typing import Optional, List, Dict, Generator, Tuple, Union, Any, Set
|
||||
|
||||
try:
|
||||
qemu_dir = path.abspath(path.dirname(path.dirname(__file__)))
|
||||
sys.path.append(path.join(qemu_dir, 'python'))
|
||||
from qemu.machine import QEMUMachine
|
||||
except ModuleNotFoundError as exc:
|
||||
print(f"Module '{exc.name}' not found.")
|
||||
print("Try export PYTHONPATH=top-qemu-dir/python or run from top-qemu-dir")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
default_qemu_args = '-enable-kvm -machine none'
|
||||
default_qemu_binary = 'build/qemu-system-x86_64'
|
||||
|
||||
|
||||
# Methods for gettig the right values of drivers properties
|
||||
#
|
||||
# Use these methods as a 'whitelist' and add entries only if necessary. It's
|
||||
# important to be stable and predictable in analysis and tests.
|
||||
# Be careful:
|
||||
# * Class must be inherited from 'QEMUObject' and used in new_driver()
|
||||
# * Class has to implement get_prop method in order to get values
|
||||
# * Specialization always wins (with the given classes for 'device' and
|
||||
# 'x86_64-cpu', method of 'x86_64-cpu' will be used for '486-x86_64-cpu')
|
||||
|
||||
class Driver():
|
||||
def __init__(self, vm: QEMUMachine, name: str, abstract: bool) -> None:
|
||||
self.vm = vm
|
||||
self.name = name
|
||||
self.abstract = abstract
|
||||
self.parent: Optional[Driver] = None
|
||||
self.property_getter: Optional[Driver] = None
|
||||
|
||||
def get_prop(self, driver: str, prop: str) -> str:
|
||||
if self.property_getter:
|
||||
return self.property_getter.get_prop(driver, prop)
|
||||
else:
|
||||
return 'Unavailable method'
|
||||
|
||||
def is_child_of(self, parent: 'Driver') -> bool:
|
||||
"""Checks whether self is (recursive) child of @parent"""
|
||||
cur_parent = self.parent
|
||||
while cur_parent:
|
||||
if cur_parent is parent:
|
||||
return True
|
||||
cur_parent = cur_parent.parent
|
||||
|
||||
return False
|
||||
|
||||
def set_implementations(self, implementations: List['Driver']) -> None:
|
||||
self.implementations = implementations
|
||||
|
||||
|
||||
class QEMUObject(Driver):
|
||||
def __init__(self, vm: QEMUMachine, name: str) -> None:
|
||||
super().__init__(vm, name, True)
|
||||
|
||||
def set_implementations(self, implementations: List[Driver]) -> None:
|
||||
self.implementations = implementations
|
||||
|
||||
# each implementation of the abstract driver has to use property getter
|
||||
# of this abstract driver unless it has specialization. (e.g. having
|
||||
# 'device' and 'x86_64-cpu', property getter of 'x86_64-cpu' will be
|
||||
# used for '486-x86_64-cpu')
|
||||
for impl in implementations:
|
||||
if not impl.property_getter or\
|
||||
self.is_child_of(impl.property_getter):
|
||||
impl.property_getter = self
|
||||
|
||||
|
||||
class QEMUDevice(QEMUObject):
|
||||
def __init__(self, vm: QEMUMachine) -> None:
|
||||
super().__init__(vm, 'device')
|
||||
self.cached: Dict[str, List[Dict[str, Any]]] = {}
|
||||
|
||||
def get_prop(self, driver: str, prop_name: str) -> str:
|
||||
if driver not in self.cached:
|
||||
self.cached[driver] = self.vm.cmd('device-list-properties',
|
||||
typename=driver)
|
||||
for prop in self.cached[driver]:
|
||||
if prop['name'] == prop_name:
|
||||
return str(prop.get('default-value', 'No default value'))
|
||||
|
||||
return 'Unknown property'
|
||||
|
||||
|
||||
class QEMUx86CPU(QEMUObject):
|
||||
def __init__(self, vm: QEMUMachine) -> None:
|
||||
super().__init__(vm, 'x86_64-cpu')
|
||||
self.cached: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
def get_prop(self, driver: str, prop_name: str) -> str:
|
||||
if not driver.endswith('-x86_64-cpu'):
|
||||
return 'Wrong x86_64-cpu name'
|
||||
|
||||
# crop last 11 chars '-x86_64-cpu'
|
||||
name = driver[:-11]
|
||||
if name not in self.cached:
|
||||
self.cached[name] = self.vm.cmd(
|
||||
'query-cpu-model-expansion', type='full',
|
||||
model={'name': name})['model']['props']
|
||||
return str(self.cached[name].get(prop_name, 'Unknown property'))
|
||||
|
||||
|
||||
# Now it's stub, because all memory_backend types don't have default values
|
||||
# but this behaviour can be changed
|
||||
class QEMUMemoryBackend(QEMUObject):
|
||||
def __init__(self, vm: QEMUMachine) -> None:
|
||||
super().__init__(vm, 'memory-backend')
|
||||
self.cached: Dict[str, List[Dict[str, Any]]] = {}
|
||||
|
||||
def get_prop(self, driver: str, prop_name: str) -> str:
|
||||
if driver not in self.cached:
|
||||
self.cached[driver] = self.vm.cmd('qom-list-properties',
|
||||
typename=driver)
|
||||
for prop in self.cached[driver]:
|
||||
if prop['name'] == prop_name:
|
||||
return str(prop.get('default-value', 'No default value'))
|
||||
|
||||
return 'Unknown property'
|
||||
|
||||
|
||||
def new_driver(vm: QEMUMachine, name: str, is_abstr: bool) -> Driver:
|
||||
if name == 'object':
|
||||
return QEMUObject(vm, 'object')
|
||||
elif name == 'device':
|
||||
return QEMUDevice(vm)
|
||||
elif name == 'x86_64-cpu':
|
||||
return QEMUx86CPU(vm)
|
||||
elif name == 'memory-backend':
|
||||
return QEMUMemoryBackend(vm)
|
||||
else:
|
||||
return Driver(vm, name, is_abstr)
|
||||
# End of methods definition
|
||||
|
||||
|
||||
class VMPropertyGetter:
|
||||
"""It implements the relationship between drivers and how to get their
|
||||
properties"""
|
||||
def __init__(self, vm: QEMUMachine) -> None:
|
||||
self.drivers: Dict[str, Driver] = {}
|
||||
|
||||
qom_all_types = vm.cmd('qom-list-types', abstract=True)
|
||||
self.drivers = {t['name']: new_driver(vm, t['name'],
|
||||
t.get('abstract', False))
|
||||
for t in qom_all_types}
|
||||
|
||||
for t in qom_all_types:
|
||||
drv = self.drivers[t['name']]
|
||||
if 'parent' in t:
|
||||
drv.parent = self.drivers[t['parent']]
|
||||
|
||||
for drv in self.drivers.values():
|
||||
imps = vm.cmd('qom-list-types', implements=drv.name)
|
||||
# only implementations inherit property getter
|
||||
drv.set_implementations([self.drivers[imp['name']]
|
||||
for imp in imps])
|
||||
|
||||
def get_prop(self, driver: str, prop: str) -> str:
|
||||
# wrong driver name or disabled in config driver
|
||||
try:
|
||||
drv = self.drivers[driver]
|
||||
except KeyError:
|
||||
return 'Unavailable driver'
|
||||
|
||||
assert not drv.abstract
|
||||
|
||||
return drv.get_prop(driver, prop)
|
||||
|
||||
def get_implementations(self, driver: str) -> List[str]:
|
||||
return [impl.name for impl in self.drivers[driver].implementations]
|
||||
|
||||
|
||||
class Machine:
|
||||
"""A short QEMU machine type description. It contains only processed
|
||||
compat_props (properties of abstract classes are applied to its
|
||||
implementations)
|
||||
"""
|
||||
# raw_mt_dict - dict produced by `query-machines`
|
||||
def __init__(self, raw_mt_dict: Dict[str, Any],
|
||||
qemu_drivers: VMPropertyGetter) -> None:
|
||||
self.name = raw_mt_dict['name']
|
||||
self.compat_props: Dict[str, Any] = {}
|
||||
# properties are applied sequentially and can rewrite values like in
|
||||
# QEMU. Also it has to resolve class relationships to apply appropriate
|
||||
# values from abstract class to all implementations
|
||||
for prop in raw_mt_dict['compat-props']:
|
||||
driver = prop['qom-type']
|
||||
try:
|
||||
# implementation adds only itself, abstract class adds
|
||||
# lementation (abstract classes are uninterestiong)
|
||||
impls = qemu_drivers.get_implementations(driver)
|
||||
for impl in impls:
|
||||
if impl not in self.compat_props:
|
||||
self.compat_props[impl] = {}
|
||||
self.compat_props[impl][prop['property']] = prop['value']
|
||||
except KeyError:
|
||||
# QEMU doesn't know this driver thus it has to be saved
|
||||
if driver not in self.compat_props:
|
||||
self.compat_props[driver] = {}
|
||||
self.compat_props[driver][prop['property']] = prop['value']
|
||||
|
||||
|
||||
class Configuration():
|
||||
"""Class contains all necessary components to generate table and is used
|
||||
to compare different binaries"""
|
||||
def __init__(self, vm: QEMUMachine,
|
||||
req_mt: List[str], all_mt: bool) -> None:
|
||||
self._vm = vm
|
||||
self._binary = vm.binary
|
||||
self._qemu_args = args.qemu_args.split(' ')
|
||||
|
||||
self._qemu_drivers = VMPropertyGetter(vm)
|
||||
self.req_mt = get_req_mt(self._qemu_drivers, vm, req_mt, all_mt)
|
||||
|
||||
def get_implementations(self, driver_name: str) -> List[str]:
|
||||
return self._qemu_drivers.get_implementations(driver_name)
|
||||
|
||||
def get_table(self, req_props: List[Tuple[str, str]]) -> pd.DataFrame:
|
||||
table: List[pd.DataFrame] = []
|
||||
for mt in self.req_mt:
|
||||
name = f'{self._binary}\n{mt.name}'
|
||||
column = []
|
||||
for driver, prop in req_props:
|
||||
try:
|
||||
# values from QEMU machine type definitions
|
||||
column.append(mt.compat_props[driver][prop])
|
||||
except KeyError:
|
||||
# values from QEMU type definitions
|
||||
column.append(self._qemu_drivers.get_prop(driver, prop))
|
||||
table.append(pd.DataFrame({name: column}))
|
||||
|
||||
return pd.concat(table, axis=1)
|
||||
|
||||
|
||||
script_desc = """Script to compare machine types (their compat_props).
|
||||
|
||||
Examples:
|
||||
* save info about all machines: ./scripts/compare-machine-types.py --all \
|
||||
--format csv --raw > table.csv
|
||||
* compare machines: ./scripts/compare-machine-types.py --mt pc-q35-2.12 \
|
||||
pc-q35-3.0
|
||||
* compare binaries and machines: ./scripts/compare-machine-types.py \
|
||||
--mt pc-q35-6.2 pc-q35-7.0 --qemu-binary build/qemu-system-x86_64 \
|
||||
build/qemu-exp
|
||||
╒════════════╤══════════════════════════╤════════════════════════════\
|
||||
╤════════════════════════════╤══════════════════╤══════════════════╕
|
||||
│ Driver │ Property │ build/qemu-system-x86_64 \
|
||||
│ build/qemu-system-x86_64 │ build/qemu-exp │ build/qemu-exp │
|
||||
│ │ │ pc-q35-6.2 \
|
||||
│ pc-q35-7.0 │ pc-q35-6.2 │ pc-q35-7.0 │
|
||||
╞════════════╪══════════════════════════╪════════════════════════════\
|
||||
╪════════════════════════════╪══════════════════╪══════════════════╡
|
||||
│ PIIX4_PM │ x-not-migrate-acpi-index │ True \
|
||||
│ False │ False │ False │
|
||||
├────────────┼──────────────────────────┼────────────────────────────\
|
||||
┼────────────────────────────┼──────────────────┼──────────────────┤
|
||||
│ virtio-mem │ unplugged-inaccessible │ False \
|
||||
│ auto │ False │ auto │
|
||||
╘════════════╧══════════════════════════╧════════════════════════════\
|
||||
╧════════════════════════════╧══════════════════╧══════════════════╛
|
||||
|
||||
If a property from QEMU machine defintion applies to an abstract class (e.g. \
|
||||
x86_64-cpu) this script will compare all implementations of this class.
|
||||
|
||||
"Unavailable method" - means that this script doesn't know how to get \
|
||||
default values of the driver. To add method use the construction described \
|
||||
at the top of the script.
|
||||
"Unavailable driver" - means that this script doesn't know this driver. \
|
||||
For instance, this can happen if you configure QEMU without this device or \
|
||||
if machine type definition has error.
|
||||
"No default value" - means that the appropriate method can't get the default \
|
||||
value and most likely that this property doesn't have it.
|
||||
"Unknown property" - means that the appropriate method can't find property \
|
||||
with this name."""
|
||||
|
||||
|
||||
def parse_args() -> Namespace:
|
||||
parser = ArgumentParser(formatter_class=RawTextHelpFormatter,
|
||||
description=script_desc)
|
||||
parser.add_argument('--format', choices=['human-readable', 'json', 'csv'],
|
||||
default='human-readable',
|
||||
help='returns table in json format')
|
||||
parser.add_argument('--raw', action='store_true',
|
||||
help='prints ALL defined properties without value '
|
||||
'transformation. By default, only rows '
|
||||
'with different values will be printed and '
|
||||
'values will be transformed(e.g. "on" -> True)')
|
||||
parser.add_argument('--qemu-args', default=default_qemu_args,
|
||||
help='command line to start qemu. '
|
||||
f'Default: "{default_qemu_args}"')
|
||||
parser.add_argument('--qemu-binary', nargs="*", type=str,
|
||||
default=[default_qemu_binary],
|
||||
help='list of qemu binaries that will be compared. '
|
||||
f'Deafult: {default_qemu_binary}')
|
||||
|
||||
mt_args_group = parser.add_mutually_exclusive_group()
|
||||
mt_args_group.add_argument('--all', action='store_true',
|
||||
help='prints all available machine types (list '
|
||||
'of machine types will be ignored)')
|
||||
mt_args_group.add_argument('--mt', nargs="*", type=str,
|
||||
help='list of Machine Types '
|
||||
'that will be compared')
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def mt_comp(mt: Machine) -> Tuple[str, int, int, int]:
|
||||
"""Function to compare and sort machine by names.
|
||||
It returns socket_name, major version, minor version, revision"""
|
||||
# none, microvm, x-remote and etc.
|
||||
if '-' not in mt.name or '.' not in mt.name:
|
||||
return mt.name, 0, 0, 0
|
||||
|
||||
socket, ver = mt.name.rsplit('-', 1)
|
||||
ver_list = list(map(int, ver.split('.', 2)))
|
||||
ver_list += [0] * (3 - len(ver_list))
|
||||
return socket, ver_list[0], ver_list[1], ver_list[2]
|
||||
|
||||
|
||||
def get_mt_definitions(qemu_drivers: VMPropertyGetter,
|
||||
vm: QEMUMachine) -> List[Machine]:
|
||||
"""Constructs list of machine definitions (primarily compat_props) via
|
||||
info from QEMU"""
|
||||
raw_mt_defs = vm.cmd('query-machines', compat_props=True)
|
||||
mt_defs = []
|
||||
for raw_mt in raw_mt_defs:
|
||||
mt_defs.append(Machine(raw_mt, qemu_drivers))
|
||||
|
||||
mt_defs.sort(key=mt_comp)
|
||||
return mt_defs
|
||||
|
||||
|
||||
def get_req_mt(qemu_drivers: VMPropertyGetter, vm: QEMUMachine,
|
||||
req_mt: Optional[List[str]], all_mt: bool) -> List[Machine]:
|
||||
"""Returns list of requested by user machines"""
|
||||
mt_defs = get_mt_definitions(qemu_drivers, vm)
|
||||
if all_mt:
|
||||
return mt_defs
|
||||
|
||||
if req_mt is None:
|
||||
print('Enter machine types for comparision')
|
||||
exit(0)
|
||||
|
||||
matched_mt = []
|
||||
for mt in mt_defs:
|
||||
if mt.name in req_mt:
|
||||
matched_mt.append(mt)
|
||||
|
||||
return matched_mt
|
||||
|
||||
|
||||
def get_affected_props(configs: List[Configuration]) -> Generator[Tuple[str,
|
||||
str],
|
||||
None, None]:
|
||||
"""Helps to go through all affected in machine definitions drivers
|
||||
and properties"""
|
||||
driver_props: Dict[str, Set[Any]] = {}
|
||||
for config in configs:
|
||||
for mt in config.req_mt:
|
||||
compat_props = mt.compat_props
|
||||
for driver, prop in compat_props.items():
|
||||
if driver not in driver_props:
|
||||
driver_props[driver] = set()
|
||||
driver_props[driver].update(prop.keys())
|
||||
|
||||
for driver, props in sorted(driver_props.items()):
|
||||
for prop in sorted(props):
|
||||
yield driver, prop
|
||||
|
||||
|
||||
def transform_value(value: str) -> Union[str, bool]:
|
||||
true_list = ['true', 'on']
|
||||
false_list = ['false', 'off']
|
||||
|
||||
out = value.lower()
|
||||
|
||||
if out in true_list:
|
||||
return True
|
||||
|
||||
if out in false_list:
|
||||
return False
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def simplify_table(table: pd.DataFrame) -> pd.DataFrame:
|
||||
"""transforms values to make it easier to compare it and drops rows
|
||||
with the same values for all columns"""
|
||||
|
||||
table = table.map(transform_value)
|
||||
|
||||
return table[~table.iloc[:, 3:].eq(table.iloc[:, 2], axis=0).all(axis=1)]
|
||||
|
||||
|
||||
# constructs table in the format:
|
||||
#
|
||||
# Driver | Property | binary1 | binary1 | ...
|
||||
# | | machine1 | machine2 | ...
|
||||
# ------------------------------------------------------ ...
|
||||
# driver1 | property1 | value1 | value2 | ...
|
||||
# driver1 | property2 | value3 | value4 | ...
|
||||
# driver2 | property3 | value5 | value6 | ...
|
||||
# ... | ... | ... | ... | ...
|
||||
#
|
||||
def fill_prop_table(configs: List[Configuration],
|
||||
is_raw: bool) -> pd.DataFrame:
|
||||
req_props = list(get_affected_props(configs))
|
||||
if not req_props:
|
||||
print('No drivers to compare. Check machine names')
|
||||
exit(0)
|
||||
|
||||
driver_col, prop_col = tuple(zip(*req_props))
|
||||
table = [pd.DataFrame({'Driver': driver_col}),
|
||||
pd.DataFrame({'Property': prop_col})]
|
||||
|
||||
table.extend([config.get_table(req_props) for config in configs])
|
||||
|
||||
df_table = pd.concat(table, axis=1)
|
||||
|
||||
if is_raw:
|
||||
return df_table
|
||||
|
||||
return simplify_table(df_table)
|
||||
|
||||
|
||||
def print_table(table: pd.DataFrame, table_format: str) -> None:
|
||||
if table_format == 'json':
|
||||
print(comp_table.to_json())
|
||||
elif table_format == 'csv':
|
||||
print(comp_table.to_csv())
|
||||
else:
|
||||
print(comp_table.to_markdown(index=False, stralign='center',
|
||||
colalign=('center',), headers='keys',
|
||||
tablefmt='fancy_grid',
|
||||
disable_numparse=True))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = parse_args()
|
||||
with ExitStack() as stack:
|
||||
vms = [stack.enter_context(QEMUMachine(binary=binary, qmp_timer=15,
|
||||
args=args.qemu_args.split(' '))) for binary in args.qemu_binary]
|
||||
|
||||
configurations = []
|
||||
for vm in vms:
|
||||
vm.launch()
|
||||
configurations.append(Configuration(vm, args.mt, args.all))
|
||||
|
||||
comp_table = fill_prop_table(configurations, args.raw)
|
||||
if not comp_table.empty:
|
||||
print_table(comp_table, args.format)
|
@ -741,6 +741,9 @@ static QemuOptsList qemu_smp_opts = {
|
||||
}, {
|
||||
.name = "clusters",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
}, {
|
||||
.name = "modules",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
}, {
|
||||
.name = "cores",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
|
112
target/i386/cpu-apic.c
Normal file
112
target/i386/cpu-apic.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* QEMU x86 CPU <-> APIC
|
||||
*
|
||||
* Copyright (c) 2003-2004 Fabrice Bellard
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/error.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "monitor/hmp-target.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/xen.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/i386/apic_internal.h"
|
||||
#include "cpu-internal.h"
|
||||
|
||||
APICCommonClass *apic_get_class(Error **errp)
|
||||
{
|
||||
const char *apic_type = "apic";
|
||||
|
||||
/* TODO: in-kernel irqchip for hvf */
|
||||
if (kvm_enabled()) {
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
error_setg(errp, "KVM does not support userspace APIC");
|
||||
return NULL;
|
||||
}
|
||||
apic_type = "kvm-apic";
|
||||
} else if (xen_enabled()) {
|
||||
apic_type = "xen-apic";
|
||||
} else if (whpx_apic_in_platform()) {
|
||||
apic_type = "whpx-apic";
|
||||
}
|
||||
|
||||
return APIC_COMMON_CLASS(object_class_by_name(apic_type));
|
||||
}
|
||||
|
||||
void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
|
||||
{
|
||||
APICCommonState *apic;
|
||||
APICCommonClass *apic_class = apic_get_class(errp);
|
||||
|
||||
if (!apic_class) {
|
||||
return;
|
||||
}
|
||||
|
||||
cpu->apic_state = DEVICE(object_new_with_class(OBJECT_CLASS(apic_class)));
|
||||
object_property_add_child(OBJECT(cpu), "lapic",
|
||||
OBJECT(cpu->apic_state));
|
||||
object_unref(OBJECT(cpu->apic_state));
|
||||
|
||||
/* TODO: convert to link<> */
|
||||
apic = APIC_COMMON(cpu->apic_state);
|
||||
apic->cpu = cpu;
|
||||
apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
|
||||
|
||||
/*
|
||||
* apic_common_set_id needs to check if the CPU has x2APIC
|
||||
* feature in case APIC ID >= 255, so we need to set apic->cpu
|
||||
* before setting APIC ID
|
||||
*/
|
||||
qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
|
||||
}
|
||||
|
||||
void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
|
||||
{
|
||||
APICCommonState *apic;
|
||||
static bool apic_mmio_map_once;
|
||||
|
||||
if (cpu->apic_state == NULL) {
|
||||
return;
|
||||
}
|
||||
qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
|
||||
|
||||
/* Map APIC MMIO area */
|
||||
apic = APIC_COMMON(cpu->apic_state);
|
||||
if (!apic_mmio_map_once) {
|
||||
memory_region_add_subregion_overlap(get_system_memory(),
|
||||
apic->apicbase &
|
||||
MSR_IA32_APICBASE_BASE,
|
||||
&apic->io_memory,
|
||||
0x1000);
|
||||
apic_mmio_map_once = true;
|
||||
}
|
||||
}
|
||||
|
||||
void hmp_info_local_apic(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
if (qdict_haskey(qdict, "apic-id")) {
|
||||
int id = qdict_get_try_int(qdict, "apic-id", 0);
|
||||
|
||||
cs = cpu_by_arch_id(id);
|
||||
if (cs) {
|
||||
cpu_synchronize_state(cs);
|
||||
}
|
||||
} else {
|
||||
cs = mon_get_cpu(mon);
|
||||
}
|
||||
|
||||
|
||||
if (!cs) {
|
||||
monitor_printf(mon, "No CPU available\n");
|
||||
return;
|
||||
}
|
||||
x86_cpu_dump_local_apic_state(cs, CPU_DUMP_FPU);
|
||||
}
|
@ -19,19 +19,12 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/xen.h"
|
||||
#include "sysemu/whpx.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-visit-run-state.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qom/qom-qobject.h"
|
||||
#include "qapi/qapi-commands-machine-target.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/i386/apic_internal.h"
|
||||
|
||||
#include "cpu-internal.h"
|
||||
|
||||
@ -273,75 +266,6 @@ void x86_cpu_machine_reset_cb(void *opaque)
|
||||
cpu_reset(CPU(cpu));
|
||||
}
|
||||
|
||||
APICCommonClass *apic_get_class(Error **errp)
|
||||
{
|
||||
const char *apic_type = "apic";
|
||||
|
||||
/* TODO: in-kernel irqchip for hvf */
|
||||
if (kvm_enabled()) {
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
error_setg(errp, "KVM does not support userspace APIC");
|
||||
return NULL;
|
||||
}
|
||||
apic_type = "kvm-apic";
|
||||
} else if (xen_enabled()) {
|
||||
apic_type = "xen-apic";
|
||||
} else if (whpx_apic_in_platform()) {
|
||||
apic_type = "whpx-apic";
|
||||
}
|
||||
|
||||
return APIC_COMMON_CLASS(object_class_by_name(apic_type));
|
||||
}
|
||||
|
||||
void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
|
||||
{
|
||||
APICCommonState *apic;
|
||||
APICCommonClass *apic_class = apic_get_class(errp);
|
||||
|
||||
if (!apic_class) {
|
||||
return;
|
||||
}
|
||||
|
||||
cpu->apic_state = DEVICE(object_new_with_class(OBJECT_CLASS(apic_class)));
|
||||
object_property_add_child(OBJECT(cpu), "lapic",
|
||||
OBJECT(cpu->apic_state));
|
||||
object_unref(OBJECT(cpu->apic_state));
|
||||
|
||||
/* TODO: convert to link<> */
|
||||
apic = APIC_COMMON(cpu->apic_state);
|
||||
apic->cpu = cpu;
|
||||
apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
|
||||
|
||||
/*
|
||||
* apic_common_set_id needs to check if the CPU has x2APIC
|
||||
* feature in case APIC ID >= 255, so we need to set apic->cpu
|
||||
* before setting APIC ID
|
||||
*/
|
||||
qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
|
||||
}
|
||||
|
||||
void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
|
||||
{
|
||||
APICCommonState *apic;
|
||||
static bool apic_mmio_map_once;
|
||||
|
||||
if (cpu->apic_state == NULL) {
|
||||
return;
|
||||
}
|
||||
qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
|
||||
|
||||
/* Map APIC MMIO area */
|
||||
apic = APIC_COMMON(cpu->apic_state);
|
||||
if (!apic_mmio_map_once) {
|
||||
memory_region_add_subregion_overlap(get_system_memory(),
|
||||
apic->apicbase &
|
||||
MSR_IA32_APICBASE_BASE,
|
||||
&apic->io_memory,
|
||||
0x1000);
|
||||
apic_mmio_map_once = true;
|
||||
}
|
||||
}
|
||||
|
||||
GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
@ -385,4 +309,3 @@ void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v,
|
||||
errp);
|
||||
qapi_free_GuestPanicInformation(panic_info);
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ i386_system_ss.add(files(
|
||||
'arch_memory_mapping.c',
|
||||
'machine.c',
|
||||
'monitor.c',
|
||||
'cpu-apic.c',
|
||||
'cpu-sysemu.c',
|
||||
))
|
||||
i386_system_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-sysemu-stub.c'))
|
||||
|
@ -28,8 +28,6 @@
|
||||
#include "monitor/hmp-target.h"
|
||||
#include "monitor/hmp.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc-target.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
@ -647,26 +645,3 @@ const MonitorDef *target_monitor_defs(void)
|
||||
{
|
||||
return monitor_defs;
|
||||
}
|
||||
|
||||
void hmp_info_local_apic(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
if (qdict_haskey(qdict, "apic-id")) {
|
||||
int id = qdict_get_try_int(qdict, "apic-id", 0);
|
||||
|
||||
cs = cpu_by_arch_id(id);
|
||||
if (cs) {
|
||||
cpu_synchronize_state(cs);
|
||||
}
|
||||
} else {
|
||||
cs = mon_get_cpu(mon);
|
||||
}
|
||||
|
||||
|
||||
if (!cs) {
|
||||
monitor_printf(mon, "No CPU available\n");
|
||||
return;
|
||||
}
|
||||
x86_cpu_dump_local_apic_state(cs, CPU_DUMP_FPU);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ static void qos_set_machines_devices_available(void)
|
||||
MachineInfoList *mach_info;
|
||||
ObjectTypeInfoList *type_info;
|
||||
|
||||
mach_info = qmp_query_machines(&error_abort);
|
||||
mach_info = qmp_query_machines(false, false, &error_abort);
|
||||
machines_apply_to_node(mach_info);
|
||||
qapi_free_MachineInfoList(mach_info);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user