On Thu, Aug 07, 2025 at 04:39:35PM +0200, Magnus Kulke wrote:
> Create MSHV vCPUs using MSHV_CREATE_VP and initialize their state.
> Register the MSHV CPU execution loop loop with the QEMU accelerator
> framework to enable guest code execution.
> 
> The target/i386 functionality is still mostly stubbed out and will be
> populated in a later commit in this series.
> 
> Signed-off-by: Magnus Kulke <magnusku...@linux.microsoft.com>
> ---
>  accel/mshv/mshv-all.c       | 187 +++++++++++++++++++++++++++++++++---
>  accel/mshv/trace-events     |   2 +
>  include/system/mshv.h       |  17 ++++
>  target/i386/mshv/mshv-cpu.c |  63 ++++++++++++
>  4 files changed, 257 insertions(+), 12 deletions(-)
> 
> diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
> index 54c32d6252..a4eeaeec76 100644
> --- a/accel/mshv/mshv-all.c
> +++ b/accel/mshv/mshv-all.c
> @@ -391,6 +391,24 @@ int mshv_hvcall(int vm_fd, const struct mshv_root_hvcall 
> *args)
>      return ret;
>  }
>  
> +static int mshv_init_vcpu(CPUState *cpu)
> +{
> +    int vm_fd = mshv_state->vm;
> +    uint8_t vp_index = cpu->cpu_index;
> +    int ret;
> +
> +    mshv_arch_init_vcpu(cpu);
> +    cpu->accel = g_new0(AccelCPUState, 1);
> +
> +    ret = mshv_create_vcpu(vm_fd, vp_index, &cpu->accel->cpufd);
> +    if (ret < 0) {
> +        return -1;
> +    }
> +
> +    cpu->accel->dirty = true;
> +
> +    return 0;
> +}
>  
>  static int mshv_init(AccelState *as, MachineState *ms)
>  {
> @@ -413,6 +431,8 @@ static int mshv_init(AccelState *as, MachineState *ms)
>          return -1;
>      }
>  
> +    mshv_init_cpu_logic();
> +
>      mshv_init_msicontrol();
>  
>      ret = create_vm(mshv_fd, &vm_fd);
> @@ -442,40 +462,183 @@ static int mshv_init(AccelState *as, MachineState *ms)
>      return 0;
>  }
>  
> +static int mshv_destroy_vcpu(CPUState *cpu)
> +{
> +    int cpu_fd = mshv_vcpufd(cpu);
> +    int vm_fd = mshv_state->vm;
> +
> +    mshv_remove_vcpu(vm_fd, cpu_fd);
> +    mshv_vcpufd(cpu) = 0;
> +
> +    mshv_arch_destroy_vcpu(cpu);
> +    g_free(cpu->accel);

Since the lifetime of the CPUState is not tightly
tied to the cpu->accel, I'd suggest that here
should use

  g_clear_pointer(&cpu->accel, g_free);

so that if there is any race with code accessing
cpu->accel after it is free'd, we'll get a clear
NULL de-reference, rather than use-after-free which
is harder to diagnose.


> +static void *mshv_vcpu_thread(void *arg)
> +{
> +    CPUState *cpu = arg;
> +    int ret;
> +
> +    rcu_register_thread();
> +
> +    bql_lock();
> +    qemu_thread_get_self(cpu->thread);
> +    cpu->thread_id = qemu_get_thread_id();

So every MSHV  vCPU has a corresponding Linux thread, similar
to the model with KVM.  In libvirt we rely on the vCPU thread
being controllable with all the normal Linux process related
APIs. For example, setting thread CPU affinity, setting NUMA
memory policy, setting scheduler priorities, putting threads
into cgroups and applying a wide variety of cgroup controls.

Will there be any significant "gotchas" with the threads for
MSHV vCPUs, that would mean the above libvirt controls would
either raise errors, or silently not have any effect ?


> +    current_cpu = cpu;
> +    ret = mshv_init_vcpu(cpu);
> +    if (ret < 0) {
> +        error_report("Failed to init vcpu %d", cpu->cpu_index);
> +        goto cleanup;
> +    }
> +
> +    /* signal CPU creation */
> +    cpu_thread_signal_created(cpu);
> +    qemu_guest_random_seed_thread_part2(cpu->random_seed);
> +
> +    do {
> +        if (cpu_can_run(cpu)) {
> +            mshv_cpu_exec(cpu);
> +        }
> +        qemu_wait_io_event(cpu);
> +    } while (!cpu->unplug || cpu_can_run(cpu));
> +
> +    mshv_destroy_vcpu(cpu);
> +cleanup:
> +    cpu_thread_signal_destroyed(cpu);
> +    bql_unlock();
> +    rcu_unregister_thread();
> +    return NULL;
> +}
> +
>  static void mshv_start_vcpu_thread(CPUState *cpu)
>  {
> -    error_report("unimplemented");
> -    abort();
> +    char thread_name[VCPU_THREAD_NAME_SIZE];
> +
> +    cpu->thread = g_malloc0(sizeof(QemuThread));

     = g_new0(QemuThread, 1);

> +    cpu->halt_cond = g_malloc0(sizeof(QemuCond));

     = g_new0(QemuCond, 1);

> +
> +    qemu_cond_init(cpu->halt_cond);
> +
> +    trace_mshv_start_vcpu_thread(thread_name, cpu->cpu_index);
> +    qemu_thread_create(cpu->thread, thread_name, mshv_vcpu_thread, cpu,
> +                       QEMU_THREAD_JOINABLE);
> +}



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 via email to