All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrangé" <berrange@redhat.com>
To: Magnus Kulke <magnuskulke@linux.microsoft.com>
Cc: qemu-devel@nongnu.org, "Eric Blake" <eblake@redhat.com>,
	"Eduardo Habkost" <eduardo@habkost.net>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>,
	"Magnus Kulke" <magnus.kulke@linux.microsoft.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Phil Dennis-Jordan" <phil@philjordan.eu>,
	"Marcel Apfelbaum" <marcel.apfelbaum@gmail.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Magnus Kulke" <magnus.kulke@microsoft.com>,
	"Cornelia Huck" <cohuck@redhat.com>,
	"Zhao Liu" <zhao1.liu@intel.com>,
	"Thomas Huth" <thuth@redhat.com>,
	"Yanan Wang" <wangyanan55@huawei.com>,
	"Cameron Esfahani" <dirty@apple.com>,
	"Wei Liu" <wei.liu@kernel.org>, "Wei Liu" <liuwe@microsoft.com>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Roman Bolshakov" <rbolshakov@ddn.com>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>
Subject: Re: [PATCH v3 18/26] target/i386/mshv: Register CPUID entries with MSHV
Date: Wed, 27 Aug 2025 12:29:25 +0100	[thread overview]
Message-ID: <aK7sFds3tf5fMToM@redhat.com> (raw)
In-Reply-To: <20250807143951.1154713-19-magnuskulke@linux.microsoft.com>

On Thu, Aug 07, 2025 at 04:39:43PM +0200, Magnus Kulke wrote:
> Convert the guest CPU's CPUID model into MSHV's format and register it
> with the hypervisor. This ensures that the guest observes the correct
> CPU feature set during CPUID instructions.

QEMU supports a variety of CPU models. '-cpu host' is intended to
expose every possible feature that the underlying hypervisor can
support, while '-cpu $NAME' exposes certain named CPU models.

Also KVM will force enable certain features that it can either
unconditionally emulate, or requires to always be present.

Are you aware if there any noteworthy differences /  restrictions
in the use of CPU models for MSHV that would not be present for
KVM, or vica-verca ?  I'm particularly wondering if there is
anything special libvirt needs to be aware of - most of what
libvirt does it gets via the QMP query-cpu-XXXX commands.

