[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v1.1 5/5] tests: Introduce a TSX test
On 14.06.2021 12:47, Andrew Cooper wrote: > --- /dev/null > +++ b/tools/tests/tsx/Makefile > @@ -0,0 +1,43 @@ > +XEN_ROOT = $(CURDIR)/../../.. > +include $(XEN_ROOT)/tools/Rules.mk > + > +TARGET := test-tsx > + > +.PHONY: all > +all: $(TARGET) > + > +.PHONY: run > +run: $(TARGET) > + ./$(TARGET) > + > +.PHONY: clean > +clean: > + $(RM) -f -- *.o $(TARGET) $(DEPS_RM) I'm surprised this is necessary, but indeed I can see it elsewhere too. > +.PHONY: distclean > +distclean: clean > + $(RM) -f -- *~ > + > +.PHONY: install > +install: all > + > +.PHONY: uninstall > +uninstall: > + > +CFLAGS += -Werror -std=gnu11 Is this strictly necessary? It excludes a fair share of the gcc versions that we claim the tree can be built with. If it is necessary, then I think it needs arranging for that the tools/ build as a whole won't fail just because of this test not building. We do something along these lines for the x86 emulator harness, for example. > +CFLAGS += $(CFLAGS_xeninclude) > +CFLAGS += $(CFLAGS_libxenctrl) > +CFLAGS += $(CFLAGS_libxenguest) > +CFLAGS += -I$(XEN_ROOT)/tools/libs/ctrl -I$(XEN_ROOT)/tools/libs/guest > +CFLAGS += $(APPEND_CFLAGS) > + > +LDFLAGS += $(LDLIBS_libxenctrl) > +LDFLAGS += $(LDLIBS_libxenguest) > +LDFLAGS += $(APPEND_LDFLAGS) > + > +test-tsx.o: Makefile > + > +test-tsx: test-tsx.o Wouldn't you want to use $(TARGET) at least here? > +/* > + * Test a specific TSX MSR for consistency across the system, taking into > + * account whether it ought to be accessable or not. > + * > + * We can't query offline CPUs, so skip those if encountered. We don't care > + * particularly for the exact MSR value, but we do care that it is the same > + * everywhere. > + */ > +static void test_tsx_msr_consistency(unsigned int msr, bool accessable) Isn't it "accessible"? > +{ > + uint64_t cpu0_val = ~0; > + > + for ( unsigned int cpu = 0; cpu <= physinfo.max_cpu_id; ++cpu ) > + { > + xc_resource_entry_t ent = { > + .u.cmd = XEN_RESOURCE_OP_MSR_READ, > + .idx = msr, > + }; > + xc_resource_op_t op = { > + .cpu = cpu, > + .entries = &ent, > + .nr_entries = 1, > + }; > + int rc = xc_resource_op(xch, 1, &op); > + > + if ( rc < 0 ) > + { > + /* Don't emit a message for offline CPUs */ > + if ( errno != ENODEV ) > + fail(" xc_resource_op() for CPU%u failed: rc %d, errno %d - > %s\n", > + cpu, rc, errno, strerror(errno)); > + continue; > + } > + > + if ( accessable ) > + { > + if ( rc != 1 ) > + { > + fail(" Expected 1 result, got %u\n", rc); %d > + continue; > + } > + if ( ent.u.ret != 0 ) > + { > + fail(" Expected ok, got %d\n", ent.u.ret); > + continue; > + } > + } > + else > + { > + if ( rc != 0 ) > + fail(" Expected 0 results, got %u\n", rc); > + else if ( ent.u.ret != -EPERM ) > + fail(" Expected -EPERM, got %d\n", ent.u.ret); > + continue; > + } > + > + if ( cpu == 0 ) > + { > + cpu0_val = ent.val; > + printf(" CPU0 val %#"PRIx64"\n", cpu0_val); > + } > + else if ( ent.val != cpu0_val ) > + fail(" CPU%u val %#"PRIx64" differes from CPU0 %#"PRIx64"\n", Nit: differs? > +/* > + * Probe for how RTM behaves, deliberately not inspecting CPUID. > + * Distinguishes between "no support at all" (i.e. XBEGIN suffers #UD), > + * working ok, and appearing to always abort. > + */ > +static enum rtm_behaviour probe_rtm_behaviour(void) > +{ > + for ( int i = 0; i < 1000; ++i ) > + { > + /* > + * Opencoding the RTM infrastructure from immintrin.h, because we > + * still support older versions of GCC. ALso so we can include #UD > + * detection logic. > + */ > +#define XBEGIN_STARTED -1 > +#define XBEGIN_UD -2 > + unsigned int status = XBEGIN_STARTED; > + > + asm volatile (".Lxbegin: .byte 0xc7,0xf8,0,0,0,0" /* XBEGIN 1f; 1: */ > + : "+a" (status) :: "memory"); > + if ( status == XBEGIN_STARTED ) > + { > + asm volatile (".byte 0x0f,0x01,0xd5" ::: "memory"); /* XEND */ Nit: This otherwise following hypervisor style, the asm()s want more blanks added (also again further down). > + return RTM_OK; > + } > + else if ( status == XBEGIN_UD ) > + return RTM_UD; > + } > + > + return RTM_ABORT; > +} > + > +static struct sigaction old_sigill; > + > +static void sigill_handler(int signo, siginfo_t *info, void *extra) > +{ > + extern char xbegin_label[] asm(".Lxbegin"); Perhaps add const? I'm also not sure about .L names used for extern-s. > + if ( info->si_addr == xbegin_label || > + memcmp(info->si_addr, "\xc7\xf8\x00\x00\x00\x00", 6) == 0 ) Why the || here? I could see you use && if you really wanted to be on the safe side, but the way you have it I don't understand the intentions. > + { > + ucontext_t *context = extra; > + > + /* > + * Found the XBEGIN instruction. Step over it, and update `status` > to > + * signal #UD. > + */ > +#ifdef __x86_64__ > + context->uc_mcontext.gregs[REG_RIP] += 6; > + context->uc_mcontext.gregs[REG_RAX] = XBEGIN_UD; > +#else > + context->uc_mcontext.gregs[REG_EIP] += 6; > + context->uc_mcontext.gregs[REG_EAX] = XBEGIN_UD; > +#endif At the very least for this, don't you need to constrain the test to just Linux? > +static void test_tsx(void) > +{ > + int rc; > + > + /* Read all policies except raw. */ > + for ( int i = XEN_SYSCTL_cpu_policy_host; To avoid having this as bad precedent, even though it's "just" testing code: unsigned int? (I've first spotted this here, but later I've found more places elsewhere.) Jan
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |