On 28/03/2018 22:48, Justin Terry (VM) wrote:
> 1. (As the code is doing now). At partition creation time you can
> register for specific CPUID exits and then respond to the CPUID with
> your custom answer or with the Hypervisor defaults that were forwarded
> to you. Unfortunately, QEMU has no way to know the Hypervisor default
> ahead of time but QEMU can make at least make a runtime decision about
> how to respond.
>
> 2. At partition creation time the platform allows QEMU to inject (set)
> the default responses for specific CPUID exits.

... but it still cannot access the hypervisor defaults, right?

> This can now be done by
> setting the `WHV_X64_CPUID_RESULT` in the `CpuidResultList` of
> `WHV_PARTITION_PROPERTY` to the exit values QEMU wants. So effectively
> you can know the answers ahead of time for any that you set but the
> answers are not dynamic.
> 
> The only issues/questions I have there are:
> 
> If we use [1] (like the code is now) I don't see any way to keep the
> exits in cpu_x86_cpuid() matched up with the registered exits to WHPX.

You'd have to do that on a case-by-case basis.  For example, the number
of leaves can be the minimum of the hypervisor and QEMU values, or just
the QEMU value; for "feature" leaves the results will be the AND of the
QEMU and WHPX features; for the XSAVE/XSAVEC/XSAVES (size, offset)
tuples you have to use WHPX's; for family/model/stepping/name/vendor
your mileage may vary but I suppose you can just use WHPX's; and so on.

You can take a look at target/i386/cpu.c's array feature_word_info and
add a function like

void x86_is_feature_word(uint32_t eax, uint32_t ecx, int reg)
{
    for (w = 0; w < FEATURE_WORDS; w++) {
        FeatureWordInfo *wi = &feature_word_info[w];
        if (eax == wi->cpuid_eax &&
            (ecx == wi->cpuid_ecx || wi->cpuid_needs_ecx) &&
            reg == wi->cpuid_reg) {
            return true;
        }
    }
    return false;
}

so that the code in the end is

    switch (eax) {
        /* yadda yadda... code to special case leaves whose value
         * comes from WHPX.
         */
        ...
    default:
        if (x86_is_feature_word(eax, ecx, R_EAX)) {
            rax &= vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
        }
        if (x86_is_feature_word(eax, ecx, R_EBX)) {
            rax &= vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
        }
        if (x86_is_feature_word(eax, ecx, R_ECX)) {
            rax &= vcpu->exit_ctx.CpuidAccess.DefaultResultRcx;
        }
        if (x86_is_feature_word(eax, ecx, R_EDX)) {
            rax &= vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
        }
    }

> If we use [2] to inject the answers at creation time WHPX needs access
> to the CPUX86State at accel init which also doesn't seem to be possible
> in QEMU today. WHPX could basically just call cpu_x86_cpuid() for each
> CPUID QEMU cares about and plumb the answer before start. This has the
> best performance as we avoid the additional exits but has an issue in
> that the results must be known ahead of time.

The earliest where you have access to that is x86_cpu_initfn.

Paolo

Reply via email to