Re: kvm: test: timer testcase

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

 



On 10/07/2009 09:02 PM, Marcelo Tosatti wrote:

Test timer interrupts (HPET, LAPIC, PIT) in correlation with
ACPI/TSC counters.

New tests/variations are easy to add.

Signed-off-by: Marcelo Tosatti<mtosatti@xxxxxxxxxx>

Index: qemu-kvm/kvm/user/config-x86-common.mak
===================================================================
--- qemu-kvm.orig/kvm/user/config-x86-common.mak
+++ qemu-kvm/kvm/user/config-x86-common.mak
@@ -58,6 +58,9 @@ $(TEST_DIR)/tsc.flat: $(cstart.o) $(TEST
  $(TEST_DIR)/apic.flat: $(cstart.o) $(TEST_DIR)/apic.o $(TEST_DIR)/vm.o \
  		       $(TEST_DIR)/print.o

+$(TEST_DIR)/time.flat: $(cstart.o) $(TEST_DIR)/time.o $(TEST_DIR)/vm.o \
+		       $(TEST_DIR)/print.o

Is print.o really needed?

===================================================================
--- /dev/null
+++ qemu-kvm/kvm/user/test/x86/io.h
@@ -0,0 +1,35 @@
+static inline void outb(unsigned char val, unsigned short port)
+{
+	asm volatile("outb %0, %w1": : "a"(val), "Nd" (port));
+}
+
+static inline void outw(unsigned short val, unsigned short port)
+{
+	asm volatile("outw %0, %w1": : "a"(val), "Nd" (port));
+}
+
+static inline void outl(unsigned long val, unsigned short port)
+{
+	asm volatile("outl %0, %w1": : "a"(val), "Nd" (port));
+}
+
+static inline unsigned char inb(unsigned short port)
+{
+	unsigned char val;
+	asm volatile("inb %w1, %0": "=a"(val) : "Nd" (port));
+	return val;
+}
+
+static inline short inw(unsigned short port)
+{
+	short val;
+	asm volatile("inw %w1, %0": "=a"(val) : "Nd" (port));
+	return val;
+}
+
+static inline unsigned int inl(unsigned short port)
+{
+	unsigned int val;
+	asm volatile("inl %w1, %0": "=a"(val) : "Nd" (port));
+	return val;
+}

Include guards.

Index: qemu-kvm/kvm/user/test/x86/time.c
===================================================================
--- /dev/null
+++ qemu-kvm/kvm/user/test/x86/time.c
@@ -0,0 +1,1010 @@
+#include "libcflat.h"
+#include "apic.h"
+#include "vm.h"
+#include "io.h"
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned u32;
+typedef unsigned long ulong;
+typedef unsigned long long u64;
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+typedef struct {
+    unsigned short offset0;
+    unsigned short selector;
+    unsigned short ist : 3;
+    unsigned short : 5;
+    unsigned short type : 4;
+    unsigned short : 1;
+    unsigned short dpl : 2;
+    unsigned short p : 1;
+    unsigned short offset1;
+#ifdef __x86_64__
+    unsigned offset2;
+    unsigned reserved;
+#endif
+} idt_entry_t;
+
+typedef struct {
+    ulong rflags;
+    ulong cs;
+    ulong rip;
+    ulong func;
+    ulong regs[sizeof(ulong)*2];
+} isr_regs_t;
+
+#ifdef __x86_64__
+#  define R "r"
+#else
+#  define R "e"
+#endif
+
+extern char isr_entry_point[];
+
+asm (
+    "isr_entry_point: \n"
+#ifdef __x86_64__
+    "push %r15 \n\t"
+    "push %r14 \n\t"
+    "push %r13 \n\t"
+    "push %r12 \n\t"
+    "push %r11 \n\t"
+    "push %r10 \n\t"
+    "push %r9  \n\t"
+    "push %r8  \n\t"
+#endif
+    "push %"R "di \n\t"
+    "push %"R "si \n\t"
+    "push %"R "bp \n\t"
+    "push %"R "sp \n\t"
+    "push %"R "bx \n\t"
+    "push %"R "dx \n\t"
+    "push %"R "cx \n\t"
+    "push %"R "ax \n\t"
+#ifdef __x86_64__
+    "mov %rsp, %rdi \n\t"
+    "callq *8*16(%rsp) \n\t"
+#else
+    "push %esp \n\t"
+    "calll *4+4*8(%esp) \n\t"
+    "add $4, %esp \n\t"
+#endif
+    "pop %"R "ax \n\t"
+    "pop %"R "cx \n\t"
+    "pop %"R "dx \n\t"
+    "pop %"R "bx \n\t"
+    "pop %"R "bp \n\t"
+    "pop %"R "bp \n\t"
+    "pop %"R "si \n\t"
+    "pop %"R "di \n\t"
+#ifdef __x86_64__
+    "pop %r8  \n\t"
+    "pop %r9  \n\t"
+    "pop %r10 \n\t"
+    "pop %r11 \n\t"
+    "pop %r12 \n\t"
+    "pop %r13 \n\t"
+    "pop %r14 \n\t"
+    "pop %r15 \n\t"
+#endif
+#ifdef __x86_64__
+    "add $8, %rsp \n\t"
+    "iretq \n\t"
+#else
+    "add $4, %esp \n\t"
+    "iretl \n\t"
+#endif
+    );
+
+static idt_entry_t idt[256];
+
+static int g_fail;
+static int g_tests;
+
+static void report(const char *msg, int pass)
+{
+    ++g_tests;
+    printf("%s: %s\n", msg, (pass ? "PASS" : "FAIL"));
+    if (!pass)
+        ++g_fail;
+}
+
+static u16 read_cs(void)
+{
+    u16 v;
+
+    asm("mov %%cs, %0" : "=rm"(v));
+    return v;
+}
+
+static void init_idt(void)
+{
+    struct {
+        u16 limit;
+        ulong idt;
+    } __attribute__((packed)) idt_ptr = {
+        sizeof(idt_entry_t) * 256 - 1,
+        (ulong)&idt,
+    };
+
+    asm volatile("lidt %0" : : "m"(idt_ptr));
+}
+
+static void set_idt_entry(unsigned vec, void (*func)(isr_regs_t *regs))
+{
+    u8 *thunk = vmalloc(50);
+    ulong ptr = (ulong)thunk;
+    idt_entry_t ent = {
+        .offset0 = ptr,
+        .selector = read_cs(),
+        .ist = 0,
+        .type = 14,
+        .dpl = 0,
+        .p = 1,
+        .offset1 = ptr>>  16,
+#ifdef __x86_64__
+        .offset2 = ptr>>  32,
+#endif
+    };
+#ifdef __x86_64__
+    /* sub $8, %rsp */
+    *thunk++ = 0x48; *thunk++ = 0x83; *thunk++ = 0xec; *thunk++ = 0x08;
+    /* mov $func_low, %(rsp) */
+    *thunk++ = 0xc7; *thunk++ = 0x04; *thunk++ = 0x24;
+    *(u32 *)thunk = (ulong)func; thunk += 4;
+    /* mov $func_high, %(rsp+4) */
+    *thunk++ = 0xc7; *thunk++ = 0x44; *thunk++ = 0x24; *thunk++ = 0x04;
+    *(u32 *)thunk = (ulong)func>>  32; thunk += 4;
+    /* jmp isr_entry_point */
+    *thunk ++ = 0xe9;
+    *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
+#else
+    /* push $func */
+    *thunk++ = 0x68;
+    *(u32 *)thunk = (ulong)func;
+    /* jmp isr_entry_point */
+    *thunk ++ = 0xe9;
+    *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
+#endif
+    idt[vec] = ent;
+}
+
+static void irq_disable(void)
+{
+    asm volatile("cli");
+}
+
+static void irq_enable(void)
+{
+    asm volatile("sti");
+}
+
+static void eoi(void)
+{
+    apic_write(APIC_EOI, 0);
+}
+
+static int ipi_count;
+
+static void self_ipi_isr(isr_regs_t *regs)
+{
+    ++ipi_count;
+    eoi();
+}
+
+static void test_self_ipi(void)
+{
+    int vec = 0xf1;
+
+    set_idt_entry(vec, self_ipi_isr);
+    irq_enable();
+    apic_write(APIC_ICR,
+               APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec);
+    asm volatile ("nop");
+    report("self ipi", ipi_count == 1);
+}
+

Needed?

+static void set_ioapic_redir(unsigned line, unsigned vec, unsigned trig_mode)
+{
+    ioapic_redir_entry_t e = {
+        .vector = vec,
+        .delivery_mode = 0,
+        .trig_mode = trig_mode,
+    };
+
+    ioapic_write_redir(line, e);
+}
+
+/* interrupt handlers */
+
+#define TIMER_VEC_BASE 0x90
+
+struct int_table {
+    void (*func)(isr_regs_t *regs);
+    void (*irq_handler)(void *irq_priv);
+    void *irq_priv;
+};
+
+static struct int_table int_handlers[];
+
+#define decl_irq_handler(N)                         \
+static void timer_int_##N(isr_regs_t *regs) {       \
+    struct int_table *t =&int_handlers[N];         \
+    t->irq_handler(t->irq_priv);                    \
+    eoi();                                          \
+}
+
+void set_irq_handler(int vec, void (*func)(void *irq_priv), void *irq_priv);
+
+void hlt(void) { asm volatile("hlt"); }
+
+#define NS_FREQ 1000000000ULL
+#define US_FREQ 1000000ULL
+
+#define ns2cyc(ns) (ns*cpu_hz)/NS_FREQ
+#define cyc2ns(cyc) (cyc*NS_FREQ)/cpu_hz
+
+#define us_to_ns(n) (1000*n)
+#define ms_to_ns(n) (1000000*n)
+#define s_to_ns(n)  (1000000000*n)
+
+#define sdelay(n) nsdelay(s_to_ns(n))
+
+u64 cpu_hz;
+
+static inline int fls(int x)
+{
+        int r;
+        asm("bsrl %1,%0\n\t"
+            "jnz 1f\n\t"
+            "movl $-1,%0\n"
+            "1:" : "=r" (r) : "rm" (x));
+        return r + 1;
+}
+
+# define do_div(n,base) ({                                      \
+        uint32_t __base = (base);                               \
+        uint32_t __rem;                                         \
+        __rem = ((uint64_t)(n)) % __base;                       \
+        (n) = ((uint64_t)(n)) / __base;                         \
+        __rem;                                                  \
+ })
+
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+        *remainder = dividend % divisor;
+        return dividend / divisor;
+}
+
+static inline u64 div_u64(u64 dividend, u32 divisor)
+{
+        u32 remainder;
+        return div_u64_rem(dividend, divisor,&remainder);
+}

What's wrong with / and %?

+/* 64bit divisor, dividend and result. dynamic precision */
+u64 div64_u64(u64 dividend, u64 divisor)
+{
+        u32 high, d;
+
+        high = divisor>>  32;
+        if (high) {
+                unsigned int shift = fls(high);
+
+                d = divisor>>  shift;
+                dividend>>= shift;
+        } else
+                d = divisor;
+
+        return div_u64(dividend, d);
+}

Ordinary 64-bit divides should work, no?


--
error compiling committee.c: too many arguments to function

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[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