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<mtosa...@redhat.com> 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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html