# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1251368734 -3600
# Node ID e8004f6c254a5778b50babd527e74208981640b9
# Parent b63b1db5b388ef92bc1ecd709ddb0d357cf2d6b7
x86: softtsc for PV domains
Implement softtsc (TSC emulation) for userland code in PV domains. It
currently is tied to the existing "softtsc" Xen boot option (which
does the same thing but for HVM domains). Later it should be tied to
a vm.cfg option, but this is sufficient for now to obtain performance
degradation data for PV environments that heavily utilize rdtsc. To
record emulation frequency, use debug-key "s".
Signed-off-by: Dan Magenheimer <dan.magenheimer@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/domain.c | 6 +++-
xen/arch/x86/hvm/hvm.c | 3 --
xen/arch/x86/time.c | 55 ++++++++++++++++++++++++++++++++++++++
xen/arch/x86/traps.c | 16 ++++++-----
xen/include/asm-x86/domain.h | 15 ++++++++--
xen/include/asm-x86/hvm/support.h | 1
xen/include/asm-x86/time.h | 3 ++
7 files changed, 84 insertions(+), 15 deletions(-)
diff -r b63b1db5b388 -r e8004f6c254a xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Thu Aug 27 10:13:13 2009 +0100
+++ b/xen/arch/x86/domain.c Thu Aug 27 11:25:34 2009 +0100
@@ -516,6 +516,10 @@ int arch_domain_create(struct domain *d,
d->arch.cpuids[i].input[1] = XEN_CPUID_INPUT_UNUSED;
}
+ /* For now, per-domain SoftTSC status is taken from global boot param. */
+ d->arch.vtsc = opt_softtsc;
+ spin_lock_init(&d->arch.vtsc_lock);
+
return 0;
fail:
@@ -1259,7 +1263,7 @@ static void paravirt_ctxt_switch_to(stru
set_int80_direct_trap(v);
switch_kernel_stack(v);
- cr4 = pv_guest_cr4_to_real_cr4(v->arch.guest_context.ctrlreg[4]);
+ cr4 = pv_guest_cr4_to_real_cr4(v);
if ( unlikely(cr4 != read_cr4()) )
write_cr4(cr4);
diff -r b63b1db5b388 -r e8004f6c254a xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Thu Aug 27 10:13:13 2009 +0100
+++ b/xen/arch/x86/hvm/hvm.c Thu Aug 27 11:25:34 2009 +0100
@@ -61,9 +61,6 @@ unsigned int opt_hvm_debug_level __read_
unsigned int opt_hvm_debug_level __read_mostly;
integer_param("hvm_debug", opt_hvm_debug_level);
-int opt_softtsc;
-boolean_param("softtsc", opt_softtsc);
-
struct hvm_function_table hvm_funcs __read_mostly;
/* I/O permission bitmap is globally shared by all HVM guests. */
diff -r b63b1db5b388 -r e8004f6c254a xen/arch/x86/time.c
--- a/xen/arch/x86/time.c Thu Aug 27 10:13:13 2009 +0100
+++ b/xen/arch/x86/time.c Thu Aug 27 11:25:34 2009 +0100
@@ -21,6 +21,7 @@
#include <xen/smp.h>
#include <xen/irq.h>
#include <xen/softirq.h>
+#include <xen/keyhandler.h>
#include <asm/io.h>
#include <asm/msr.h>
#include <asm/mpspec.h>
@@ -34,6 +35,9 @@
/* opt_clocksource: Force clocksource to one of: pit, hpet, cyclone, acpi. */
static char opt_clocksource[10];
string_param("clocksource", opt_clocksource);
+
+int opt_softtsc;
+boolean_param("softtsc", opt_softtsc);
/*
* opt_consistent_tscs: All TSCs tick at the exact same rate, allowing
@@ -1429,6 +1433,57 @@ struct tm wallclock_time(void)
return gmtime(seconds);
}
+
+/*
+ * PV SoftTSC Emulation.
+ */
+
+static unsigned long rdtsc_kerncount, rdtsc_usercount;
+
+void pv_soft_rdtsc(struct vcpu *v, struct cpu_user_regs *regs)
+{
+ s_time_t now;
+
+ if ( guest_kernel_mode(v, regs) )
+ {
+ rdtsc_kerncount++;
+ rdtsc(regs->eax, regs->edx);
+ }
+ else
+ {
+ rdtsc_usercount++;
+ spin_lock(&v->domain->arch.vtsc_lock);
+ now = get_s_time() + v->domain->arch.vtsc_stime_offset;
+ if ( (int64_t)(now - v->domain->arch.vtsc_last) >= 0 )
+ v->domain->arch.vtsc_last = now;
+ else
+ now = v->domain->arch.vtsc_last;
+ spin_unlock(&v->domain->arch.vtsc_lock);
+ regs->eax = (uint32_t)now;
+ regs->edx = (uint32_t)(now >> 32);
+ }
+}
+
+static void dump_softtsc(unsigned char key)
+{
+ printk("softtsc count: %lu kernel, %lu user\n",
+ rdtsc_kerncount, rdtsc_usercount);
+}
+
+static struct keyhandler dump_softtsc_keyhandler = {
+ .diagnostic = 1,
+ .u.fn = dump_softtsc,
+ .desc = "dump softtsc stats"
+};
+
+static int __init setup_dump_softtsc(void)
+{
+ if ( opt_softtsc )
+ register_keyhandler('s', &dump_softtsc_keyhandler);
+ return 0;
+}
+__initcall(setup_dump_softtsc);
+
/*
* Local variables:
* mode: C
diff -r b63b1db5b388 -r e8004f6c254a xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Thu Aug 27 10:13:13 2009 +0100
+++ b/xen/arch/x86/traps.c Thu Aug 27 11:25:34 2009 +0100
@@ -2005,12 +2005,15 @@ static int emulate_privileged_op(struct
goto fail;
twobyte_opcode:
- /* Two-byte opcodes only emulated from guest kernel. */
- if ( !guest_kernel_mode(v, regs) )
+ /*
+ * All two-byte opcodes, except RDTSC (0x31) are executable only from
+ * guest kernel mode (virtual ring 0).
+ */
+ opcode = insn_fetch(u8, code_base, eip, code_limit);
+ if ( !guest_kernel_mode(v, regs) &&
+ !((opcode == 0x31) && v->domain->arch.vtsc) )
goto fail;
- /* Privileged (ring 0) instructions. */
- opcode = insn_fetch(u8, code_base, eip, code_limit);
if ( lock && (opcode & ~3) != 0x20 )
goto fail;
switch ( opcode )
@@ -2127,8 +2130,7 @@ static int emulate_privileged_op(struct
case 4: /* Write CR4 */
v->arch.guest_context.ctrlreg[4] = pv_guest_cr4_fixup(*reg);
- write_cr4(pv_guest_cr4_to_real_cr4(
- v->arch.guest_context.ctrlreg[4]));
+ write_cr4(pv_guest_cr4_to_real_cr4(v));
break;
default:
@@ -2266,7 +2268,7 @@ static int emulate_privileged_op(struct
}
case 0x31: /* RDTSC */
- rdtsc(regs->eax, regs->edx);
+ pv_soft_rdtsc(v, regs);
break;
case 0x32: /* RDMSR */
diff -r b63b1db5b388 -r e8004f6c254a xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h Thu Aug 27 10:13:13 2009 +0100
+++ b/xen/include/asm-x86/domain.h Thu Aug 27 11:25:34 2009 +0100
@@ -299,6 +299,12 @@ struct arch_domain
/* For Guest vMCA handling */
struct domain_mca_msrs vmca_msrs;
+
+ /* SoftTSC emulation */
+ bool_t vtsc;
+ s_time_t vtsc_last;
+ spinlock_t vtsc_lock;
+ int64_t vtsc_stime_offset;
} __cacheline_aligned;
#define has_arch_pdevs(d) (!list_empty(&(d)->arch.pdev_list))
@@ -426,10 +432,13 @@ unsigned long pv_guest_cr4_fixup(unsigne
unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4);
/* Convert between guest-visible and real CR4 values. */
-#define pv_guest_cr4_to_real_cr4(c) \
- (((c) | (mmu_cr4_features & (X86_CR4_PGE | X86_CR4_PSE))) & ~X86_CR4_DE)
+#define pv_guest_cr4_to_real_cr4(v) \
+ (((v)->arch.guest_context.ctrlreg[4] \
+ | (mmu_cr4_features & (X86_CR4_PGE | X86_CR4_PSE)) \
+ | ((v)->domain->arch.vtsc ? X86_CR4_TSD : 0)) \
+ & ~X86_CR4_DE)
#define real_cr4_to_pv_guest_cr4(c) \
- ((c) & ~(X86_CR4_PGE | X86_CR4_PSE))
+ ((c) & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_TSD))
void domain_cpuid(struct domain *d,
unsigned int input,
diff -r b63b1db5b388 -r e8004f6c254a xen/include/asm-x86/hvm/support.h
--- a/xen/include/asm-x86/hvm/support.h Thu Aug 27 10:13:13 2009 +0100
+++ b/xen/include/asm-x86/hvm/support.h Thu Aug 27 11:25:34 2009 +0100
@@ -126,7 +126,6 @@ void hvm_hlt(unsigned long rflags);
void hvm_hlt(unsigned long rflags);
void hvm_triple_fault(void);
-extern int opt_softtsc;
void hvm_rdtsc_intercept(struct cpu_user_regs *regs);
/* These functions all return X86EMUL return codes. */
diff -r b63b1db5b388 -r e8004f6c254a xen/include/asm-x86/time.h
--- a/xen/include/asm-x86/time.h Thu Aug 27 10:13:13 2009 +0100
+++ b/xen/include/asm-x86/time.h Thu Aug 27 11:25:34 2009 +0100
@@ -41,4 +41,7 @@ uint64_t acpi_pm_tick_to_ns(uint64_t tic
uint64_t acpi_pm_tick_to_ns(uint64_t ticks);
uint64_t ns_to_acpi_pm_tick(uint64_t ns);
+extern int opt_softtsc;
+void pv_soft_rdtsc(struct vcpu *v, struct cpu_user_regs *regs);
+
#endif /* __X86_TIME_H__ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|