> 
> Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
> ---
>  target/i386/mshv/mshv-cpu.c | 199 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 199 insertions(+)
> 
> diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
> index c233d4af70..0b7350877d 100644
> --- a/target/i386/mshv/mshv-cpu.c
> +++ b/target/i386/mshv/mshv-cpu.c
> @@ -324,6 +324,199 @@ int mshv_load_regs(CPUState *cpu)
>      return 0;
>  }
>  
> +static void add_cpuid_entry(GList *cpuid_entries,
> +                            uint32_t function, uint32_t index,
> +                            uint32_t eax, uint32_t ebx,
> +                            uint32_t ecx, uint32_t edx)
> +{
> +    struct hv_cpuid_entry *entry;
> +
> +    entry = g_malloc0(sizeof(struct hv_cpuid_entry));
> +    entry->function = function;
> +    entry->index = index;
> +    entry->eax = eax;
> +    entry->ebx = ebx;
> +    entry->ecx = ecx;
> +    entry->edx = edx;
> +
> +    cpuid_entries = g_list_append(cpuid_entries, entry);
> +}
> +
> +static void collect_cpuid_entries(const CPUState *cpu, GList *cpuid_entries)
> +{
> +    X86CPU *x86_cpu = X86_CPU(cpu);
> +    CPUX86State *env = &x86_cpu->env;
> +    uint32_t eax, ebx, ecx, edx;
> +    uint32_t leaf, subleaf;
> +    size_t max_leaf = 0x1F;
> +    size_t max_subleaf = 0x20;
> +
> +    uint32_t leaves_with_subleaves[] = {0x4, 0x7, 0xD, 0xF, 0x10};
> +    int n_subleaf_leaves = ARRAY_SIZE(leaves_with_subleaves);
> +
> +    /* Regular leaves without subleaves */
> +    for (leaf = 0; leaf <= max_leaf; leaf++) {
> +        bool has_subleaves = false;
> +        for (int i = 0; i < n_subleaf_leaves; i++) {
> +            if (leaf == leaves_with_subleaves[i]) {
> +                has_subleaves = true;
> +                break;
> +            }
> +        }
> +
> +        if (!has_subleaves) {
> +            cpu_x86_cpuid(env, leaf, 0, &eax, &ebx, &ecx, &edx);
> +            if (eax == 0 && ebx == 0 && ecx == 0 && edx == 0) {
> +                /* all zeroes indicates no more leaves */
> +                continue;
> +            }
> +
> +            add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx);
> +            continue;
> +        }
> +
> +        subleaf = 0;
> +        while (subleaf < max_subleaf) {
> +            cpu_x86_cpuid(env, leaf, subleaf, &eax, &ebx, &ecx, &edx);
> +
> +            if (eax == 0 && ebx == 0 && ecx == 0 && edx == 0) {
> +                /* all zeroes indicates no more leaves */
> +                break;
> +            }
> +            add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx);
> +            subleaf++;
> +        }
> +    }
> +}
> +
> +static int register_intercept_result_cpuid_entry(int cpu_fd,
> +                                                 uint8_t subleaf_specific,
> +                                                 uint8_t always_override,
> +                                                 struct hv_cpuid_entry *entry)
> +{
> +    struct hv_register_x64_cpuid_result_parameters cpuid_params = {
> +        .input.eax = entry->function,
> +        .input.ecx = entry->index,
> +        .input.subleaf_specific = subleaf_specific,
> +        .input.always_override = always_override,
> +        .input.padding = 0,
> +        /*
> +         * With regard to masks - these are to specify bits to be overwritten
> +         * The current CpuidEntry structure wouldn't allow to carry the masks
> +         * in addition to the actual register values. For this reason, the
> +         * masks are set to the exact values of the corresponding register bits
> +         * to be registered for an overwrite. To view resulting values the
> +         * hypervisor would return, HvCallGetVpCpuidValues hypercall can be
> +         * used.
> +         */
> +        .result.eax = entry->eax,
> +        .result.eax_mask = entry->eax,
> +        .result.ebx = entry->ebx,
> +        .result.ebx_mask = entry->ebx,
> +        .result.ecx = entry->ecx,
> +        .result.ecx_mask = entry->ecx,
> +        .result.edx = entry->edx,
> +        .result.edx_mask = entry->edx,
> +    };
> +    union hv_register_intercept_result_parameters parameters = {
> +        .cpuid = cpuid_params,
> +    };
> +    struct mshv_register_intercept_result args = {
> +        .intercept_type = HV_INTERCEPT_TYPE_X64_CPUID,
> +        .parameters = parameters,
> +    };
> +    int ret;
> +
> +    ret = ioctl(cpu_fd, MSHV_VP_REGISTER_INTERCEPT_RESULT, &args);
> +    if (ret < 0) {
> +        error_report("failed to register intercept result for cpuid: %s",
> +                     strerror(errno));
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +static int register_intercept_result_cpuid(int cpu_fd, struct hv_cpuid *cpuid)
> +{
> +    int ret = 0, entry_ret;
> +    struct hv_cpuid_entry *entry;
> +    uint8_t subleaf_specific, always_override;
> +
> +    for (size_t i = 0; i < cpuid->nent; i++) {
> +        entry = &cpuid->entries[i];
> +
> +        /* set defaults */
> +        subleaf_specific = 0;
> +        always_override = 1;
> +
> +        /* Intel */
> +        /* 0xb - Extended Topology Enumeration Leaf */
> +        /* 0x1f - V2 Extended Topology Enumeration Leaf */
> +        /* AMD */
> +        /* 0x8000_001e - Processor Topology Information */
> +        /* 0x8000_0026 - Extended CPU Topology */
> +        if (entry->function == 0xb
> +            || entry->function == 0x1f
> +            || entry->function == 0x8000001e
> +            || entry->function == 0x80000026) {
> +            subleaf_specific = 1;
> +            always_override = 1;
> +        } else if (entry->function == 0x00000001
> +            || entry->function == 0x80000000
> +            || entry->function == 0x80000001
> +            || entry->function == 0x80000008) {
> +            subleaf_specific = 0;
> +            always_override = 1;
> +        }
> +
> +        entry_ret = register_intercept_result_cpuid_entry(cpu_fd,
> +                                                          subleaf_specific,
> +                                                          always_override,
> +                                                          entry);
> +        if ((entry_ret < 0) && (ret == 0)) {
> +            ret = entry_ret;
> +        }
> +    }
> +
> +    return ret;
> +}
> +
> +static int set_cpuid2(const CPUState *cpu)
> +{
> +    int ret;
> +    size_t n_entries, cpuid_size;
> +    struct hv_cpuid *cpuid;
> +    struct hv_cpuid_entry *entry;
> +    GList *entries = NULL;
> +    int cpu_fd = mshv_vcpufd(cpu);
> +
> +    collect_cpuid_entries(cpu, entries);
> +    n_entries = g_list_length(entries);
> +
> +    cpuid_size = sizeof(struct hv_cpuid)
> +        + n_entries * sizeof(struct hv_cpuid_entry);
> +
> +    cpuid = g_malloc0(cpuid_size);
> +    cpuid->nent = n_entries;
> +    cpuid->padding = 0;
> +
> +    for (size_t i = 0; i < n_entries; i++) {
> +        entry = g_list_nth_data(entries, i);
> +        cpuid->entries[i] = *entry;
> +        g_free(entry);
> +    }
> +    g_list_free(entries);
> +
> +    ret = register_intercept_result_cpuid(cpu_fd, cpuid);
> +    g_free(cpuid);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +
> +    return 0;
> +}
> +
>  static inline void populate_hv_segment_reg(SegmentCache *seg,
>                                             hv_x64_segment_register *hv_reg)
>  {
> @@ -608,6 +801,12 @@ int mshv_configure_vcpu(const CPUState *cpu, const struct MshvFPU *fpu,
>      int ret;
>      int cpu_fd = mshv_vcpufd(cpu);
>  
> +    ret = set_cpuid2(cpu);
> +    if (ret < 0) {
> +        error_report("failed to set cpuid");
> +        return -1;
> +    }
> +
>      ret = set_cpu_state(cpu, fpu, xcr0);
>      if (ret < 0) {
>          error_report("failed to set cpu state");
> -- 
> 2.34.1
> 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



  reply	other threads:[~2025-08-27 11:30 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-07 14:39 [PATCH v3 00/26] Implementing a MSHV (Microsoft Hypervisor) accelerator Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 01/26] accel: Add Meson and config support for MSHV accelerator Magnus Kulke
2025-08-11 17:51   ` Wei Liu
2025-08-27 10:27   ` Daniel P. Berrangé
2025-08-07 14:39 ` [PATCH v3 02/26] target/i386/emulate: Allow instruction decoding from stream Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 03/26] target/i386/mshv: Add x86 decoder/emu implementation Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 04/26] hw/intc: Generalize APIC helper names from kvm_* to accel_* Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 05/26] include/hw/hyperv: Add MSHV ABI header definitions Magnus Kulke
2025-08-27 10:44   ` Daniel P. Berrangé
2025-08-07 14:39 ` [PATCH v3 06/26] linux-headers/linux: Add mshv.h headers Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 07/26] accel/mshv: Add accelerator skeleton Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 08/26] accel/mshv: Register memory region listeners Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 09/26] accel/mshv: Initialize VM partition Magnus Kulke
2025-08-27 11:15   ` Daniel P. Berrangé
2025-08-07 14:39 ` [PATCH v3 10/26] accel/mshv: Add vCPU creation and execution loop Magnus Kulke
2025-08-27 11:24   ` Daniel P. Berrangé
2025-08-27 17:39     ` Wei Liu
2025-09-16  9:33     ` Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 11/26] accel/mshv: Add vCPU signal handling Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 12/26] target/i386/mshv: Add CPU create and remove logic Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 13/26] target/i386/mshv: Implement mshv_store_regs() Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 14/26] target/i386/mshv: Implement mshv_get_standard_regs() Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 15/26] target/i386/mshv: Implement mshv_get_special_regs() Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 16/26] target/i386/mshv: Implement mshv_arch_put_registers() Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 17/26] target/i386/mshv: Set local interrupt controller state Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 18/26] target/i386/mshv: Register CPUID entries with MSHV Magnus Kulke
2025-08-27 11:29   ` Daniel P. Berrangé [this message]
2025-09-16 10:49     ` Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 19/26] target/i386/mshv: Register MSRs " Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 20/26] target/i386/mshv: Integrate x86 instruction decoder/emulator Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 21/26] target/i386/mshv: Write MSRs to the hypervisor Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 22/26] target/i386/mshv: Implement mshv_vcpu_run() Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 23/26] accel/mshv: Handle overlapping mem mappings Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 24/26] docs: Add mshv to documentation Magnus Kulke
2025-08-27 11:33   ` Daniel P. Berrangé
2025-08-07 14:39 ` [PATCH v3 25/26] MAINTAINERS: Add maintainers for mshv accelerator Magnus Kulke
2025-08-07 14:39 ` [PATCH v3 26/26] qapi/accel: Allow to query mshv capabilities Magnus Kulke
2025-08-07 19:22   ` Wei Liu
2025-08-13  0:37     ` Wei Liu
2025-08-27 11:39   ` Daniel P. Berrangé
2025-08-11 17:59 ` [PATCH v3 00/26] Implementing a MSHV (Microsoft Hypervisor) accelerator Wei Liu
2025-09-11  6:59 ` Michael S. Tsirkin
2025-09-11 15:21   ` Paolo Bonzini
2025-09-11 16:07     ` Wei Liu
2025-09-11 16:26     ` Magnus Kulke
2025-09-18  4:08   ` Mohamed Mediouni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aK7sFds3tf5fMToM@redhat.com \
    --to=berrange@redhat.com \
    --cc=alex.bennee@linaro.org \
    --cc=armbru@redhat.com \
    --cc=cohuck@redhat.com \
    --cc=dirty@apple.com \
    --cc=eblake@redhat.com \
    --cc=eduardo@habkost.net \
    --cc=liuwe@microsoft.com \
    --cc=magnus.kulke@linux.microsoft.com \
    --cc=magnus.kulke@microsoft.com \
    --cc=magnuskulke@linux.microsoft.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=marcel.apfelbaum@gmail.com \
    --cc=mst@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=phil@philjordan.eu \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=rbolshakov@ddn.com \
    --cc=richard.henderson@linaro.org \
    --cc=thuth@redhat.com \
    --cc=wangyanan55@huawei.com \
    --cc=wei.liu@kernel.org \
    --cc=zhao1.liu@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.