Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- x86/chaos.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 64 insertions(+) diff --git a/x86/chaos.c b/x86/chaos.c index e723a3b..0b1e29c 100644 --- a/x86/chaos.c +++ b/x86/chaos.c @@ -1,5 +1,7 @@ #include "libcflat.h" #include "smp.h" +#include "isr.h" +#include "apic.h" #include "bitops.h" #include "string.h" #include "alloc.h" @@ -9,14 +11,24 @@ #define MAX_NR_CPUS 256 +#define TIMER_IRQ 0x44 + struct chaos_args { long npages; /* 0 for CPU workload. */ const char *mem; int invtlb; + + int hz; + bool hlt; +}; + +struct counters { + int ticks_left; }; int ncpus; struct chaos_args all_args[MAX_NR_CPUS]; +struct counters cnt[MAX_NR_CPUS]; static void parse_arg(struct chaos_args *args, const char *arg) { @@ -58,6 +70,20 @@ static void parse_arg(struct chaos_args *args, const char *arg) } args->invtlb = i; printf("CPU %d: invtlb=%ld\n", smp_id(), i); + } else if (!strcmp(word, "hz")) { + if (!have_arg) + i = 1000; + args->hz = i; + printf("CPU %d: hz=%ld\n", smp_id(), i); + } else if (!strcmp(word, "hlt")) { + if (!have_arg) + i = 1; + else if (i != 0 && i != 1) { + printf("hlt argument must be 0 or 1\n"); + i = 1; + } + args->hlt = i; + printf("CPU %d: hlt=%ld\n", smp_id(), i); } else { printf("invalid argument %s\n", word); } @@ -65,6 +91,31 @@ static void parse_arg(struct chaos_args *args, const char *arg) free(s); } +static void do_timer(void) +{ + int cpu = smp_id(); + struct counters *c = &cnt[cpu]; + char out[4]; + if (c->ticks_left > 0) { + c->ticks_left--; + return; + } + + c->ticks_left = all_args[cpu].hz; + + /* Print current CPU number. */ + out[2] = (cpu % 10) + '0'; cpu /= 10; + out[1] = (cpu % 10) + '0'; cpu /= 10; + out[0] = (cpu % 10) + '0'; cpu /= 10; + puts(out + (ncpus < 100) + (ncpus < 10)); +} + +static void timer(isr_regs_t *regs) +{ + do_timer(); + eoi(); +} + static void __attribute__((noreturn)) stress(void *data) { const char *arg = data; @@ -73,6 +124,15 @@ static void __attribute__((noreturn)) stress(void *data) printf("starting CPU %d workload: %s\n", smp_id(), arg); parse_arg(args, arg); + apic_write(APIC_TDCR, 0x0000000b); + if (args->hz) { + /* FIXME: assumes that the LAPIC timer counts in nanoseconds. */ + + apic_write(APIC_TMICT, 1000000000 / args->hz); + apic_write(APIC_LVTT, TIMER_IRQ | APIC_LVT_TIMER_PERIODIC); + } + + irq_enable(); for (;;) { if (args->mem) { const char *s = args->mem; @@ -85,6 +145,8 @@ static void __attribute__((noreturn)) stress(void *data) s += sizeof(unsigned long); } } + if (args->hlt) + asm volatile("hlt"); } } @@ -103,6 +165,8 @@ int main(int argc, char *argv[]) if (ncpus > MAX_NR_CPUS) ncpus = MAX_NR_CPUS; + handle_irq(TIMER_IRQ, timer); + for (i = 1; i < ncpus; ++i) { if (i >= argc) { break; -- 2.29.2