diff mbox

[6/6] qapi: discriminate CpuInfo[Fast] on SysEmuTarget, not CpuInfoArch

Message ID 20180424214550.32549-7-lersek@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Laszlo Ersek April 24, 2018, 9:45 p.m. UTC
Add a new field @target (of type @SysEmuTarget) to the outputs of the
@query-cpus and @query-cpus-fast commands, which provides more information
about the emulation target than the field @arch (of type @CpuInfoArch).
Keep @arch for compatibility.

Make @target the new discriminator for the @CpuInfo and @CpuInfoFast
return structures. This lets us hoist @arch to @CpuInfoCommon, but it also
requires some gymnastics in qmp_query_cpus() and qmp_query_cpus_fast().

In particular, conditional compilation cannot be removed, because each
pair of CPU base arch structures, such as X86CPU/CPUX86State,
PowerPCCPU/CPUPPCState, SPARCCPU/CPUSPARCState, is only visible when
building QEMU for a target that maps to that CPU base arch.

Cc: Eric Blake <eblake@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---

Notes:
    PATCHv1:
    
    - new patch

 qapi/misc.json | 118 ++++++++++++++++++-------
 cpus.c         | 275 ++++++++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 291 insertions(+), 102 deletions(-)

Comments

Markus Armbruster April 25, 2018, 7:33 a.m. UTC | #1
Laszlo Ersek <lersek@redhat.com> writes:

> Add a new field @target (of type @SysEmuTarget) to the outputs of the
> @query-cpus and @query-cpus-fast commands, which provides more information
> about the emulation target than the field @arch (of type @CpuInfoArch).
> Keep @arch for compatibility.
>
> Make @target the new discriminator for the @CpuInfo and @CpuInfoFast
> return structures. This lets us hoist @arch to @CpuInfoCommon, but it also
> requires some gymnastics in qmp_query_cpus() and qmp_query_cpus_fast().
>
> In particular, conditional compilation cannot be removed, because each
> pair of CPU base arch structures, such as X86CPU/CPUX86State,
> PowerPCCPU/CPUPPCState, SPARCCPU/CPUSPARCState, is only visible when
> building QEMU for a target that maps to that CPU base arch.
>
> Cc: Eric Blake <eblake@redhat.com>
> Cc: Markus Armbruster <armbru@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
> Cc: Richard Henderson <rth@twiddle.net>
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
> ---
>
> Notes:
>     PATCHv1:
>     
>     - new patch
>
>  qapi/misc.json | 118 ++++++++++++++++++-------
>  cpus.c         | 275 ++++++++++++++++++++++++++++++++++++++++++---------------
>  2 files changed, 291 insertions(+), 102 deletions(-)
>
> diff --git a/qapi/misc.json b/qapi/misc.json
> index d7b776a5af37..98c15880f9f0 100644
> --- a/qapi/misc.json
> +++ b/qapi/misc.json
> @@ -361,77 +361,105 @@
>  # Collects fields common to @CpuInfoBase and @CpuInfoFastBase; that is,
>  # fields that are shared by @query-cpus and @query-cpus-fast, and not
>  # specific to the target architecture.
>  #
>  # @qom-path: path to the CPU object in the QOM tree (since 2.4)
>  #
>  # @thread-id: ID of the underlying host thread
>  #
>  # @props: properties describing which node/socket/core/thread the
>  #         virtual CPU belongs to, if supported by the board (since 2.10)
>  #
> +# @arch: base architecture of the cpu (since 2.6)
> +#
>  # Since: 2.13
>  ##
>  { 'struct' : 'CpuInfoCommon',
>    'data'   : { 'qom-path'  : 'str',
>                 'thread-id' : 'int',
> -               '*props'    : 'CpuInstanceProperties' } }
> +               '*props'    : 'CpuInstanceProperties',
> +               'arch'      : 'CpuInfoArch' } }
>  
>  ##
>  # @CpuInfoBase:
>  #
>  # Extends @CpuInfoCommon with fields that are specific to the @query-cpus
>  # command, but not specific to the target architecture.
>  #
>  # @CPU: the index of the virtual CPU
>  #
>  # @current: this only exists for backwards compatibility and should be ignored
>  #
>  # @halted: true if the virtual CPU is in the halt state.  Halt usually refers
>  #          to a processor specific low power mode.
>  #
> -# @arch: architecture of the cpu, which determines which additional fields
> -#        will be listed (since 2.6)
> +# @target: the QEMU system emulation target, which is more specific than
> +#          @arch and determines which additional fields will be listed
> +#
>  #
>  # Since: 2.13
>  #
>  # Notes: @halted is a transient state that changes frequently.  By the time the
>  #        data is sent to the client, the guest may no longer be halted.
> -#        Moreover, @arch cannot be moved up to @CpuInfoCommon because
> +#        Moreover, @target cannot be moved up to @CpuInfoCommon because
>  #        that would prevent its use as the discriminator in @CpuInfo.
>  ##
>  { 'struct' : 'CpuInfoBase',
>    'base'   : 'CpuInfoCommon',
>    'data'   : { 'CPU'     : 'int',
>                 'current' : 'bool',
>                 'halted'  : 'bool',
> -               'arch'    : 'CpuInfoArch' } }
> +               'target'  : 'SysEmuTarget' } }
>  
>  ##
>  # @CpuInfo:
>  #
>  # Information about a virtual CPU
>  #
>  # Since: 0.14.0
>  ##
> -{ 'union': 'CpuInfo',
> -  'base': 'CpuInfoBase',
> -  'discriminator': 'arch',
> -  'data': { 'x86': 'CpuInfoX86',
> -            'sparc': 'CpuInfoSPARC',
> -            'ppc': 'CpuInfoPPC',
> -            'mips': 'CpuInfoMIPS',
> -            'tricore': 'CpuInfoTricore',
> -            's390': 'CpuInfoS390',
> -            'riscv': 'CpuInfoRISCV',
> -            'other': 'CpuInfoOther' } }
> +{ 'union'         : 'CpuInfo',
> +  'base'          : 'CpuInfoBase',
> +  'discriminator' : 'target',
> +  'data'          : { 'i386'         : 'CpuInfoX86',
> +                      'x86_64'       : 'CpuInfoX86',
> +                      'sparc'        : 'CpuInfoSPARC',
> +                      'sparc64'      : 'CpuInfoSPARC',
> +                      'ppc'          : 'CpuInfoPPC',
> +                      'ppcemb'       : 'CpuInfoPPC',
> +                      'ppc64'        : 'CpuInfoPPC',
> +                      'mips'         : 'CpuInfoMIPS',
> +                      'mipsel'       : 'CpuInfoMIPS',
> +                      'mips64'       : 'CpuInfoMIPS',
> +                      'mips64el'     : 'CpuInfoMIPS',
> +                      'tricore'      : 'CpuInfoTricore',
> +                      's390x'        : 'CpuInfoS390',
> +                      'riscv32'      : 'CpuInfoRISCV',
> +                      'riscv64'      : 'CpuInfoRISCV',
> +                      'aarch64'      : 'CpuInfoOther',
> +                      'alpha'        : 'CpuInfoOther',
> +                      'arm'          : 'CpuInfoOther',
> +                      'cris'         : 'CpuInfoOther',
> +                      'hppa'         : 'CpuInfoOther',
> +                      'lm32'         : 'CpuInfoOther',
> +                      'm68k'         : 'CpuInfoOther',
> +                      'microblaze'   : 'CpuInfoOther',
> +                      'microblazeel' : 'CpuInfoOther',
> +                      'moxie'        : 'CpuInfoOther',
> +                      'nios2'        : 'CpuInfoOther',
> +                      'or1k'         : 'CpuInfoOther',
> +                      'sh4'          : 'CpuInfoOther',
> +                      'sh4eb'        : 'CpuInfoOther',
> +                      'unicore32'    : 'CpuInfoOther',
> +                      'xtensa'       : 'CpuInfoOther',
> +                      'xtensaeb'     : 'CpuInfoOther' } }
>  
>  ##
>  # @CpuInfoX86:
>  #
>  # Additional information about a virtual i386 or x86_64 CPU
>  #
>  # @pc: the 64-bit instruction pointer
>  #
>  # Since: 2.6
>  ##
>  { 'struct': 'CpuInfoX86', 'data': { 'pc': 'int' } }
> @@ -543,84 +571,110 @@
>  #
>  # Example:
>  #
>  # -> { "execute": "query-cpus" }
>  # <- { "return": [
>  #          {
>  #             "CPU":0,
>  #             "current":true,
>  #             "halted":false,
>  #             "qom-path":"/machine/unattached/device[0]",
>  #             "arch":"x86",
> +#             "target":"x86_64",
>  #             "pc":3227107138,
>  #             "thread-id":3134
>  #          },
>  #          {
>  #             "CPU":1,
>  #             "current":false,
>  #             "halted":true,
>  #             "qom-path":"/machine/unattached/device[2]",
>  #             "arch":"x86",
> +#             "target":"x86_64",
>  #             "pc":7108165,
>  #             "thread-id":3135
>  #          }
>  #       ]
>  #    }
>  #
>  # Notes: This interface is deprecated (since 2.12.0), and it is strongly
>  #        recommended that you avoid using it. Use @query-cpus-fast to
>  #        obtain information about virtual CPUs.
>  #
>  ##
>  { 'command': 'query-cpus', 'returns': ['CpuInfo'] }
>  
>  ##
>  # @CpuInfoFastBase:
>  #
>  # Extends @CpuInfoCommon with fields that are specific to the
>  # @query-cpus-fast command, but not specific to the target architecture.
>  #
>  # @cpu-index: index of the virtual CPU
>  #
> -# @arch: architecture of the cpu, which determines which additional fields
> -#        will be listed
> +# @target: the QEMU system emulation target, which is more specific than
> +#          @arch and determines which additional fields will be listed
>  #
>  # Since: 2.13
>  #
> -# Notes: @arch cannot be moved up to @CpuInfoCommon because that would
> +# Notes: @target cannot be moved up to @CpuInfoCommon because that would
>  #        prevent its use as the discriminator in @CpuInfoFast.
>  ##
>  { 'struct' : 'CpuInfoFastBase',
>    'base'   : 'CpuInfoCommon',
>    'data'   : { 'cpu-index' : 'int',
> -               'arch'      : 'CpuInfoArch' } }
> +               'target'    : 'SysEmuTarget' } }
>  
>  ##
>  # @CpuInfoFast:
>  #
>  # Information about a virtual CPU
>  #
>  # Since: 2.12
>  #
>  ##
> -{ 'union': 'CpuInfoFast',
> -  'base': 'CpuInfoFastBase',
> -  'discriminator': 'arch',
> -  'data': { 'x86': 'CpuInfoOther',
> -            'sparc': 'CpuInfoOther',
> -            'ppc': 'CpuInfoOther',
> -            'mips': 'CpuInfoOther',
> -            'tricore': 'CpuInfoOther',
> -            's390': 'CpuInfoS390',
> -            'riscv': 'CpuInfoOther',
> -            'other': 'CpuInfoOther' } }
> +{ 'union'         : 'CpuInfoFast',
> +  'base'          : 'CpuInfoFastBase',
> +  'discriminator' : 'target',
> +  'data'          : { 'i386'         : 'CpuInfoOther',
> +                      'x86_64'       : 'CpuInfoOther',
> +                      'sparc'        : 'CpuInfoOther',
> +                      'sparc64'      : 'CpuInfoOther',
> +                      'ppc'          : 'CpuInfoOther',
> +                      'ppcemb'       : 'CpuInfoOther',
> +                      'ppc64'        : 'CpuInfoOther',
> +                      'mips'         : 'CpuInfoOther',
> +                      'mipsel'       : 'CpuInfoOther',
> +                      'mips64'       : 'CpuInfoOther',
> +                      'mips64el'     : 'CpuInfoOther',
> +                      'tricore'      : 'CpuInfoOther',
> +                      's390x'        : 'CpuInfoS390',
> +                      'riscv32'      : 'CpuInfoOther',
> +                      'riscv64'      : 'CpuInfoOther',
> +                      'aarch64'      : 'CpuInfoOther',
> +                      'alpha'        : 'CpuInfoOther',
> +                      'arm'          : 'CpuInfoOther',
> +                      'cris'         : 'CpuInfoOther',
> +                      'hppa'         : 'CpuInfoOther',
> +                      'lm32'         : 'CpuInfoOther',
> +                      'm68k'         : 'CpuInfoOther',
> +                      'microblaze'   : 'CpuInfoOther',
> +                      'microblazeel' : 'CpuInfoOther',
> +                      'moxie'        : 'CpuInfoOther',
> +                      'nios2'        : 'CpuInfoOther',
> +                      'or1k'         : 'CpuInfoOther',
> +                      'sh4'          : 'CpuInfoOther',
> +                      'sh4eb'        : 'CpuInfoOther',
> +                      'unicore32'    : 'CpuInfoOther',
> +                      'xtensa'       : 'CpuInfoOther',
> +                      'xtensaeb'     : 'CpuInfoOther' } }
>  
>  ##
>  # @query-cpus-fast:
>  #
>  # Returns information about all virtual CPUs. This command does not
>  # incur a performance penalty and should be used in production
>  # instead of query-cpus.
>  #
>  # Returns: list of @CpuInfoFast
>  #
>  # Since: 2.12
> @@ -630,33 +684,35 @@
>  # -> { "execute": "query-cpus-fast" }
>  # <- { "return": [
>  #         {
>  #             "thread-id": 25627,
>  #             "props": {
>  #                 "core-id": 0,
>  #                 "thread-id": 0,
>  #                 "socket-id": 0
>  #             },
>  #             "qom-path": "/machine/unattached/device[0]",
>  #             "arch":"x86",
> +#             "target":"x86_64",
>  #             "cpu-index": 0
>  #         },
>  #         {
>  #             "thread-id": 25628,
>  #             "props": {
>  #                 "core-id": 0,
>  #                 "thread-id": 0,
>  #                 "socket-id": 1
>  #             },
>  #             "qom-path": "/machine/unattached/device[2]",
>  #             "arch":"x86",
> +#             "target":"x86_64",
>  #             "cpu-index": 1
>  #         }
>  #     ]
>  # }
>  ##
>  { 'command': 'query-cpus-fast', 'returns': [ 'CpuInfoFast' ] }
>  
>  ##
>  # @IOThreadInfo:
>  #
>  # Information about an iothread
> diff --git a/cpus.c b/cpus.c
> index 60563a6d54ec..86eed0ffe796 100644
> --- a/cpus.c
> +++ b/cpus.c
> @@ -2093,88 +2093,235 @@ int vm_stop_force_state(RunState state)
>      }
>  }
>  
>  void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
>  {
>      /* XXX: implement xxx_cpu_list for targets that still miss it */
>  #if defined(cpu_list)
>      cpu_list(f, cpu_fprintf);
>  #endif
>  }
>  
> +static CpuInfoArch sysemu_target_to_cpuinfo_arch(SysEmuTarget target)
> +{
> +    /*
> +     * The @SysEmuTarget -> @CpuInfoArch mapping below is based on the
> +     * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script.
> +     */
> +    switch (target) {
> +    case SYS_EMU_TARGET_I386:
> +    case SYS_EMU_TARGET_X86_64:
> +        return CPU_INFO_ARCH_X86;
> +
> +    case SYS_EMU_TARGET_PPC:
> +    case SYS_EMU_TARGET_PPCEMB:
> +    case SYS_EMU_TARGET_PPC64:
> +        return CPU_INFO_ARCH_PPC;
> +
> +    case SYS_EMU_TARGET_SPARC:
> +    case SYS_EMU_TARGET_SPARC64:
> +        return CPU_INFO_ARCH_SPARC;
> +
> +    case SYS_EMU_TARGET_MIPS:
> +    case SYS_EMU_TARGET_MIPSEL:
> +    case SYS_EMU_TARGET_MIPS64:
> +    case SYS_EMU_TARGET_MIPS64EL:
> +        return CPU_INFO_ARCH_MIPS;
> +
> +    case SYS_EMU_TARGET_TRICORE:
> +        return CPU_INFO_ARCH_TRICORE;
> +
> +    case SYS_EMU_TARGET_S390X:
> +        return CPU_INFO_ARCH_S390;
> +
> +    case SYS_EMU_TARGET_RISCV32:
> +    case SYS_EMU_TARGET_RISCV64:
> +        return CPU_INFO_ARCH_RISCV;
> +
> +    default:
> +        return CPU_INFO_ARCH_OTHER;
> +    }
> +}

Hmm.  Can we avoid duplicating configure's mapping here?  More on that
below.

> +
> +static void cpustate_to_cpuinfo_x86(CpuInfoX86 *info, const CPUState *cpu)
> +{
> +#ifdef TARGET_I386
> +    X86CPU *x86_cpu = X86_CPU(cpu);
> +    CPUX86State *env = &x86_cpu->env;
> +
> +    info->pc = env->eip + env->segs[R_CS].base;
> +#else
> +    abort();
> +#endif
> +}
> +
> +static void cpustate_to_cpuinfo_ppc(CpuInfoPPC *info, const CPUState *cpu)
> +{
> +#ifdef TARGET_PPC
> +    PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
> +    CPUPPCState *env = &ppc_cpu->env;
> +
> +    info->nip = env->nip;
> +#else
> +    abort();
> +#endif
> +}
> +
> +static void cpustate_to_cpuinfo_sparc(CpuInfoSPARC *info, const CPUState *cpu)
> +{
> +#ifdef TARGET_SPARC
> +    SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
> +    CPUSPARCState *env = &sparc_cpu->env;
> +
> +    info->pc = env->pc;
> +    info->npc = env->npc;
> +#else
> +    abort();
> +#endif
> +}
> +
> +static void cpustate_to_cpuinfo_mips(CpuInfoMIPS *info, const CPUState *cpu)
> +{
> +#ifdef TARGET_MIPS
> +    MIPSCPU *mips_cpu = MIPS_CPU(cpu);
> +    CPUMIPSState *env = &mips_cpu->env;
> +
> +    info->PC = env->active_tc.PC;
> +#else
> +    abort();
> +#endif
> +}
> +
> +static void cpustate_to_cpuinfo_tricore(CpuInfoTricore *info,
> +                                        const CPUState *cpu)
> +{
> +#ifdef TARGET_TRICORE
> +    TriCoreCPU *tricore_cpu = TRICORE_CPU(cpu);
> +    CPUTriCoreState *env = &tricore_cpu->env;
> +
> +    info->PC = env->PC;
> +#else
> +    abort();
> +#endif
> +}
> +
> +static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu)
> +{
> +#ifdef TARGET_S390X
> +    S390CPU *s390_cpu = S390_CPU(cpu);
> +    CPUS390XState *env = &s390_cpu->env;
> +
> +    info->cpu_state = env->cpu_state;
> +#else
> +    abort();
> +#endif
> +}
> +
> +static void cpustate_to_cpuinfo_riscv(CpuInfoRISCV *info, const CPUState *cpu)
> +{
> +#ifdef TARGET_RISCV
> +    RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
> +    CPURISCVState *env = &riscv_cpu->env;
> +
> +    info->pc = env->pc;
> +#else
> +    abort();
> +#endif
> +}
> +

