Re: [PATCH v2 6/6] KVM: selftests: Add XCR0 Test

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Jan 4, 2023 at 5:13 PM Sean Christopherson <seanjc@xxxxxxxxxx> wrote:
>
> On Fri, Dec 30, 2022, Aaron Lewis wrote:
> > +static uint64_t get_supported_user_xfeatures(void)
>
> I would rather put this in processor.h too, with a "this_cpu" prefix.  Maybe
> this_cpu_supported_xcr0() or this_cpu_supported_user_xfeatures()?

this_cpu_supported_xcr0 works for me.

>
> > +{
> > +     uint32_t a, b, c, d;
> > +
> > +     cpuid(0xd, &a, &b, &c, &d);
> > +
> > +     return a | ((uint64_t)d << 32);
> > +}
> > +
> > +static void guest_code(void)
> > +{
> > +     uint64_t xcr0_rest;
>
> s/rest/reset ?
>
> > +     uint64_t supported_xcr0;
> > +     uint64_t xfeature_mask;
> > +     uint64_t supported_state;
> > +
> > +     set_cr4(get_cr4() | X86_CR4_OSXSAVE);
> > +
> > +     xcr0_rest = xgetbv(0);
> > +     supported_xcr0 = get_supported_user_xfeatures();
> > +
> > +     GUEST_ASSERT(xcr0_rest == 1ul);
>
> XFEATURE_MASK_FP instead of 1ul.
>
> > +
> > +     /* Check AVX */
> > +     xfeature_mask = XFEATURE_MASK_SSE | XFEATURE_MASK_YMM;
> > +     supported_state = supported_xcr0 & xfeature_mask;
> > +     GUEST_ASSERT(supported_state != XFEATURE_MASK_YMM);
>
> Oof, this took me far too long to read correctly.  What about?
>
>         /* AVX can be supported if and only if SSE is supported. */
>         GUEST_ASSERT((supported_xcr0 & XFEATURE_MASK_SSE) ||
>                      !(supported_xcr0 & XFEATURE_MASK_YMM));
>
> Hmm or maybe add helpers?  Printing the info on failure would also make it easier
> to debug.  E.g.
>
> static void check_all_or_none_xfeature(uint64_t supported_xcr0, uint64_t mask)
> {
>         supported_xcr0 &= mask;
>
>         GUEST_ASSERT_2(!supported_xcr0 || supported_xcr0 == mask,
>                        supported_xcr0, mask);
> }
>
> static void check_xfeature_dependencies(uint64_t supported_xcr0, uint64_t mask,
>                                         uint64_t dependencies)
> {
>         supported_xcr0 &= (mask | dependencies);
>
>         GUEST_ASSERT_3(!(supported_xcr0 & mask) ||
>                        supported_xcr0 == (mask | dependencies),
>                        supported_xcr0, mask, dependencies);
> }
>
> would yield
>
>         check_xfeature_dependencies(supported_xcr0, XFEATURE_MASK_YMM,
>                                     XFEATURE_MASK_SSE);
>
> and then for AVX512:
>
>         check_xfeature_dependencies(supported_xcr0, XFEATURE_MASK_AVX512,
>                                     XFEATURE_MASK_SSE | XFEATURE_MASK_YMM);
>         check_all_or_none_xfeature(supported_xcr0, XFEATURE_MASK_AVX512);
>
> That would more or less eliminate the need for comments, and IMO makes it more
> obvious what is being checked.

The reason I chose not to use helpers here was it hides the line
number the assert occured on.  With helpers you have multiple places
the problem came from and one place it's asserting.  The way I wrote
it the line number in the assert tells you exactly where the problem
occured.

I get you can deduce the line number with the values passed back in
the assert, but the assert information printed out on the host has to
be purposefully vague because you get one fmt for the entire test.  If
I was able to do a printf style asserts from the guest, that would
allow me to provide more, clear context to tie it back.  Having the
line number where the assert fired I felt was useful to keep.

I guess one way to get the best of both worlds would be to have the
helpers return a bool rather than assert in the helper.  I could also
include the additional info you suggested in the asserts.

That said, if we do end up going with helpers I don't think we have to
call them both like in the AVX512 example.  They both check the same
thing, except check_xfeature_dependencies() additionally allows for
dependencies to be used.  E.g.

if you call:
check_xfeature_dependencies(supported_xcr0, XFEATURE_MASK_AVX512, 0)

it's the same as calling:
check_all_or_none_xfeature(supported_xcr0, XFEATURE_MASK_AVX512)

Maybe we should call them: check_xfeature() and
check_xfeature_dependencies(), or with_dependencies... something to
show they are related to each other.

>
> > +     xsetbv(0, supported_xcr0);
> > +
> > +     GUEST_DONE();
> > +}
> > +
> > +static void guest_gp_handler(struct ex_regs *regs)
> > +{
> > +     GUEST_ASSERT(!"Failed to set the supported xfeature bits in XCR0.");
>
> I'd rather add an xsetbv_safe() variant than install a #GP handler.  That would
> also make it super easy to add negative testing.  E.g. (completely untested)
>
> static inline uint8_t xsetbv_safe(uint32_t index, uint64_t value)
> {
>         u32 eax = value;
>         u32 edx = value >> 32;
>
>         return kvm_asm_safe("xsetbv", "a" (eax), "d" (edx), "c" (index));
> }
>
> and
>         vector = xsetbv_safe(0, supported_xcr0);
>         GUEST_ASSERT_2(!vector, supported_xcr0, vector);
>
> and rudimentary negative testing
>
>         for (i = 0; i < 64; i++) {
>                 if (supported_xcr0 & BIT_ULL(i))
>                         continue;
>
>                 vector = xsetbv_safe(0, supported_xcr0 | BIT_ULL(i));
>                 GUEST_ASSERT_2(vector == GP_VECTOR, supported_xcr0, vector);
>         }

I like the idea of this additional test.  I'll add it.



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux