@@ -546,7 +546,7 @@ static inline void irq_enable(void)
asm volatile("sti");
}
-static inline void invlpg(volatile void *va)
+static inline void invlpg(const volatile void *va)
{
asm volatile("invlpg (%0)" ::"r" (va) : "memory");
}
@@ -20,6 +20,7 @@ tests += $(TEST_DIR)/tscdeadline_latency.flat
tests += $(TEST_DIR)/intel-iommu.flat
tests += $(TEST_DIR)/vmware_backdoors.flat
tests += $(TEST_DIR)/rdpru.flat
+tests += $(TEST_DIR)/chaos.flat
include $(SRCDIR)/$(TEST_DIR)/Makefile.common
new file mode 100644
@@ -0,0 +1,114 @@
+#include "libcflat.h"
+#include "smp.h"
+#include "bitops.h"
+#include "string.h"
+#include "alloc.h"
+#include "alloc_page.h"
+#include "asm/page.h"
+#include "processor.h"
+
+#define MAX_NR_CPUS 256
+
+struct chaos_args {
+ long npages; /* 0 for CPU workload. */
+ const char *mem;
+ int invtlb;
+};
+
+int ncpus;
+struct chaos_args all_args[MAX_NR_CPUS];
+
+static void parse_arg(struct chaos_args *args, const char *arg)
+{
+ char *s = strdup(arg);
+ char *p = s;
+
+ while (*p) {
+ char *word = p;
+ char delim = strdelim(&p, ",=");
+ long i = 0;
+ bool have_arg = false;
+ if (delim == '=') {
+ char *num = p;
+ strdelim(&p, ",");
+ if (!parse_long(num, &i))
+ printf("invalid argument for %s\n", word);
+ else
+ have_arg = true;
+ }
+
+ if (!strcmp(word, "mem")) {
+ if (!have_arg)
+ i = 12;
+ else if (i >= BITS_PER_LONG - 1 - PAGE_SHIFT) {
+ printf("mem argument too large, using 12\n");
+ i = 12;
+ }
+ args->npages = 1 << i;
+ args->mem = alloc_pages(i);
+ if (!args->mem)
+ printf("could not allocate memory\n");
+ printf("CPU %d: mem=%ld @ %p\n", smp_id(), i, args->mem);
+ } else if (!strcmp(word, "invtlb")) {
+ if (!have_arg)
+ i = 1;
+ else if (i != 0 && i != 1) {
+ printf("invtlb argument must be 0 or 1\n");
+ i = 1;
+ }
+ args->invtlb = i;
+ printf("CPU %d: invtlb=%ld\n", smp_id(), i);
+ } else {
+ printf("invalid argument %s\n", word);
+ }
+ }
+ free(s);
+}
+
+static void __attribute__((noreturn)) stress(void *data)
+{
+ const char *arg = data;
+ struct chaos_args *args = &all_args[smp_id()];
+
+ printf("starting CPU %d workload: %s\n", smp_id(), arg);
+ parse_arg(args, arg);
+
+ for (;;) {
+ if (args->mem) {
+ const char *s = args->mem;
+ const char *e = s + (args->npages << PAGE_SHIFT);
+ long i;
+ for (i = args->npages; args->invtlb && i--; )
+ invlpg(s + ((args->npages - i) << PAGE_SHIFT));
+ while (s < e) {
+ (*(unsigned long *)s)++;
+ s += sizeof(unsigned long);
+ }
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ setup_vm();
+ if (argc <= 1) {
+ return 1;
+ }
+
+ argv++;
+ argc--;
+ ncpus = cpu_count();
+ if (ncpus > MAX_NR_CPUS)
+ ncpus = MAX_NR_CPUS;
+
+ for (i = 1; i < ncpus; ++i) {
+ if (i >= argc) {
+ break;
+ }
+ on_cpu_async(i, stress, argv[i]);
+ }
+
+ stress(argv[0]);
+}
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> --- lib/x86/processor.h | 2 +- x86/Makefile.x86_64 | 1 + x86/chaos.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 x86/chaos.c