To reduce #ifdeffery here, these helpers could be moved to suitable
files in target/*/, plus stubs, but I doubt it's worth the bother.

>  CpuInfoList *qmp_query_cpus(Error **errp)
>  {
>      MachineState *ms = MACHINE(qdev_get_machine());
>      MachineClass *mc = MACHINE_GET_CLASS(ms);
>      CpuInfoList *head = NULL, *cur_item = NULL;
> +    SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME,
> +                                          -1, &error_abort);

Note how configure providing TARGET_NAME makes computing target easy.

Compare to how sysemu_target_to_cpuinfo_arch() computes arch.  Would it
make sense to have configure provide TARGET_BASE_NAME, so we can compute
arch the same way as target?

>      CPUState *cpu;
>  
>      CPU_FOREACH(cpu) {
>          CpuInfoList *info;
> -#if defined(TARGET_I386)
> -        X86CPU *x86_cpu = X86_CPU(cpu);
> -        CPUX86State *env = &x86_cpu->env;
> -#elif defined(TARGET_PPC)
> -        PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
> -        CPUPPCState *env = &ppc_cpu->env;
> -#elif defined(TARGET_SPARC)
> -        SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
> -        CPUSPARCState *env = &sparc_cpu->env;
> -#elif defined(TARGET_RISCV)
> -        RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
> -        CPURISCVState *env = &riscv_cpu->env;
> -#elif defined(TARGET_MIPS)
> -        MIPSCPU *mips_cpu = MIPS_CPU(cpu);
> -        CPUMIPSState *env = &mips_cpu->env;
> -#elif defined(TARGET_TRICORE)
> -        TriCoreCPU *tricore_cpu = TRICORE_CPU(cpu);
> -        CPUTriCoreState *env = &tricore_cpu->env;
> -#elif defined(TARGET_S390X)
> -        S390CPU *s390_cpu = S390_CPU(cpu);
> -        CPUS390XState *env = &s390_cpu->env;
> -#endif
>  
>          cpu_synchronize_state(cpu);
>  
>          info = g_malloc0(sizeof(*info));
>          info->value = g_malloc0(sizeof(*info->value));
>          info->value->CPU = cpu->cpu_index;
>          info->value->current = (cpu == first_cpu);
>          info->value->halted = cpu->halted;
>          info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
>          info->value->thread_id = cpu->thread_id;
> -#if defined(TARGET_I386)
> -        info->value->arch = CPU_INFO_ARCH_X86;
> -        info->value->u.x86.pc = env->eip + env->segs[R_CS].base;
> -#elif defined(TARGET_PPC)
> -        info->value->arch = CPU_INFO_ARCH_PPC;
> -        info->value->u.ppc.nip = env->nip;
> -#elif defined(TARGET_SPARC)
> -        info->value->arch = CPU_INFO_ARCH_SPARC;
> -        info->value->u.q_sparc.pc = env->pc;
> -        info->value->u.q_sparc.npc = env->npc;
> -#elif defined(TARGET_MIPS)
> -        info->value->arch = CPU_INFO_ARCH_MIPS;
> -        info->value->u.q_mips.PC = env->active_tc.PC;
> -#elif defined(TARGET_TRICORE)
> -        info->value->arch = CPU_INFO_ARCH_TRICORE;
> -        info->value->u.tricore.PC = env->PC;
> -#elif defined(TARGET_S390X)
> -        info->value->arch = CPU_INFO_ARCH_S390;
> -        info->value->u.s390.cpu_state = env->cpu_state;
> -#elif defined(TARGET_RISCV)
> -        info->value->arch = CPU_INFO_ARCH_RISCV;
> -        info->value->u.riscv.pc = env->pc;
> -#else
> -        info->value->arch = CPU_INFO_ARCH_OTHER;
> -#endif
> +        info->value->arch = sysemu_target_to_cpuinfo_arch(target);
> +        info->value->target = target;
> +
> +        /*
> +         * The @SysEmuTarget -> @CpuInfo mapping below is based on the
> +         * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script.
> +         */
> +        switch (target) {
> +        case SYS_EMU_TARGET_I386:
> +            cpustate_to_cpuinfo_x86(&info->value->u.i386, cpu);
> +            break;
> +        case SYS_EMU_TARGET_X86_64:
> +            cpustate_to_cpuinfo_x86(&info->value->u.x86_64, cpu);
> +            break;
> +
> +        case SYS_EMU_TARGET_PPC:
> +            cpustate_to_cpuinfo_ppc(&info->value->u.ppc, cpu);
> +            break;
> +        case SYS_EMU_TARGET_PPCEMB:
> +            cpustate_to_cpuinfo_ppc(&info->value->u.ppcemb, cpu);
> +            break;
> +        case SYS_EMU_TARGET_PPC64:
> +            cpustate_to_cpuinfo_ppc(&info->value->u.ppc64, cpu);
> +            break;
> +
> +        case SYS_EMU_TARGET_SPARC:
> +            cpustate_to_cpuinfo_sparc(&info->value->u.q_sparc, cpu);
> +            break;
> +        case SYS_EMU_TARGET_SPARC64:
> +            cpustate_to_cpuinfo_sparc(&info->value->u.sparc64, cpu);
> +            break;
> +
> +        case SYS_EMU_TARGET_MIPS:
> +            cpustate_to_cpuinfo_mips(&info->value->u.q_mips, cpu);
> +            break;
> +        case SYS_EMU_TARGET_MIPSEL:
> +            cpustate_to_cpuinfo_mips(&info->value->u.mipsel, cpu);
> +            break;
> +        case SYS_EMU_TARGET_MIPS64:
> +            cpustate_to_cpuinfo_mips(&info->value->u.mips64, cpu);
> +            break;
> +        case SYS_EMU_TARGET_MIPS64EL:
> +            cpustate_to_cpuinfo_mips(&info->value->u.mips64el, cpu);
> +            break;
> +
> +        case SYS_EMU_TARGET_TRICORE:
> +            cpustate_to_cpuinfo_tricore(&info->value->u.tricore, cpu);
> +            break;
> +
> +        case SYS_EMU_TARGET_S390X:
> +            cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
> +            break;
> +
> +        case SYS_EMU_TARGET_RISCV32:
> +            cpustate_to_cpuinfo_riscv(&info->value->u.riscv32, cpu);
> +            break;
> +        case SYS_EMU_TARGET_RISCV64:
> +            cpustate_to_cpuinfo_riscv(&info->value->u.riscv64, cpu);
> +            break;
> +
> +        default:
> +            /* do nothing for @CpuInfoOther */
> +            break;
> +        }
> +
>          info->value->has_props = !!mc->cpu_index_to_instance_props;
>          if (info->value->has_props) {
>              CpuInstanceProperties *props;
>              props = g_malloc0(sizeof(*props));
>              *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
>              info->value->props = props;
>          }
>  
>          /* XXX: waiting for the qapi to support GSList */
>          if (!cur_item) {
>              head = cur_item = info;
> @@ -2188,64 +2335,50 @@ CpuInfoList *qmp_query_cpus(Error **errp)
>  }
>  
>  /*
>   * fast means: we NEVER interrupt vCPU threads to retrieve
>   * information from KVM.
>   */
>  CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
>  {
>      MachineState *ms = MACHINE(qdev_get_machine());
>      MachineClass *mc = MACHINE_GET_CLASS(ms);
>      CpuInfoFastList *head = NULL, *cur_item = NULL;
> +    SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME,
> +                                          -1, &error_abort);
>      CPUState *cpu;
> -#if defined(TARGET_S390X)
> -    S390CPU *s390_cpu;
> -    CPUS390XState *env;
> -#endif
>  
>      CPU_FOREACH(cpu) {
>          CpuInfoFastList *info = g_malloc0(sizeof(*info));
>          info->value = g_malloc0(sizeof(*info->value));
>  
>          info->value->cpu_index = cpu->cpu_index;
>          info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
>          info->value->thread_id = cpu->thread_id;
>  
>          info->value->has_props = !!mc->cpu_index_to_instance_props;
>          if (info->value->has_props) {
>              CpuInstanceProperties *props;
>              props = g_malloc0(sizeof(*props));
>              *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
>              info->value->props = props;
>          }
>  
> -#if defined(TARGET_I386)
> -        info->value->arch = CPU_INFO_ARCH_X86;
> -#elif defined(TARGET_PPC)
> -        info->value->arch = CPU_INFO_ARCH_PPC;
> -#elif defined(TARGET_SPARC)
> -        info->value->arch = CPU_INFO_ARCH_SPARC;
> -#elif defined(TARGET_MIPS)
> -        info->value->arch = CPU_INFO_ARCH_MIPS;
> -#elif defined(TARGET_TRICORE)
> -        info->value->arch = CPU_INFO_ARCH_TRICORE;
> -#elif defined(TARGET_S390X)
> -        s390_cpu = S390_CPU(cpu);
> -        env = &s390_cpu->env;
> -        info->value->arch = CPU_INFO_ARCH_S390;
> -        info->value->u.s390.cpu_state = env->cpu_state;
> -#elif defined(TARGET_RISCV)
> -        info->value->arch = CPU_INFO_ARCH_RISCV;
> -#else
> -        info->value->arch = CPU_INFO_ARCH_OTHER;
> -#endif
> +        info->value->arch = sysemu_target_to_cpuinfo_arch(target);
> +        info->value->target = target;
> +        if (target == SYS_EMU_TARGET_S390X) {
> +            cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
> +        } else {
> +            /* do nothing for @CpuInfoOther */
> +        }
> +
>          if (!cur_item) {
>              head = cur_item = info;
>          } else {
>              cur_item->next = info;
>              cur_item = info;
>          }
>      }
>  
>      return head;
>  }
Laszlo Ersek April 25, 2018, 1:47 p.m. UTC | #2
On 04/25/18 09:33, Markus Armbruster wrote:
> Laszlo Ersek <lersek@redhat.com> writes:

[snip]

>> +static CpuInfoArch sysemu_target_to_cpuinfo_arch(SysEmuTarget target)
>> +{
>> +    /*
>> +     * The @SysEmuTarget -> @CpuInfoArch mapping below is based on the
>> +     * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script.
>> +     */
>> +    switch (target) {
>> +    case SYS_EMU_TARGET_I386:
>> +    case SYS_EMU_TARGET_X86_64:
>> +        return CPU_INFO_ARCH_X86;
>> +
>> +    case SYS_EMU_TARGET_PPC:
>> +    case SYS_EMU_TARGET_PPCEMB:
>> +    case SYS_EMU_TARGET_PPC64:
>> +        return CPU_INFO_ARCH_PPC;
>> +
>> +    case SYS_EMU_TARGET_SPARC:
>> +    case SYS_EMU_TARGET_SPARC64:
>> +        return CPU_INFO_ARCH_SPARC;
>> +
>> +    case SYS_EMU_TARGET_MIPS:
>> +    case SYS_EMU_TARGET_MIPSEL:
>> +    case SYS_EMU_TARGET_MIPS64:
>> +    case SYS_EMU_TARGET_MIPS64EL:
>> +        return CPU_INFO_ARCH_MIPS;
>> +
>> +    case SYS_EMU_TARGET_TRICORE:
>> +        return CPU_INFO_ARCH_TRICORE;
>> +
>> +    case SYS_EMU_TARGET_S390X:
>> +        return CPU_INFO_ARCH_S390;
>> +
>> +    case SYS_EMU_TARGET_RISCV32:
>> +    case SYS_EMU_TARGET_RISCV64:
>> +        return CPU_INFO_ARCH_RISCV;
>> +
>> +    default:
>> +        return CPU_INFO_ARCH_OTHER;
>> +    }
>> +}
> 
> Hmm.  Can we avoid duplicating configure's mapping here?  More on that
> below.
> 
>> +
>> +static void cpustate_to_cpuinfo_x86(CpuInfoX86 *info, const CPUState *cpu)
>> +{
>> +#ifdef TARGET_I386
>> +    X86CPU *x86_cpu = X86_CPU(cpu);
>> +    CPUX86State *env = &x86_cpu->env;
>> +
>> +    info->pc = env->eip + env->segs[R_CS].base;
>> +#else
>> +    abort();
>> +#endif
>> +}
>> +
>> +static void cpustate_to_cpuinfo_ppc(CpuInfoPPC *info, const CPUState *cpu)
>> +{
>> +#ifdef TARGET_PPC
>> +    PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
>> +    CPUPPCState *env = &ppc_cpu->env;
>> +
>> +    info->nip = env->nip;
>> +#else
>> +    abort();
>> +#endif
>> +}
>> +
>> +static void cpustate_to_cpuinfo_sparc(CpuInfoSPARC *info, const CPUState *cpu)
>> +{
>> +#ifdef TARGET_SPARC
>> +    SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
>> +    CPUSPARCState *env = &sparc_cpu->env;
>> +
>> +    info->pc = env->pc;
>> +    info->npc = env->npc;
>> +#else
>> +    abort();
>> +#endif
>> +}
>> +
>> +static void cpustate_to_cpuinfo_mips(CpuInfoMIPS *info, const CPUState *cpu)
>> +{
>> +#ifdef TARGET_MIPS
>> +    MIPSCPU *mips_cpu = MIPS_CPU(cpu);
>> +    CPUMIPSState *env = &mips_cpu->env;
>> +
>> +    info->PC = env->active_tc.PC;
>> +#else
>> +    abort();
>> +#endif
>> +}
>> +
>> +static void cpustate_to_cpuinfo_tricore(CpuInfoTricore *info,
>> +                                        const CPUState *cpu)
>> +{
>> +#ifdef TARGET_TRICORE
>> +    TriCoreCPU *tricore_cpu = TRICORE_CPU(cpu);
>> +    CPUTriCoreState *env = &tricore_cpu->env;
>> +
>> +    info->PC = env->PC;
>> +#else
>> +    abort();
>> +#endif
>> +}
>> +
>> +static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu)
>> +{
>> +#ifdef TARGET_S390X
>> +    S390CPU *s390_cpu = S390_CPU(cpu);
>> +    CPUS390XState *env = &s390_cpu->env;
>> +
>> +    info->cpu_state = env->cpu_state;
>> +#else
>> +    abort();
>> +#endif
>> +}
>> +
>> +static void cpustate_to_cpuinfo_riscv(CpuInfoRISCV *info, const CPUState *cpu)
>> +{
>> +#ifdef TARGET_RISCV
>> +    RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
>> +    CPURISCVState *env = &riscv_cpu->env;
>> +
>> +    info->pc = env->pc;
>> +#else
>> +    abort();
>> +#endif
>> +}
>> +
> 
> To reduce #ifdeffery here, these helpers could be moved to suitable
> files in target/*/, plus stubs, but I doubt it's worth the bother.

Indeed. I did look for suitable recipient C files under target/*/, in
particular target/*/cpu.c, but my results weren't promising.

For example, "target/ppc/cpu.c" says "PowerPC CPU routines for qemu"
(and its actual contents agree), so quite inappropriate.

I wouldn't like to introduce new files for this, and if we're just
looking for a dumping ground for these functions, let's keep them here.

> 
>>  CpuInfoList *qmp_query_cpus(Error **errp)
>>  {
>>      MachineState *ms = MACHINE(qdev_get_machine());
>>      MachineClass *mc = MACHINE_GET_CLASS(ms);
>>      CpuInfoList *head = NULL, *cur_item = NULL;
>> +    SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME,
>> +                                          -1, &error_abort);
> 
> Note how configure providing TARGET_NAME makes computing target easy.
> 
> Compare to how sysemu_target_to_cpuinfo_arch() computes arch.  Would it
> make sense to have configure provide TARGET_BASE_NAME, so we can compute
> arch the same way as target?

It would eliminate sysemu_target_to_cpuinfo_arch() entirely, yes.

However, the (quite more painful) mapping below would not be helped:

[snip]

>> +        /*
>> +         * The @SysEmuTarget -> @CpuInfo mapping below is based on the
>> +         * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script.
>> +         */
>> +        switch (target) {
>> +        case SYS_EMU_TARGET_I386:
>> +            cpustate_to_cpuinfo_x86(&info->value->u.i386, cpu);
>> +            break;
>> +        case SYS_EMU_TARGET_X86_64:
>> +            cpustate_to_cpuinfo_x86(&info->value->u.x86_64, cpu);
>> +            break;
>> +
>> +        case SYS_EMU_TARGET_PPC:
>> +            cpustate_to_cpuinfo_ppc(&info->value->u.ppc, cpu);
>> +            break;
>> +        case SYS_EMU_TARGET_PPCEMB:
>> +            cpustate_to_cpuinfo_ppc(&info->value->u.ppcemb, cpu);
>> +            break;
>> +        case SYS_EMU_TARGET_PPC64:
>> +            cpustate_to_cpuinfo_ppc(&info->value->u.ppc64, cpu);
>> +            break;
>> +
>> +        case SYS_EMU_TARGET_SPARC:
>> +            cpustate_to_cpuinfo_sparc(&info->value->u.q_sparc, cpu);
>> +            break;
>> +        case SYS_EMU_TARGET_SPARC64:
>> +            cpustate_to_cpuinfo_sparc(&info->value->u.sparc64, cpu);
>> +            break;
>> +
>> +        case SYS_EMU_TARGET_MIPS:
>> +            cpustate_to_cpuinfo_mips(&info->value->u.q_mips, cpu);
>> +            break;
>> +        case SYS_EMU_TARGET_MIPSEL:
>> +            cpustate_to_cpuinfo_mips(&info->value->u.mipsel, cpu);
>> +            break;
>> +        case SYS_EMU_TARGET_MIPS64:
>> +            cpustate_to_cpuinfo_mips(&info->value->u.mips64, cpu);
>> +            break;
>> +        case SYS_EMU_TARGET_MIPS64EL:
>> +            cpustate_to_cpuinfo_mips(&info->value->u.mips64el, cpu);
>> +            break;
>> +
>> +        case SYS_EMU_TARGET_TRICORE:
>> +            cpustate_to_cpuinfo_tricore(&info->value->u.tricore, cpu);
>> +            break;
>> +
>> +        case SYS_EMU_TARGET_S390X:
>> +            cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
>> +            break;
>> +
>> +        case SYS_EMU_TARGET_RISCV32:
>> +            cpustate_to_cpuinfo_riscv(&info->value->u.riscv32, cpu);
>> +            break;
>> +        case SYS_EMU_TARGET_RISCV64:
>> +            cpustate_to_cpuinfo_riscv(&info->value->u.riscv64, cpu);
>> +            break;
>> +
>> +        default:
>> +            /* do nothing for @CpuInfoOther */
>> +            break;
>> +        }
>> +

I don't know how this could be simplified. Even if the build system
provided some more macros, and we used token pasting here, we'd still
have to list all the case labels and the function calls one by one.

... I've also thought of fusing this switch statement with the one in
sysemu_target_to_cpuinfo_arch(), somehow, into a more generic helper
function. The idea would be to map the enums unconditionally, and map
the sub-structure only conditionally (e.g. if the "cpu" parameter were
not NULL). However, this helper function would not be reusable from
qmp_query_cpus_fast(): the helper cannot take a pointer *to the union*
called "u", because (a) that union has no *named* type, (b) even if it
had a type, that type differs between @CpuInfo and @CpuInfoFast.

In other words, it is impossible to write a C function that takes a
pointer to "some" union, and then fills the "s390x" member for *both*
qmp_query_cpus() and qmp_query_cpus_fast(). Those unions are genuinely
different, so the discrimination -- the identification of the
appropriate union member -- must occur separately in each. Once that's
done, we can call cpustate_to_cpuinfo_s390() from both places:

[snip]

>> +        info->value->arch = sysemu_target_to_cpuinfo_arch(target);
>> +        info->value->target = target;
>> +        if (target == SYS_EMU_TARGET_S390X) {
>> +            cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
>> +        } else {
>> +            /* do nothing for @CpuInfoOther */
>> +        }
>> +

In brief, I think extending configure / the build system would only help
with the less painful part of this (the scalar mapping), and so it's not
worth doing.

Thanks!
Laszlo
Markus Armbruster April 26, 2018, 6:26 a.m. UTC | #3
Laszlo Ersek <lersek@redhat.com> writes:

[...]
> In brief, I think extending configure / the build system would only help
> with the less painful part of this (the scalar mapping), and so it's not
> worth doing.

We're going to leave deprecated query-cpus alone (see Eric's review of
the previous patch).  Does that change matters?

PS: Instead of configure changes, #TARGET_BASE_ARCH might do.
Laszlo Ersek April 26, 2018, 9:18 a.m. UTC | #4
On 04/26/18 08:26, Markus Armbruster wrote:
> Laszlo Ersek <lersek@redhat.com> writes:
> 
> [...]
>> In brief, I think extending configure / the build system would only help
>> with the less painful part of this (the scalar mapping), and so it's not
>> worth doing.
> 
> We're going to leave deprecated query-cpus alone (see Eric's review of
> the previous patch).

Yes.

> Does that change matters?

It does.

> PS: Instead of configure changes, #TARGET_BASE_ARCH might do.

Does that already exist as a macro? Hmm... After grepping my build dir,
it doesn't seem to, but maybe I can change that. Because,
TARGET_BASE_ARCH is exactly what we need.

Thanks!
Laszlo
Markus Armbruster April 26, 2018, 11:57 a.m. UTC | #5
Laszlo Ersek <lersek@redhat.com> writes:

> On 04/26/18 08:26, Markus Armbruster wrote:
>> Laszlo Ersek <lersek@redhat.com> writes:
>> 
>> [...]
>>> In brief, I think extending configure / the build system would only help
>>> with the less painful part of this (the scalar mapping), and so it's not
>>> worth doing.
>> 
>> We're going to leave deprecated query-cpus alone (see Eric's review of
>> the previous patch).
>
> Yes.
>
>> Does that change matters?
>
> It does.
>
>> PS: Instead of configure changes, #TARGET_BASE_ARCH might do.
>
> Does that already exist as a macro? Hmm... After grepping my build dir,
> it doesn't seem to, but maybe I can change that. Because,
> TARGET_BASE_ARCH is exactly what we need.

You're right, it's not in config-target.h, only in config-target.mak.
scripts/create_config would need a (trivial) patch.
Laszlo Ersek April 26, 2018, 1:33 p.m. UTC | #6
On 04/26/18 11:18, Laszlo Ersek wrote:
> On 04/26/18 08:26, Markus Armbruster wrote:
>> Laszlo Ersek <lersek@redhat.com> writes:
>>
>> [...]
>>> In brief, I think extending configure / the build system would only help
>>> with the less painful part of this (the scalar mapping), and so it's not
>>> worth doing.
>>
>> We're going to leave deprecated query-cpus alone (see Eric's review of
>> the previous patch).
> 
> Yes.
> 
>> Does that change matters?
> 
> It does.
> 
>> PS: Instead of configure changes, #TARGET_BASE_ARCH might do.
> 
> Does that already exist as a macro? Hmm... After grepping my build dir,
> it doesn't seem to, but maybe I can change that. Because,
> TARGET_BASE_ARCH is exactly what we need.

Acerbic discovery of the day: @CpuInfoArch has "x86", while configure
produces:

  TARGET_NAME  TARGET_BASE_ARCH
         i386              i386
       x86_64              i386

Note how "i386" does not match "x86".

I guess I'll have to keep the sysemu_target_to_cpuinfo_arch() function.

Thanks
Laszlo
Markus Armbruster April 26, 2018, 2:34 p.m. UTC | #7
Laszlo Ersek <lersek@redhat.com> writes:

> On 04/26/18 11:18, Laszlo Ersek wrote:
>> On 04/26/18 08:26, Markus Armbruster wrote:
>>> Laszlo Ersek <lersek@redhat.com> writes:
>>>
>>> [...]
>>>> In brief, I think extending configure / the build system would only help
>>>> with the less painful part of this (the scalar mapping), and so it's not
>>>> worth doing.
>>>
>>> We're going to leave deprecated query-cpus alone (see Eric's review of
>>> the previous patch).
>> 
>> Yes.
>> 
>>> Does that change matters?
>> 
>> It does.
>> 
>>> PS: Instead of configure changes, #TARGET_BASE_ARCH might do.
>> 
>> Does that already exist as a macro? Hmm... After grepping my build dir,
>> it doesn't seem to, but maybe I can change that. Because,
>> TARGET_BASE_ARCH is exactly what we need.
>
> Acerbic discovery of the day: @CpuInfoArch has "x86", while configure
> produces:
>
>   TARGET_NAME  TARGET_BASE_ARCH
>          i386              i386
>        x86_64              i386
>
> Note how "i386" does not match "x86".

Review fail.

Just three weeks ago, we could still have fixed query-cpus-fast...

> I guess I'll have to keep the sysemu_target_to_cpuinfo_arch() function.

Assuming this is the only offender, you could also s/i386/x86/ before
you pass it to qapi_enum_parse().  Pick what you hate less.
Eric Blake April 26, 2018, 2:48 p.m. UTC | #8
On 04/26/2018 09:34 AM, Markus Armbruster wrote:
>>
>> Acerbic discovery of the day: @CpuInfoArch has "x86", while configure
>> produces:
>>
>>   TARGET_NAME  TARGET_BASE_ARCH
>>          i386              i386
>>        x86_64              i386
>>
>> Note how "i386" does not match "x86".
> 
> Review fail.
> 
> Just three weeks ago, we could still have fixed query-cpus-fast...

Actually, I think we still can.  We already documented in the 2.12
release notes that the "arch" field of query-cpus-fast is known to be
broken for all but "s390x" (which is really the only arch field that
MUST be correct, as that is the only time we send additional
information).  And introspection can easily see both the enum contents
(if we add something) as well as any other additions to the
query-cpus-fast output union (although that is less likely), to use
those as a witness for whether qemu is new enough to have fixed the
bogus "arch" values.  I'd argue that if we change things right now, with
intent to include the change in 2.12.1, before people start relying on
the bogus "arch" of 2.12, then we should feel free to make
query-cpus-fast output whatever we want for all architectures other than
"s390x", even if it changes the current output of "x86".
Markus Armbruster April 26, 2018, 3:51 p.m. UTC | #9
Eric Blake <eblake@redhat.com> writes:

> On 04/26/2018 09:34 AM, Markus Armbruster wrote:
>>>
>>> Acerbic discovery of the day: @CpuInfoArch has "x86", while configure
>>> produces:
>>>
>>>   TARGET_NAME  TARGET_BASE_ARCH
>>>          i386              i386
>>>        x86_64              i386
>>>
>>> Note how "i386" does not match "x86".
>> 
>> Review fail.
>> 
>> Just three weeks ago, we could still have fixed query-cpus-fast...
>
> Actually, I think we still can.  We already documented in the 2.12
> release notes that the "arch" field of query-cpus-fast is known to be
> broken for all but "s390x" (which is really the only arch field that
> MUST be correct, as that is the only time we send additional
> information).  And introspection can easily see both the enum contents
> (if we add something) as well as any other additions to the
> query-cpus-fast output union (although that is less likely), to use
> those as a witness for whether qemu is new enough to have fixed the
> bogus "arch" values.  I'd argue that if we change things right now, with
> intent to include the change in 2.12.1, before people start relying on
> the bogus "arch" of 2.12, then we should feel free to make
> query-cpus-fast output whatever we want for all architectures other than
> "s390x", even if it changes the current output of "x86".

In other words, we managed to screw up query-cpus-fast sufficiently to
let us fix it even now.  Cool, let's do it!
Laszlo Ersek April 26, 2018, 4:30 p.m. UTC | #10
On 04/26/18 17:51, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> On 04/26/2018 09:34 AM, Markus Armbruster wrote:
>>>>
>>>> Acerbic discovery of the day: @CpuInfoArch has "x86", while configure
>>>> produces:
>>>>
>>>>   TARGET_NAME  TARGET_BASE_ARCH
>>>>          i386              i386
>>>>        x86_64              i386
>>>>
>>>> Note how "i386" does not match "x86".
>>>
>>> Review fail.
>>>
>>> Just three weeks ago, we could still have fixed query-cpus-fast...
>>
>> Actually, I think we still can.  We already documented in the 2.12
>> release notes that the "arch" field of query-cpus-fast is known to be
>> broken for all but "s390x" (which is really the only arch field that
>> MUST be correct, as that is the only time we send additional
>> information).  And introspection can easily see both the enum contents
>> (if we add something) as well as any other additions to the
>> query-cpus-fast output union (although that is less likely), to use
>> those as a witness for whether qemu is new enough to have fixed the
>> bogus "arch" values.  I'd argue that if we change things right now, with
>> intent to include the change in 2.12.1, before people start relying on
>> the bogus "arch" of 2.12, then we should feel free to make
>> query-cpus-fast output whatever we want for all architectures other than
>> "s390x", even if it changes the current output of "x86".
> 
> In other words, we managed to screw up query-cpus-fast sufficiently to
> let us fix it even now.  Cool, let's do it!
> 

Let me clarify a little.

The @CpuInfoArch enum has the following constants now:

['x86', 'sparc', 'ppc', 'mips', 'tricore', 's390', 'riscv', 'other' ]

This enum was originally introduced in 2.6 (according to the
documentation), and only the @s390 and @riscv constants were added in 2.12.

The enum constants show up in the following two places, *on the wire*:

- in @CpuInfo.@arch, only produced by @query-cpus,
- in @CpuInfoFast.@arch, only produced by @query-cpus-fast.

The plan would be to rewrite *all* those enum constants of @CpuInfoArch
to which the respective TARGET_BASE_ARCH values (from "configure") do
not map *identically*. Here's the mapping:

  TARGET_BASE_ARCH  CpuInfoArch  CpuInfoArch needs change
  ----------------  -----------  ------------------------
  i386              x86          YES
  sparc             sparc        no
  ppc               ppc          no
  mips              mips         no
  tricore           tricore      no
  s390x             s390         YES
  riscv             riscv        no

In other words, @CpuInfoArch would have to be changed to the following:

['i386', 'sparc', 'ppc', 'mips', 'tricore', 's390x', 'riscv', 'other' ]
 ^^^^^^                                     ^^^^^^^

This means that the @arch field, returned by @query-cpus and
@query-cpus-fast, would change incompatibly for those QAPI clients that
look specifically for "x86" or "s390".

Is this a safe change?

I would say, because of the 's390' -> 's390x' change, that it isn't.

(Also, to confirm, the wiki section at
<https://wiki.qemu.org/Planning/2.12#Issues_that_will_not_be_fixed> states,

  * the query-cpus-fast QMP command reports bogus arch data for all
    architectures except x86 and s390; applications should be careful to
    not rely on the bogus information

It (correctly) refers to "s390". That value would change.)

Thanks
Laszlo
Markus Armbruster April 27, 2018, 6:53 a.m. UTC | #11
Laszlo Ersek <lersek@redhat.com> writes:

> On 04/26/18 17:51, Markus Armbruster wrote:
>> Eric Blake <eblake@redhat.com> writes:
>> 
>>> On 04/26/2018 09:34 AM, Markus Armbruster wrote:
>>>>>
>>>>> Acerbic discovery of the day: @CpuInfoArch has "x86", while configure
>>>>> produces:
>>>>>
>>>>>   TARGET_NAME  TARGET_BASE_ARCH
>>>>>          i386              i386
>>>>>        x86_64              i386
>>>>>
>>>>> Note how "i386" does not match "x86".
>>>>
>>>> Review fail.
>>>>
>>>> Just three weeks ago, we could still have fixed query-cpus-fast...
>>>
>>> Actually, I think we still can.  We already documented in the 2.12
>>> release notes that the "arch" field of query-cpus-fast is known to be
>>> broken for all but "s390x" (which is really the only arch field that
>>> MUST be correct, as that is the only time we send additional
>>> information).  And introspection can easily see both the enum contents
>>> (if we add something) as well as any other additions to the
>>> query-cpus-fast output union (although that is less likely), to use
>>> those as a witness for whether qemu is new enough to have fixed the
>>> bogus "arch" values.  I'd argue that if we change things right now, with
>>> intent to include the change in 2.12.1, before people start relying on
>>> the bogus "arch" of 2.12, then we should feel free to make
>>> query-cpus-fast output whatever we want for all architectures other than
>>> "s390x", even if it changes the current output of "x86".
>> 
>> In other words, we managed to screw up query-cpus-fast sufficiently to
>> let us fix it even now.  Cool, let's do it!
>> 
>
> Let me clarify a little.
>
> The @CpuInfoArch enum has the following constants now:
>
> ['x86', 'sparc', 'ppc', 'mips', 'tricore', 's390', 'riscv', 'other' ]
>
> This enum was originally introduced in 2.6 (according to the
> documentation), and only the @s390 and @riscv constants were added in 2.12.
>
> The enum constants show up in the following two places, *on the wire*:
>
> - in @CpuInfo.@arch, only produced by @query-cpus,
> - in @CpuInfoFast.@arch, only produced by @query-cpus-fast.
>
> The plan would be to rewrite *all* those enum constants of @CpuInfoArch
> to which the respective TARGET_BASE_ARCH values (from "configure") do
> not map *identically*. Here's the mapping:
>
>   TARGET_BASE_ARCH  CpuInfoArch  CpuInfoArch needs change
>   ----------------  -----------  ------------------------
>   i386              x86          YES
>   sparc             sparc        no
>   ppc               ppc          no
>   mips              mips         no
>   tricore           tricore      no
>   s390x             s390         YES
>   riscv             riscv        no
>
> In other words, @CpuInfoArch would have to be changed to the following:
>
> ['i386', 'sparc', 'ppc', 'mips', 'tricore', 's390x', 'riscv', 'other' ]
>  ^^^^^^                                     ^^^^^^^
>
> This means that the @arch field, returned by @query-cpus and
> @query-cpus-fast, would change incompatibly for those QAPI clients that
> look specifically for "x86" or "s390".
>
> Is this a safe change?
>
> I would say, because of the 's390' -> 's390x' change, that it isn't.
>
> (Also, to confirm, the wiki section at
> <https://wiki.qemu.org/Planning/2.12#Issues_that_will_not_be_fixed> states,
>
>   * the query-cpus-fast QMP command reports bogus arch data for all
>     architectures except x86 and s390; applications should be careful to
>     not rely on the bogus information
>
> It (correctly) refers to "s390". That value would change.)

You're right, that's a compatibility break.

We could perhaps still declare *all* @arch values useless in v2.12.0,
then fix them in v2.12.1.

Or we deprecate @arch right when we introduce @target, and drop it later
in accordance with our deprecation policy (qemu-doc.texi @appendix
Deprecated features).  That way, the rather ridiculous code to compute
it will be temporary.  I think that's cleaner.

   @arch in     query-cpus      query-cpus-fast
   before 2.6   nonexistent
   2.6 - 2.11   CpuInfoArch
   2.12         cmd deprecated  CpuInfoArch
   2.13         cmd deprecated  memb deprecated
   2.14         cmd gone        memb deprecated
   2.15         cmd gone        memb gone

Opinions?
Eric Blake April 27, 2018, 1:46 p.m. UTC | #12
On 04/27/2018 01:53 AM, Markus Armbruster wrote:

> We could perhaps still declare *all* @arch values useless in v2.12.0,
> then fix them in v2.12.1.
> 

Well, it's still useful to know that "s390" means the extra field is
available even in 2.12.0.  But your plan:

> Or we deprecate @arch right when we introduce @target, and drop it later
> in accordance with our deprecation policy (qemu-doc.texi @appendix
> Deprecated features).  That way, the rather ridiculous code to compute
> it will be temporary.  I think that's cleaner.
> 
>    @arch in     query-cpus      query-cpus-fast
>    before 2.6   nonexistent
>    2.6 - 2.11   CpuInfoArch
>    2.12         cmd deprecated  CpuInfoArch
>    2.13         cmd deprecated  memb deprecated
>    2.14         cmd gone        memb deprecated
>    2.15         cmd gone        memb gone

works well for me.  I don't think we can accelerate the deprecation by
backporting that to 2.12.1, or if the deprecation belongs only in 2.13,
but the overall plan is sane (libvirt has the deprecation timeframe to
start accessing 'target' instead of 'arch' when worrying about whether
the extra s390x information is present - if it doesn't already just read
the information when present without worrying about the value of 'arch'
in the first place).
diff mbox

Patch

diff --git a/qapi/misc.json b/qapi/misc.json
index d7b776a5af37..98c15880f9f0 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -361,77 +361,105 @@ 
 # Collects fields common to @CpuInfoBase and @CpuInfoFastBase; that is,
 # fields that are shared by @query-cpus and @query-cpus-fast, and not
 # specific to the target architecture.
 #
 # @qom-path: path to the CPU object in the QOM tree (since 2.4)
 #
 # @thread-id: ID of the underlying host thread
 #
 # @props: properties describing which node/socket/core/thread the
 #         virtual CPU belongs to, if supported by the board (since 2.10)
 #
+# @arch: base architecture of the cpu (since 2.6)
+#
 # Since: 2.13
 ##
 { 'struct' : 'CpuInfoCommon',
   'data'   : { 'qom-path'  : 'str',
                'thread-id' : 'int',
-               '*props'    : 'CpuInstanceProperties' } }
+               '*props'    : 'CpuInstanceProperties',
+               'arch'      : 'CpuInfoArch' } }
 
 ##
 # @CpuInfoBase:
 #
 # Extends @CpuInfoCommon with fields that are specific to the @query-cpus
 # command, but not specific to the target architecture.
 #
 # @CPU: the index of the virtual CPU
 #
 # @current: this only exists for backwards compatibility and should be ignored
 #
 # @halted: true if the virtual CPU is in the halt state.  Halt usually refers
 #          to a processor specific low power mode.
 #
-# @arch: architecture of the cpu, which determines which additional fields
-#        will be listed (since 2.6)
+# @target: the QEMU system emulation target, which is more specific than
+#          @arch and determines which additional fields will be listed
+#
 #
 # Since: 2.13
 #
 # Notes: @halted is a transient state that changes frequently.  By the time the
 #        data is sent to the client, the guest may no longer be halted.
-#        Moreover, @arch cannot be moved up to @CpuInfoCommon because
+#        Moreover, @target cannot be moved up to @CpuInfoCommon because
 #        that would prevent its use as the discriminator in @CpuInfo.
 ##
 { 'struct' : 'CpuInfoBase',
   'base'   : 'CpuInfoCommon',
   'data'   : { 'CPU'     : 'int',
                'current' : 'bool',
                'halted'  : 'bool',
-               'arch'    : 'CpuInfoArch' } }
+               'target'  : 'SysEmuTarget' } }
 
 ##
 # @CpuInfo:
 #
 # Information about a virtual CPU
 #
 # Since: 0.14.0
 ##
-{ 'union': 'CpuInfo',
-  'base': 'CpuInfoBase',
-  'discriminator': 'arch',
-  'data': { 'x86': 'CpuInfoX86',
-            'sparc': 'CpuInfoSPARC',
-            'ppc': 'CpuInfoPPC',
-            'mips': 'CpuInfoMIPS',
-            'tricore': 'CpuInfoTricore',
-            's390': 'CpuInfoS390',
-            'riscv': 'CpuInfoRISCV',
-            'other': 'CpuInfoOther' } }
+{ 'union'         : 'CpuInfo',
+  'base'          : 'CpuInfoBase',
+  'discriminator' : 'target',
+  'data'          : { 'i386'         : 'CpuInfoX86',
+                      'x86_64'       : 'CpuInfoX86',
+                      'sparc'        : 'CpuInfoSPARC',
+                      'sparc64'      : 'CpuInfoSPARC',
+                      'ppc'          : 'CpuInfoPPC',
+                      'ppcemb'       : 'CpuInfoPPC',
+                      'ppc64'        : 'CpuInfoPPC',
+                      'mips'         : 'CpuInfoMIPS',
+                      'mipsel'       : 'CpuInfoMIPS',
+                      'mips64'       : 'CpuInfoMIPS',
+                      'mips64el'     : 'CpuInfoMIPS',
+                      'tricore'      : 'CpuInfoTricore',
+                      's390x'        : 'CpuInfoS390',
+                      'riscv32'      : 'CpuInfoRISCV',
+                      'riscv64'      : 'CpuInfoRISCV',
+                      'aarch64'      : 'CpuInfoOther',
+                      'alpha'        : 'CpuInfoOther',
+                      'arm'          : 'CpuInfoOther',
+                      'cris'         : 'CpuInfoOther',
+                      'hppa'         : 'CpuInfoOther',
+                      'lm32'         : 'CpuInfoOther',
+                      'm68k'         : 'CpuInfoOther',
+                      'microblaze'   : 'CpuInfoOther',
+                      'microblazeel' : 'CpuInfoOther',
+                      'moxie'        : 'CpuInfoOther',
+                      'nios2'        : 'CpuInfoOther',
+                      'or1k'         : 'CpuInfoOther',
+                      'sh4'          : 'CpuInfoOther',
+                      'sh4eb'        : 'CpuInfoOther',
+                      'unicore32'    : 'CpuInfoOther',
+                      'xtensa'       : 'CpuInfoOther',
+                      'xtensaeb'     : 'CpuInfoOther' } }
 
 ##
 # @CpuInfoX86:
 #
 # Additional information about a virtual i386 or x86_64 CPU
 #
 # @pc: the 64-bit instruction pointer
 #
 # Since: 2.6
 ##
 { 'struct': 'CpuInfoX86', 'data': { 'pc': 'int' } }
