From mboxrd@z Thu Jan 1 00:00:00 1970 From: Avi Kivity Subject: Re: kvm: test: timer testcase Date: Thu, 08 Oct 2009 14:37:29 +0200 Message-ID: <4ACDDD09.6080302@redhat.com> References: <20091007190201.GA6418@amt.cnet> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: kvm@vger.kernel.org, Zachary Amsden To: Marcelo Tosatti Return-path: Received: from mx1.redhat.com ([209.132.183.28]:62980 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757701AbZJHMh6 (ORCPT ); Thu, 8 Oct 2009 08:37:58 -0400 Received: from int-mx04.intmail.prod.int.phx2.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.17]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id n98CbW1U019258 for ; Thu, 8 Oct 2009 08:37:32 -0400 In-Reply-To: <20091007190201.GA6418@amt.cnet> Sender: kvm-owner@vger.kernel.org List-ID: 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 > > 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