aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-08-27 11:25:34 +0100
committerKeir Fraser <keir.fraser@citrix.com>2009-08-27 11:25:34 +0100
commitd4fc7ea04de2d81f78a03ff7ae0fb5ee27dd6d49 (patch)
treed0d6b1d69d3a41e094639016f55b9bb03b6b6f42
parentfbed278604f69ea801dcea2d05df9ace1156a55d (diff)
downloadxen-d4fc7ea04de2d81f78a03ff7ae0fb5ee27dd6d49.tar.gz
xen-d4fc7ea04de2d81f78a03ff7ae0fb5ee27dd6d49.tar.bz2
xen-d4fc7ea04de2d81f78a03ff7ae0fb5ee27dd6d49.zip
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@oracle.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
-rw-r--r--xen/arch/x86/domain.c6
-rw-r--r--xen/arch/x86/hvm/hvm.c3
-rw-r--r--xen/arch/x86/time.c55
-rw-r--r--xen/arch/x86/traps.c16
-rw-r--r--xen/include/asm-x86/domain.h15
-rw-r--r--xen/include/asm-x86/hvm/support.h1
-rw-r--r--xen/include/asm-x86/time.h3
7 files changed, 84 insertions, 15 deletions
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index d0eaba2f8f..94819a675e 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -516,6 +516,10 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags)
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(struct vcpu *v)
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 --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 15d2e32da5..923987214c 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -61,9 +61,6 @@ int hvm_enabled __read_mostly;
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 --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 8fc2a4836b..0fb2aaa29f 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -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>
@@ -35,6 +36,9 @@
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
* simplified system time handling.
@@ -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 --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 61e3407f0e..6feb8ccdbd 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -2005,12 +2005,15 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
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 cpu_user_regs *regs)
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 cpu_user_regs *regs)
}
case 0x31: /* RDTSC */
- rdtsc(regs->eax, regs->edx);
+ pv_soft_rdtsc(v, regs);
break;
case 0x32: /* RDMSR */
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 8e6f0aba57..cf65772ebb 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -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 @@ void vcpu_show_registers(const struct vcpu *);
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 --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h
index e533f1bee8..cfacb04e4e 100644
--- a/xen/include/asm-x86/hvm/support.h
+++ b/xen/include/asm-x86/hvm/support.h
@@ -126,7 +126,6 @@ int hvm_do_hypercall(struct cpu_user_regs *pregs);
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 --git a/xen/include/asm-x86/time.h b/xen/include/asm-x86/time.h
index 1d687a8060..ec06313f95 100644
--- a/xen/include/asm-x86/time.h
+++ b/xen/include/asm-x86/time.h
@@ -41,4 +41,7 @@ int pit_broadcast_is_available(void);
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__ */