@@ -543,84 +571,110 @@ 
 #
 # Example:
 #
 # -> { "execute": "query-cpus" }
 # <- { "return": [
 #          {
 #             "CPU":0,
 #             "current":true,
 #             "halted":false,
 #             "qom-path":"/machine/unattached/device[0]",
 #             "arch":"x86",
+#             "target":"x86_64",
 #             "pc":3227107138,
 #             "thread-id":3134
 #          },
 #          {
 #             "CPU":1,
 #             "current":false,
 #             "halted":true,
 #             "qom-path":"/machine/unattached/device[2]",
 #             "arch":"x86",
+#             "target":"x86_64",
 #             "pc":7108165,
 #             "thread-id":3135
 #          }
 #       ]
 #    }
 #
 # Notes: This interface is deprecated (since 2.12.0), and it is strongly
 #        recommended that you avoid using it. Use @query-cpus-fast to
 #        obtain information about virtual CPUs.
 #
 ##
 { 'command': 'query-cpus', 'returns': ['CpuInfo'] }
 
 ##
 # @CpuInfoFastBase:
 #
 # Extends @CpuInfoCommon with fields that are specific to the
 # @query-cpus-fast command, but not specific to the target architecture.
 #
 # @cpu-index: index of the virtual CPU
 #
-# @arch: architecture of the cpu, which determines which additional fields
-#        will be listed
+# @target: the QEMU system emulation target, which is more specific than
+#          @arch and determines which additional fields will be listed
 #
 # Since: 2.13
 #
-# Notes: @arch cannot be moved up to @CpuInfoCommon because that would
+# Notes: @target cannot be moved up to @CpuInfoCommon because that would
 #        prevent its use as the discriminator in @CpuInfoFast.
 ##
 { 'struct' : 'CpuInfoFastBase',
   'base'   : 'CpuInfoCommon',
   'data'   : { 'cpu-index' : 'int',
-               'arch'      : 'CpuInfoArch' } }
+               'target'    : 'SysEmuTarget' } }
 
 ##
 # @CpuInfoFast:
 #
 # Information about a virtual CPU
 #
 # Since: 2.12
 #
 ##
-{ 'union': 'CpuInfoFast',
-  'base': 'CpuInfoFastBase',
-  'discriminator': 'arch',
-  'data': { 'x86': 'CpuInfoOther',
-            'sparc': 'CpuInfoOther',
-            'ppc': 'CpuInfoOther',
-            'mips': 'CpuInfoOther',
-            'tricore': 'CpuInfoOther',
-            's390': 'CpuInfoS390',
-            'riscv': 'CpuInfoOther',
-            'other': 'CpuInfoOther' } }
+{ 'union'         : 'CpuInfoFast',
+  'base'          : 'CpuInfoFastBase',
+  'discriminator' : 'target',
+  'data'          : { 'i386'         : 'CpuInfoOther',
+                      'x86_64'       : 'CpuInfoOther',
+                      'sparc'        : 'CpuInfoOther',
+                      'sparc64'      : 'CpuInfoOther',
+                      'ppc'          : 'CpuInfoOther',
+                      'ppcemb'       : 'CpuInfoOther',
+                      'ppc64'        : 'CpuInfoOther',
+                      'mips'         : 'CpuInfoOther',
+                      'mipsel'       : 'CpuInfoOther',
+                      'mips64'       : 'CpuInfoOther',
+                      'mips64el'     : 'CpuInfoOther',
+                      'tricore'      : 'CpuInfoOther',
+                      's390x'        : 'CpuInfoS390',
+                      'riscv32'      : 'CpuInfoOther',
+                      'riscv64'      : 'CpuInfoOther',
+                      'aarch64'      : 'CpuInfoOther',
+                      'alpha'        : 'CpuInfoOther',
+                      'arm'          : 'CpuInfoOther',
+                      'cris'         : 'CpuInfoOther',
+                      'hppa'         : 'CpuInfoOther',
+                      'lm32'         : 'CpuInfoOther',
+                      'm68k'         : 'CpuInfoOther',
+                      'microblaze'   : 'CpuInfoOther',
+                      'microblazeel' : 'CpuInfoOther',
+                      'moxie'        : 'CpuInfoOther',
+                      'nios2'        : 'CpuInfoOther',
+                      'or1k'         : 'CpuInfoOther',
+                      'sh4'          : 'CpuInfoOther',
+                      'sh4eb'        : 'CpuInfoOther',
+                      'unicore32'    : 'CpuInfoOther',
+                      'xtensa'       : 'CpuInfoOther',
+                      'xtensaeb'     : 'CpuInfoOther' } }
 
 ##
 # @query-cpus-fast:
 #
 # Returns information about all virtual CPUs. This command does not
 # incur a performance penalty and should be used in production
 # instead of query-cpus.
 #
 # Returns: list of @CpuInfoFast
 #
 # Since: 2.12
@@ -630,33 +684,35 @@ 
 # -> { "execute": "query-cpus-fast" }
 # <- { "return": [
 #         {
 #             "thread-id": 25627,
 #             "props": {
 #                 "core-id": 0,
 #                 "thread-id": 0,
 #                 "socket-id": 0
 #             },
 #             "qom-path": "/machine/unattached/device[0]",
 #             "arch":"x86",
+#             "target":"x86_64",
 #             "cpu-index": 0
 #         },
 #         {
 #             "thread-id": 25628,
 #             "props": {
 #                 "core-id": 0,
 #                 "thread-id": 0,
 #                 "socket-id": 1
 #             },
 #             "qom-path": "/machine/unattached/device[2]",
 #             "arch":"x86",
+#             "target":"x86_64",
 #             "cpu-index": 1
 #         }
 #     ]
 # }
 ##
 { 'command': 'query-cpus-fast', 'returns': [ 'CpuInfoFast' ] }
 
 ##
 # @IOThreadInfo:
 #
 # Information about an iothread
diff --git a/cpus.c b/cpus.c
index 60563a6d54ec..86eed0ffe796 100644
--- a/cpus.c
+++ b/cpus.c
@@ -2093,88 +2093,235 @@  int vm_stop_force_state(RunState state)
     }
 }
 
 void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
 {
     /* XXX: implement xxx_cpu_list for targets that still miss it */
 #if defined(cpu_list)
     cpu_list(f, cpu_fprintf);
 #endif
 }
 
+static CpuInfoArch sysemu_target_to_cpuinfo_arch(SysEmuTarget target)
+{
+    /*
+     * The @SysEmuTarget -> @CpuInfoArch mapping below is based on the
+     * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script.
+     */
+    switch (target) {
+    case SYS_EMU_TARGET_I386:
+    case SYS_EMU_TARGET_X86_64:
+        return CPU_INFO_ARCH_X86;
+
+    case SYS_EMU_TARGET_PPC:
+    case SYS_EMU_TARGET_PPCEMB:
+    case SYS_EMU_TARGET_PPC64:
+        return CPU_INFO_ARCH_PPC;
+
+    case SYS_EMU_TARGET_SPARC:
+    case SYS_EMU_TARGET_SPARC64:
+        return CPU_INFO_ARCH_SPARC;
+
+    case SYS_EMU_TARGET_MIPS:
+    case SYS_EMU_TARGET_MIPSEL:
+    case SYS_EMU_TARGET_MIPS64:
+    case SYS_EMU_TARGET_MIPS64EL:
+        return CPU_INFO_ARCH_MIPS;
+
+    case SYS_EMU_TARGET_TRICORE:
+        return CPU_INFO_ARCH_TRICORE;
+
+    case SYS_EMU_TARGET_S390X:
+        return CPU_INFO_ARCH_S390;
+
+    case SYS_EMU_TARGET_RISCV32:
+    case SYS_EMU_TARGET_RISCV64:
+        return CPU_INFO_ARCH_RISCV;
+
+    default:
+        return CPU_INFO_ARCH_OTHER;
+    }
+}
+
+static void cpustate_to_cpuinfo_x86(CpuInfoX86 *info, const CPUState *cpu)
+{
+#ifdef TARGET_I386
+    X86CPU *x86_cpu = X86_CPU(cpu);
+    CPUX86State *env = &x86_cpu->env;
+
+    info->pc = env->eip + env->segs[R_CS].base;
+#else
+    abort();
+#endif
+}
+
+static void cpustate_to_cpuinfo_ppc(CpuInfoPPC *info, const CPUState *cpu)
+{
+#ifdef TARGET_PPC
+    PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
+    CPUPPCState *env = &ppc_cpu->env;
+
+    info->nip = env->nip;
+#else
+    abort();
+#endif
+}
+
+static void cpustate_to_cpuinfo_sparc(CpuInfoSPARC *info, const CPUState *cpu)
+{
+#ifdef TARGET_SPARC
+    SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
+    CPUSPARCState *env = &sparc_cpu->env;
+
+    info->pc = env->pc;
+    info->npc = env->npc;
+#else
+    abort();
+#endif
+}
+
+static void cpustate_to_cpuinfo_mips(CpuInfoMIPS *info, const CPUState *cpu)
+{
+#ifdef TARGET_MIPS
+    MIPSCPU *mips_cpu = MIPS_CPU(cpu);
+    CPUMIPSState *env = &mips_cpu->env;
+
+    info->PC = env->active_tc.PC;
+#else
+    abort();
+#endif
+}
+
+static void cpustate_to_cpuinfo_tricore(CpuInfoTricore *info,
+                                        const CPUState *cpu)
+{
+#ifdef TARGET_TRICORE
+    TriCoreCPU *tricore_cpu = TRICORE_CPU(cpu);
+    CPUTriCoreState *env = &tricore_cpu->env;
+
+    info->PC = env->PC;
+#else
+    abort();
+#endif
+}
+
+static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu)
+{
+#ifdef TARGET_S390X
+    S390CPU *s390_cpu = S390_CPU(cpu);
+    CPUS390XState *env = &s390_cpu->env;
+
+    info->cpu_state = env->cpu_state;
+#else
+    abort();
+#endif
+}
+
+static void cpustate_to_cpuinfo_riscv(CpuInfoRISCV *info, const CPUState *cpu)
+{
+#ifdef TARGET_RISCV
+    RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
+    CPURISCVState *env = &riscv_cpu->env;
+
+    info->pc = env->pc;
+#else
+    abort();
+#endif
+}
+
 CpuInfoList *qmp_query_cpus(Error **errp)
 {
     MachineState *ms = MACHINE(qdev_get_machine());
     MachineClass *mc = MACHINE_GET_CLASS(ms);
     CpuInfoList *head = NULL, *cur_item = NULL;
+    SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME,
+                                          -1, &error_abort);
     CPUState *cpu;
 
     CPU_FOREACH(cpu) {
         CpuInfoList *info;
-#if defined(TARGET_I386)
-        X86CPU *x86_cpu = X86_CPU(cpu);
-        CPUX86State *env = &x86_cpu->env;
-#elif defined(TARGET_PPC)
-        PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu);
-        CPUPPCState *env = &ppc_cpu->env;
-#elif defined(TARGET_SPARC)
-        SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
-        CPUSPARCState *env = &sparc_cpu->env;
-#elif defined(TARGET_RISCV)
-        RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
-        CPURISCVState *env = &riscv_cpu->env;
-#elif defined(TARGET_MIPS)
-        MIPSCPU *mips_cpu = MIPS_CPU(cpu);
-        CPUMIPSState *env = &mips_cpu->env;
-#elif defined(TARGET_TRICORE)
-        TriCoreCPU *tricore_cpu = TRICORE_CPU(cpu);
-        CPUTriCoreState *env = &tricore_cpu->env;
-#elif defined(TARGET_S390X)
-        S390CPU *s390_cpu = S390_CPU(cpu);
-        CPUS390XState *env = &s390_cpu->env;
-#endif
 
         cpu_synchronize_state(cpu);
 
         info = g_malloc0(sizeof(*info));
         info->value = g_malloc0(sizeof(*info->value));
         info->value->CPU = cpu->cpu_index;
         info->value->current = (cpu == first_cpu);
         info->value->halted = cpu->halted;
         info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
         info->value->thread_id = cpu->thread_id;
-#if defined(TARGET_I386)
-        info->value->arch = CPU_INFO_ARCH_X86;
-        info->value->u.x86.pc = env->eip + env->segs[R_CS].base;
-#elif defined(TARGET_PPC)
-        info->value->arch = CPU_INFO_ARCH_PPC;
-        info->value->u.ppc.nip = env->nip;
-#elif defined(TARGET_SPARC)
-        info->value->arch = CPU_INFO_ARCH_SPARC;
-        info->value->u.q_sparc.pc = env->pc;
-        info->value->u.q_sparc.npc = env->npc;
-#elif defined(TARGET_MIPS)
-        info->value->arch = CPU_INFO_ARCH_MIPS;
-        info->value->u.q_mips.PC = env->active_tc.PC;
-#elif defined(TARGET_TRICORE)
-        info->value->arch = CPU_INFO_ARCH_TRICORE;
-        info->value->u.tricore.PC = env->PC;
-#elif defined(TARGET_S390X)
-        info->value->arch = CPU_INFO_ARCH_S390;
-        info->value->u.s390.cpu_state = env->cpu_state;
-#elif defined(TARGET_RISCV)
-        info->value->arch = CPU_INFO_ARCH_RISCV;
-        info->value->u.riscv.pc = env->pc;
-#else
-        info->value->arch = CPU_INFO_ARCH_OTHER;
-#endif
+        info->value->arch = sysemu_target_to_cpuinfo_arch(target);
+        info->value->target = target;
+
+        /*
+         * The @SysEmuTarget -> @CpuInfo mapping below is based on the
+         * TARGET_ARCH -> TARGET_BASE_ARCH mapping in the "configure" script.
+         */
+        switch (target) {
+        case SYS_EMU_TARGET_I386:
+            cpustate_to_cpuinfo_x86(&info->value->u.i386, cpu);
+            break;
+        case SYS_EMU_TARGET_X86_64:
+            cpustate_to_cpuinfo_x86(&info->value->u.x86_64, cpu);
+            break;
+
+        case SYS_EMU_TARGET_PPC:
+            cpustate_to_cpuinfo_ppc(&info->value->u.ppc, cpu);
+            break;
+        case SYS_EMU_TARGET_PPCEMB:
+            cpustate_to_cpuinfo_ppc(&info->value->u.ppcemb, cpu);
+            break;
+        case SYS_EMU_TARGET_PPC64:
+            cpustate_to_cpuinfo_ppc(&info->value->u.ppc64, cpu);
+            break;
+
+        case SYS_EMU_TARGET_SPARC:
+            cpustate_to_cpuinfo_sparc(&info->value->u.q_sparc, cpu);
+            break;
+        case SYS_EMU_TARGET_SPARC64:
+            cpustate_to_cpuinfo_sparc(&info->value->u.sparc64, cpu);
+            break;
+
+        case SYS_EMU_TARGET_MIPS:
+            cpustate_to_cpuinfo_mips(&info->value->u.q_mips, cpu);
+            break;
+        case SYS_EMU_TARGET_MIPSEL:
+            cpustate_to_cpuinfo_mips(&info->value->u.mipsel, cpu);
+            break;
+        case SYS_EMU_TARGET_MIPS64:
+            cpustate_to_cpuinfo_mips(&info->value->u.mips64, cpu);
+            break;
+        case SYS_EMU_TARGET_MIPS64EL:
+            cpustate_to_cpuinfo_mips(&info->value->u.mips64el, cpu);
+            break;
+
+        case SYS_EMU_TARGET_TRICORE:
+            cpustate_to_cpuinfo_tricore(&info->value->u.tricore, cpu);
+            break;
+
+        case SYS_EMU_TARGET_S390X:
+            cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
+            break;
+
+        case SYS_EMU_TARGET_RISCV32:
+            cpustate_to_cpuinfo_riscv(&info->value->u.riscv32, cpu);
+            break;
+        case SYS_EMU_TARGET_RISCV64:
+            cpustate_to_cpuinfo_riscv(&info->value->u.riscv64, cpu);
+            break;
+
+        default:
+            /* do nothing for @CpuInfoOther */
+            break;
+        }
+
         info->value->has_props = !!mc->cpu_index_to_instance_props;
         if (info->value->has_props) {
             CpuInstanceProperties *props;
             props = g_malloc0(sizeof(*props));
             *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
             info->value->props = props;
         }
 
         /* XXX: waiting for the qapi to support GSList */
         if (!cur_item) {
             head = cur_item = info;
@@ -2188,64 +2335,50 @@  CpuInfoList *qmp_query_cpus(Error **errp)
 }
 
 /*
  * fast means: we NEVER interrupt vCPU threads to retrieve
  * information from KVM.
  */
 CpuInfoFastList *qmp_query_cpus_fast(Error **errp)
 {
     MachineState *ms = MACHINE(qdev_get_machine());
     MachineClass *mc = MACHINE_GET_CLASS(ms);
     CpuInfoFastList *head = NULL, *cur_item = NULL;
+    SysEmuTarget target = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME,
+                                          -1, &error_abort);
     CPUState *cpu;
-#if defined(TARGET_S390X)
-    S390CPU *s390_cpu;
-    CPUS390XState *env;
-#endif
 
     CPU_FOREACH(cpu) {
         CpuInfoFastList *info = g_malloc0(sizeof(*info));
         info->value = g_malloc0(sizeof(*info->value));
 
         info->value->cpu_index = cpu->cpu_index;
         info->value->qom_path = object_get_canonical_path(OBJECT(cpu));
         info->value->thread_id = cpu->thread_id;
 
         info->value->has_props = !!mc->cpu_index_to_instance_props;
         if (info->value->has_props) {
             CpuInstanceProperties *props;
             props = g_malloc0(sizeof(*props));
             *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
             info->value->props = props;
         }
 
-#if defined(TARGET_I386)
-        info->value->arch = CPU_INFO_ARCH_X86;
-#elif defined(TARGET_PPC)
-        info->value->arch = CPU_INFO_ARCH_PPC;
-#elif defined(TARGET_SPARC)
-        info->value->arch = CPU_INFO_ARCH_SPARC;
-#elif defined(TARGET_MIPS)
-        info->value->arch = CPU_INFO_ARCH_MIPS;
-#elif defined(TARGET_TRICORE)
-        info->value->arch = CPU_INFO_ARCH_TRICORE;
-#elif defined(TARGET_S390X)
-        s390_cpu = S390_CPU(cpu);
-        env = &s390_cpu->env;
-        info->value->arch = CPU_INFO_ARCH_S390;
-        info->value->u.s390.cpu_state = env->cpu_state;
-#elif defined(TARGET_RISCV)
-        info->value->arch = CPU_INFO_ARCH_RISCV;
-#else
-        info->value->arch = CPU_INFO_ARCH_OTHER;
-#endif
+        info->value->arch = sysemu_target_to_cpuinfo_arch(target);
+        info->value->target = target;
+        if (target == SYS_EMU_TARGET_S390X) {
+            cpustate_to_cpuinfo_s390(&info->value->u.s390x, cpu);
+        } else {
+            /* do nothing for @CpuInfoOther */
+        }
+
         if (!cur_item) {
             head = cur_item = info;
         } else {
             cur_item->next = info;
             cur_item = info;
         }
     }
 
     return head;
 }