diff mbox series

target/i386/hvf: hide MPX states from XCR0

Message ID 20241029130401.525297-1-pbonzini@redhat.com (mailing list archive)
State New
Headers show
Series target/i386/hvf: hide MPX states from XCR0 | expand

Commit Message

Paolo Bonzini Oct. 29, 2024, 1:04 p.m. UTC
QEMU does not show availability of MPX in CPUID when running under
Hypervisor.framework.  Therefore, in the unlikely chance that the host
has MPX enabled, hide those bits from leaf 0xD as well.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 target/i386/hvf/x86_cpuid.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Phil Dennis-Jordan Oct. 30, 2024, 12:30 p.m. UTC | #1
On Tue, 29 Oct 2024 at 14:05, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> QEMU does not show availability of MPX in CPUID when running under
> Hypervisor.framework.  Therefore, in the unlikely chance that the host
> has MPX enabled, hide those bits from leaf 0xD as well.

To clarify: is there some kind of issue with MPX in Qemu in general?
Or is this a consistency effort - normal Macs don't expose this
feature, so we have no idea if it were to work if someone did manage
to hack up some frankensteinian host system that somehow does have
those bits set?


> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  target/i386/hvf/x86_cpuid.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c
> index e56cd8411ba..4b184767f4a 100644
> --- a/target/i386/hvf/x86_cpuid.c
> +++ b/target/i386/hvf/x86_cpuid.c
> @@ -110,9 +110,9 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
>          if (idx == 0) {
>              uint64_t host_xcr0;
>              if (xgetbv(ecx, 0, &host_xcr0)) {
> +                /* Only show xcr0 bits corresponding to usable features.  */
>                  uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
>                                    XSTATE_SSE_MASK | XSTATE_YMM_MASK |
> -                                  XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
>                                    XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
>                                    XSTATE_Hi16_ZMM_MASK);
>                  eax &= supp_xcr0;
> --
> 2.47.0
>
>
Paolo Bonzini Oct. 30, 2024, 1:35 p.m. UTC | #2
On 10/30/24 13:30, Phil Dennis-Jordan wrote:
> On Tue, 29 Oct 2024 at 14:05, Paolo Bonzini <pbonzini@redhat.com> wrote:
>>
>> QEMU does not show availability of MPX in CPUID when running under
>> Hypervisor.framework.  Therefore, in the unlikely chance that the host
>> has MPX enabled, hide those bits from leaf 0xD as well.
> 
> To clarify: is there some kind of issue with MPX in Qemu in general?
> Or is this a consistency effort - normal Macs don't expose this
> feature, so we have no idea if it were to work if someone did manage
> to hack up some frankensteinian host system that somehow does have
> those bits set?

That, and also that real hardware will only show XSTATE_BNDREGS_MASK and 
XSTATE_BNDCSR_MASK if the MPX bit is set in CPUID; which it isn't in 
hvf_get_supported_cpuid().

In fact, for completeness it should also go the other way: if 
XSTATE_YMM_MASK is not set in the result of XGETBV, AVX should be 
hidden.  And if any of OPMASK, ZMM_Hi256 and Hi16_ZMM are not set in the 
result of XGETBV, AVX512F (and AVX10 eventually) should be hidden in 
hvf_get_supported_cpuid().

By the way, could you check if Macs set the PKRU bit of XCR0 (bit 9) 
and/or the OSPKE bit in CPUID (that's bit 4 of CPUID[EAX=7, ECX=0].ECX)?

Thanks,

Paolo

> 
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>   target/i386/hvf/x86_cpuid.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c
>> index e56cd8411ba..4b184767f4a 100644
>> --- a/target/i386/hvf/x86_cpuid.c
>> +++ b/target/i386/hvf/x86_cpuid.c
>> @@ -110,9 +110,9 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
>>           if (idx == 0) {
>>               uint64_t host_xcr0;
>>               if (xgetbv(ecx, 0, &host_xcr0)) {
>> +                /* Only show xcr0 bits corresponding to usable features.  */
>>                   uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
>>                                     XSTATE_SSE_MASK | XSTATE_YMM_MASK |
>> -                                  XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
>>                                     XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
>>                                     XSTATE_Hi16_ZMM_MASK);
>>                   eax &= supp_xcr0;
>> --
>> 2.47.0
>>
>>
> 
>
Phil Dennis-Jordan Oct. 30, 2024, 3:24 p.m. UTC | #3
On Wed, 30 Oct 2024 at 14:35, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> On 10/30/24 13:30, Phil Dennis-Jordan wrote:
> > On Tue, 29 Oct 2024 at 14:05, Paolo Bonzini <pbonzini@redhat.com> wrote:
> >>
> >> QEMU does not show availability of MPX in CPUID when running under
> >> Hypervisor.framework.  Therefore, in the unlikely chance that the host
> >> has MPX enabled, hide those bits from leaf 0xD as well.
> >
> > To clarify: is there some kind of issue with MPX in Qemu in general?
> > Or is this a consistency effort - normal Macs don't expose this
> > feature, so we have no idea if it were to work if someone did manage
> > to hack up some frankensteinian host system that somehow does have
> > those bits set?
>
> That, and also that real hardware will only show XSTATE_BNDREGS_MASK and
> XSTATE_BNDCSR_MASK if the MPX bit is set in CPUID; which it isn't in
> hvf_get_supported_cpuid().

Understood, and makes sense. Perhaps you could add this to the commit
message as well?

> In fact, for completeness it should also go the other way: if
> XSTATE_YMM_MASK is not set in the result of XGETBV, AVX should be
> hidden.  And if any of OPMASK, ZMM_Hi256 and Hi16_ZMM are not set in the
> result of XGETBV, AVX512F (and AVX10 eventually) should be hidden in
> hvf_get_supported_cpuid().

Indeed. macOS does also have AVX512 support, and I believe there were
two Mac models which shipped with Xeon CPUs that exposed some version
of the feature, the iMac Pro and the 2019 Mac Pro. I don't have access
to such a machine however, so I’m not sure exactly what the host
support entails. (I don't know if HVF guests theoretically could
support AVX512 features supported by the CPU but not the host OS as
long as it only uses register state correctly saved by the host OS?)

> By the way, could you check if Macs set the PKRU bit of XCR0 (bit 9)
> and/or the OSPKE bit in CPUID (that's bit 4 of CPUID[EAX=7, ECX=0].ECX)?

On a 2019 MacBook Pro 15" with a Coffee Lake Intel Core i9 9880H CPU,
the OSPKE bit is not set. (cpuid 7,0 returns: ebx = 0x029c67af, ecx =
0x40000000, edx = 0xbc000e00)

Assuming I'm doing this right, xcr0 on this machine appears to be 0x7,
so there's no PKRU bit set.

While trying to log xcr0, I noticed that xgetbv checks the passed ecx
value against CPUID_EXT_OSXSAVE. Except as far as I'm aware, OSXSAVE
is in cpuid function 1's ecx, whereas the code path in
hvf_get_supported_cpuid() is, by my reading, passing the ecx value for
cpuid function 0xD, index 0. The xgetbv call thus returns false on my
machine (ecx = 0x440), and eax is not modified. (stays 0x1f rather
than 0x7)

It seems like we ought to either fetch the CPUID_EXT_OSXSAVE bit in
another cpuid call, or cache it. Or do I have this wrong?

Thanks,
Phil
diff mbox series

Patch

diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c
index e56cd8411ba..4b184767f4a 100644
--- a/target/i386/hvf/x86_cpuid.c
+++ b/target/i386/hvf/x86_cpuid.c
@@ -110,9 +110,9 @@  uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
         if (idx == 0) {
             uint64_t host_xcr0;
             if (xgetbv(ecx, 0, &host_xcr0)) {
+                /* Only show xcr0 bits corresponding to usable features.  */
                 uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
                                   XSTATE_SSE_MASK | XSTATE_YMM_MASK |
-                                  XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
                                   XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
                                   XSTATE_Hi16_ZMM_MASK);
                 eax &= supp_xcr0;