From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=52810 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PCvtu-0003eJ-Ev for qemu-devel@nongnu.org; Mon, 01 Nov 2010 11:02:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PCvtX-0000hq-Gd for qemu-devel@nongnu.org; Mon, 01 Nov 2010 11:02:11 -0400 Received: from cantor2.suse.de ([195.135.220.15]:39338 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PCvtX-0000fy-3V for qemu-devel@nongnu.org; Mon, 01 Nov 2010 11:01:59 -0400 From: Alexander Graf Date: Mon, 1 Nov 2010 16:01:38 +0100 Message-Id: <1288623713-28062-26-git-send-email-agraf@suse.de> In-Reply-To: <1288623713-28062-1-git-send-email-agraf@suse.de> References: <1288623713-28062-1-git-send-email-agraf@suse.de> Subject: [Qemu-devel] [PATCH 25/40] xenner: kernel: KVM PV code List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel Developers Cc: Gerd Hoffmann Xenner uses KVM's PV functionality for timekeeping. If we don't find KVM clocksource support, we try to emulate it as good as we can. Signed-off-by: Alexander Graf --- pc-bios/xenner/xenner-pv.c | 186 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 186 insertions(+), 0 deletions(-) create mode 100644 pc-bios/xenner/xenner-pv.c diff --git a/pc-bios/xenner/xenner-pv.c b/pc-bios/xenner/xenner-pv.c new file mode 100644 index 0000000..98218a9 --- /dev/null +++ b/pc-bios/xenner/xenner-pv.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) Red Hat 2007 + * Copyright (C) Novell Inc. 2010 + * + * Author(s): Gerd Hoffmann + * Alexander Graf + * + * Xenner KVM PV integration + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "xenner.h" + +/* --------------------------------------------------------------------- */ + +const char *feature_bits[32] = { + [ KVM_FEATURE_CLOCKSOURCE ] = "clocksource", + [ KVM_FEATURE_NOP_IO_DELAY ] = "nop-iodelay", + [ KVM_FEATURE_MMU_OP ] = "mmu-op", +}; + +int pv_have_clock; + +/* --------------------------------------------------------------------- */ + +void pv_clock_update(int wakeup) +{ + static int wakeups; + static int update; + + if (wakeup) { + /* after halt() -- update clock unconditionally */ + update = 1; + wakeups++; + } else { + /* timer irq -- update only if needed */ + update = (0 == wakeups); + wakeups = 0; + } + + /* vmexit to userspace so xenner has a chance to update systime */ + if (update) { + if (pv_have_clock) { + emudev_cmd(EMUDEV_CMD_NOP, 0); + } else { + struct xen_cpu *cpu = get_cpu(); + + cpu->v.vcpu_info->time.tsc_timestamp = rdtsc(); + cpu->v.vcpu_info->time.system_time = + cpu->v.vcpu_info->time.tsc_timestamp; + + cpu->v.vcpu_info->time.version+=2; + cpu->v.vcpu_info->time.tsc_timestamp = rdtsc(); + cpu->v.vcpu_info->time.system_time = + cpu->v.vcpu_info->time.tsc_timestamp; + } + } +} + +static void pv_clock_wall(void) +{ + uint64_t wall = EMU_PA(&shared_info.wc_version); + + printk(1, "%s: register wall clock at 0x%" PRIx64 "\n", + __FUNCTION__, wall); + + if (pv_have_clock) { + if (wrmsrl_safe(MSR_KVM_WALL_CLOCK, wall)) { + panic("MSR_KVM_WALL_CLOCK wrmsr failed", NULL); + } + } else { + shared_info.wc_version = 4; + shared_info.wc_sec = 0; + shared_info.wc_nsec = 0; + } + + printk(1, "%s: v%d %d.%09d\n", __FUNCTION__, + shared_info.wc_version, + shared_info.wc_sec, + shared_info.wc_nsec); +} + +void pv_clock_sys(struct xen_cpu *cpu) +{ + uint64_t sys = cpu->v.vcpu_info_pa + offsetof(struct vcpu_info, time); + + printk(1, "%s: register vcpu %d clock at 0x%" PRIx64 "\n", + __FUNCTION__, cpu->id, sys); + + if (pv_have_clock) { + if (wrmsrl_safe(MSR_KVM_SYSTEM_TIME, sys | 1)) { + panic("MSR_KVM_SYSTEM_TIME wrmsr failed", NULL); + } + } else { + /* fake data */ + cpu->v.vcpu_info->time.tsc_to_system_mul = 1; + cpu->v.vcpu_info->time.version = 2; + cpu->v.vcpu_info->time.tsc_timestamp = rdtsc(); + cpu->v.vcpu_info->time.system_time = + cpu->v.vcpu_info->time.tsc_timestamp; + cpu->v.vcpu_info->time.tsc_shift = 0; + } + + printk(1, "%s: v%d sys %" PRIu64 " tsc %" PRIu64 " mul %u shift %d\n", + __FUNCTION__, + cpu->v.vcpu_info->time.version, + cpu->v.vcpu_info->time.system_time, + cpu->v.vcpu_info->time.tsc_timestamp, + cpu->v.vcpu_info->time.tsc_to_system_mul, + cpu->v.vcpu_info->time.tsc_shift); +} + +/* --------------------------------------------------------------------- */ + +void pv_write_cr3(struct xen_cpu *cpu, ureg_t cr3_mfn) +{ + ureg_t cr3 = frame_to_addr(cr3_mfn); + +#ifdef CONFIG_64BIT + if (cpu->user_mode) { + cpu->user_cr3_mfn = cr3_mfn; + } else { + cpu->kernel_cr3_mfn = cr3_mfn; + } +#else + cpu->cr3_mfn = cr3_mfn; +#endif + + vminfo.faults[XEN_FAULT_OTHER_CR3_LOAD]++; + write_cr3(cr3); + return; +} + +/* --------------------------------------------------------------------- */ + +void pv_init(struct xen_cpu *cpu) +{ + char buf[128]; + struct kvm_cpuid_entry entry; + uint32_t sig[3]; + uint32_t features; + + entry.function = KVM_CPUID_SIGNATURE; + real_cpuid(&entry); + sig[0] = entry.ebx; + sig[1] = entry.ecx; + sig[2] = entry.edx; + if (0 != memcmp((char*)sig, "KVMKVMKVM", 10)) { + printk(1, "%s: no kvm signature: \"%.12s\"\n", + __FUNCTION__, (char*)sig); + goto no_kvm; + } + + entry.function = KVM_CPUID_FEATURES; + real_cpuid(&entry); + features = entry.eax; + + snprintf(buf, sizeof(buf), "%s: cpu %d, signature \"%.12s\", features 0x%08x", + __FUNCTION__, cpu->id, (char*)sig, features); + print_bits(1, buf, features, features, feature_bits); + + /* pv clocksource */ + if (features & (1 << KVM_FEATURE_CLOCKSOURCE)) { + pv_have_clock = 1; + } + +no_kvm: + pv_clock_sys(cpu); + if (cpu->id == 0) { + pv_clock_wall(); + } +} + +/* --------------------------------------------------------------------- */ + -- 1.6.0.2