@@ -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;
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> --- x86/chaos.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 64 insertions(+)