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:
Richard Henderson 2024-04-25 09:43:29 -07:00
commit a118c4aff4
43 changed files with 858 additions and 197 deletions

View File

@ -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

View File

@ -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;

View File

@ -47,6 +47,7 @@ source watchdog/Kconfig
# arch Kconfig
source arm/Kconfig
source cpu/Kconfig
source alpha/Kconfig
source avr/Kconfig
source cris/Kconfig

View File

@ -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

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)

View File

@ -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, ", ");

View File

@ -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

View File

@ -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'))

View File

@ -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);
}
}

View File

@ -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()) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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) */

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

@ -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' } }

View File

@ -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
View 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)

View File

@ -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
View 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);
}

View File

@ -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);
}

View File

@ -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'))

View File

@ -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);
}

View File

@ -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);