qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: Sunil Muthuswamy <sunilmut@microsoft.com>
Subject: [PULL 07/61] WHPX: TSC get and set should be dependent on VM state
Date: Mon, 16 Mar 2020 22:26:34 +0100	[thread overview]
Message-ID: <1584394048-44994-8-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1584394048-44994-1-git-send-email-pbonzini@redhat.com>

From: Sunil Muthuswamy <sunilmut@microsoft.com>

Currently, TSC is set as part of the VM runtime state. Setting TSC at
runtime is heavy and additionally can have side effects on the guest,
which are not very resilient to variances in the TSC. This patch uses
the VM state to determine whether to set TSC or not. Some minor
enhancements for getting TSC values as well that considers the VM state.

Additionally, while setting the TSC, the partition is suspended to
reduce the variance in the TSC value across vCPUs.

Signed-off-by: Sunil Muthuswamy <sunilmut@microsoft.com>
Message-Id: <SN4PR2101MB08804D23439166E81FF151F7C0EA0@SN4PR2101MB0880.namprd21.prod.outlook.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/whpx.h      |   7 +++
 target/i386/whp-dispatch.h |   9 ++++
 target/i386/whpx-all.c     | 103 +++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 110 insertions(+), 9 deletions(-)

diff --git a/include/sysemu/whpx.h b/include/sysemu/whpx.h
index 4794e8e..a84b49e 100644
--- a/include/sysemu/whpx.h
+++ b/include/sysemu/whpx.h
@@ -35,4 +35,11 @@ int whpx_enabled(void);
 
 #endif /* CONFIG_WHPX */
 
+/* state subset only touched by the VCPU itself during runtime */
+#define WHPX_SET_RUNTIME_STATE   1
+/* state subset modified during VCPU reset */
+#define WHPX_SET_RESET_STATE     2
+/* full state set, modified during initialization or on vmload */
+#define WHPX_SET_FULL_STATE      3
+
 #endif /* QEMU_WHPX_H */
diff --git a/target/i386/whp-dispatch.h b/target/i386/whp-dispatch.h
index 87d049c..e4695c3 100644
--- a/target/i386/whp-dispatch.h
+++ b/target/i386/whp-dispatch.h
@@ -23,6 +23,12 @@
   X(HRESULT, WHvGetVirtualProcessorRegisters, (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, const WHV_REGISTER_NAME* RegisterNames, UINT32 RegisterCount, WHV_REGISTER_VALUE* RegisterValues)) \
   X(HRESULT, WHvSetVirtualProcessorRegisters, (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, const WHV_REGISTER_NAME* RegisterNames, UINT32 RegisterCount, const WHV_REGISTER_VALUE* RegisterValues)) \
 
+/*
+ * These are supplemental functions that may not be present
+ * on all versions and are not critical for basic functionality.
+ */
+#define LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(X) \
+  X(HRESULT, WHvSuspendPartitionTime, (WHV_PARTITION_HANDLE Partition)) \
 
 #define LIST_WINHVEMULATION_FUNCTIONS(X) \
   X(HRESULT, WHvEmulatorCreateEmulator, (const WHV_EMULATOR_CALLBACKS* Callbacks, WHV_EMULATOR_HANDLE* Emulator)) \
@@ -40,10 +46,12 @@
 /* Define function typedef */
 LIST_WINHVPLATFORM_FUNCTIONS(WHP_DEFINE_TYPE)
 LIST_WINHVEMULATION_FUNCTIONS(WHP_DEFINE_TYPE)
+LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_DEFINE_TYPE)
 
 struct WHPDispatch {
     LIST_WINHVPLATFORM_FUNCTIONS(WHP_DECLARE_MEMBER)
     LIST_WINHVEMULATION_FUNCTIONS(WHP_DECLARE_MEMBER)
+    LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_DECLARE_MEMBER)
 };
 
 extern struct WHPDispatch whp_dispatch;
@@ -53,6 +61,7 @@ bool init_whp_dispatch(void);
 typedef enum WHPFunctionList {
     WINHV_PLATFORM_FNS_DEFAULT,
     WINHV_EMULATION_FNS_DEFAULT,
+    WINHV_PLATFORM_FNS_SUPPLEMENTAL
 } WHPFunctionList;
 
 #endif /* WHP_DISPATCH_H */
diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c
index 683d49d..b947eb1 100644
--- a/target/i386/whpx-all.c
+++ b/target/i386/whpx-all.c
@@ -114,7 +114,6 @@ static const WHV_REGISTER_NAME whpx_register_names[] = {
     WHvX64RegisterXmmControlStatus,
 
     /* X64 MSRs */
-    WHvX64RegisterTsc,
     WHvX64RegisterEfer,
 #ifdef TARGET_X86_64
     WHvX64RegisterKernelGsBase,
@@ -215,7 +214,44 @@ static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs)
     return qs;
 }
 
-static void whpx_set_registers(CPUState *cpu)
+static int whpx_set_tsc(CPUState *cpu)
+{
+    struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
+    WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc;
+    WHV_REGISTER_VALUE tsc_val;
+    HRESULT hr;
+    struct whpx_state *whpx = &whpx_global;
+
+    /*
+     * Suspend the partition prior to setting the TSC to reduce the variance
+     * in TSC across vCPUs. When the first vCPU runs post suspend, the
+     * partition is automatically resumed.
+     */
+    if (whp_dispatch.WHvSuspendPartitionTime) {
+
+        /*
+         * Unable to suspend partition while setting TSC is not a fatal
+         * error. It just increases the likelihood of TSC variance between
+         * vCPUs and some guest OS are able to handle that just fine.
+         */
+        hr = whp_dispatch.WHvSuspendPartitionTime(whpx->partition);
+        if (FAILED(hr)) {
+            warn_report("WHPX: Failed to suspend partition, hr=%08lx", hr);
+        }
+    }
+
+    tsc_val.Reg64 = env->tsc;
+    hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+        whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val);
+    if (FAILED(hr)) {
+        error_report("WHPX: Failed to set TSC, hr=%08lx", hr);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void whpx_set_registers(CPUState *cpu, int level)
 {
     struct whpx_state *whpx = &whpx_global;
     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
@@ -230,6 +266,14 @@ static void whpx_set_registers(CPUState *cpu)
 
     assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
 
+    /*
+     * Following MSRs have side effects on the guest or are too heavy for
+     * runtime. Limit them to full state update.
+     */
+    if (level >= WHPX_SET_RESET_STATE) {
+        whpx_set_tsc(cpu);
+    }
+
     memset(&vcxt, 0, sizeof(struct whpx_register_set));
 
     v86 = (env->eflags & VM_MASK);
@@ -330,8 +374,6 @@ static void whpx_set_registers(CPUState *cpu)
     idx += 1;
 
     /* MSRs */
-    assert(whpx_register_names[idx] == WHvX64RegisterTsc);
-    vcxt.values[idx++].Reg64 = env->tsc;
     assert(whpx_register_names[idx] == WHvX64RegisterEfer);
     vcxt.values[idx++].Reg64 = env->efer;
 #ifdef TARGET_X86_64
@@ -379,6 +421,25 @@ static void whpx_set_registers(CPUState *cpu)
     return;
 }
 
+static int whpx_get_tsc(CPUState *cpu)
+{
+    struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
+    WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc;
+    WHV_REGISTER_VALUE tsc_val;
+    HRESULT hr;
+    struct whpx_state *whpx = &whpx_global;
+
+    hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
+        whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val);
+    if (FAILED(hr)) {
+        error_report("WHPX: Failed to get TSC, hr=%08lx", hr);
+        return -1;
+    }
+
+    env->tsc = tsc_val.Reg64;
+    return 0;
+}
+
 static void whpx_get_registers(CPUState *cpu)
 {
     struct whpx_state *whpx = &whpx_global;
@@ -394,6 +455,11 @@ static void whpx_get_registers(CPUState *cpu)
 
     assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
 
+    if (!env->tsc_valid) {
+        whpx_get_tsc(cpu);
+        env->tsc_valid = !runstate_is_running();
+    }
+
     hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
         whpx->partition, cpu->cpu_index,
         whpx_register_names,
@@ -492,8 +558,6 @@ static void whpx_get_registers(CPUState *cpu)
     idx += 1;
 
     /* MSRs */
-    assert(whpx_register_names[idx] == WHvX64RegisterTsc);
-    env->tsc = vcxt.values[idx++].Reg64;
     assert(whpx_register_names[idx] == WHvX64RegisterEfer);
     env->efer = vcxt.values[idx++].Reg64;
 #ifdef TARGET_X86_64
@@ -896,7 +960,7 @@ static int whpx_vcpu_run(CPUState *cpu)
 
     do {
         if (cpu->vcpu_dirty) {
-            whpx_set_registers(cpu);
+            whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);
             cpu->vcpu_dirty = false;
         }
 
@@ -1074,14 +1138,14 @@ static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,
                                                run_on_cpu_data arg)
 {
-    whpx_set_registers(cpu);
+    whpx_set_registers(cpu, WHPX_SET_RESET_STATE);
     cpu->vcpu_dirty = false;
 }
 
 static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
                                               run_on_cpu_data arg)
 {
-    whpx_set_registers(cpu);
+    whpx_set_registers(cpu, WHPX_SET_FULL_STATE);
     cpu->vcpu_dirty = false;
 }
 
@@ -1123,6 +1187,15 @@ void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
 
 static Error *whpx_migration_blocker;
 
+static void whpx_cpu_update_state(void *opaque, int running, RunState state)
+{
+    CPUX86State *env = opaque;
+
+    if (running) {
+        env->tsc_valid = false;
+    }
+}
+
 int whpx_init_vcpu(CPUState *cpu)
 {
     HRESULT hr;
@@ -1178,6 +1251,7 @@ int whpx_init_vcpu(CPUState *cpu)
 
     cpu->vcpu_dirty = true;
     cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu;
+    qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr);
 
     return 0;
 }
@@ -1367,6 +1441,10 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
 
     #define WINHV_PLATFORM_DLL "WinHvPlatform.dll"
     #define WINHV_EMULATION_DLL "WinHvEmulation.dll"
+    #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \
+        whp_dispatch.function_name = \
+            (function_name ## _t)GetProcAddress(hLib, #function_name); \
+
     #define WHP_LOAD_FIELD(return_type, function_name, signature) \
         whp_dispatch.function_name = \
             (function_name ## _t)GetProcAddress(hLib, #function_name); \
@@ -1394,6 +1472,11 @@ static bool load_whp_dispatch_fns(HMODULE *handle,
         WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
         LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
         break;
+
+    case WINHV_PLATFORM_FNS_SUPPLEMENTAL:
+        WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
+        LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL)
+        break;
     }
 
     *handle = hLib;
@@ -1554,6 +1637,8 @@ bool init_whp_dispatch(void)
         goto error;
     }
 
+    assert(load_whp_dispatch_fns(&hWinHvPlatform,
+        WINHV_PLATFORM_FNS_SUPPLEMENTAL));
     whp_dispatch_initialized = true;
 
     return true;
-- 
1.8.3.1




  parent reply	other threads:[~2020-03-16 21:37 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-16 21:26 [PULL 00/61] Misc patches for soft freeze Paolo Bonzini
2020-03-16 21:26 ` [PULL 01/61] scsi/qemu-pr-helper: Fix out-of-bounds access to trnptid_list[] Paolo Bonzini
2020-03-16 21:26 ` [PULL 02/61] optionrom/pvh: scan entire RSDP Area Paolo Bonzini
2020-03-16 21:26 ` [PULL 03/61] misc: Replace zero-length arrays with flexible array member (automatic) Paolo Bonzini
2020-03-16 21:26 ` [PULL 04/61] misc: Replace zero-length arrays with flexible array member (manual) Paolo Bonzini
2020-03-16 21:26 ` [PULL 05/61] configure: add configure option avx512f_opt Paolo Bonzini
2020-03-16 21:26 ` [PULL 06/61] util: add util function buffer_zero_avx512() Paolo Bonzini
2020-03-16 22:02   ` Paolo Bonzini
2020-03-16 21:26 ` Paolo Bonzini [this message]
2020-03-16 21:26 ` [PULL 08/61] WHPX: Use QEMU values for trapped CPUID Paolo Bonzini
2020-03-16 21:26 ` [PULL 09/61] MAINTAINERS: Add entry for Guest X86 HAXM CPUs Paolo Bonzini
2020-03-17  7:46   ` Colin Xu
2020-03-17  8:26     ` Paolo Bonzini
2020-03-17  8:55       ` Colin Xu
2020-03-17 10:27         ` Paolo Bonzini
2020-03-18  0:23           ` Colin Xu
2020-03-16 21:26 ` [PULL 10/61] hw/i386/intel_iommu: Fix out-of-bounds access on guest IRT Paolo Bonzini
2020-03-16 21:26 ` [PULL 11/61] oslib-posix: initialize mutex and condition variable Paolo Bonzini
2020-03-16 21:26 ` [PULL 12/61] build-sys: do not make qemu-ga link with pixman Paolo Bonzini
2020-03-16 21:26 ` [PULL 13/61] modules: load modules from versioned /var/run dir Paolo Bonzini
2020-03-16 21:26 ` [PULL 14/61] configure: Fix building with SASL on Windows Paolo Bonzini
2020-03-16 21:26 ` [PULL 15/61] tests/docker: Install SASL library to extend code coverage on amd64 Paolo Bonzini
2020-03-16 21:26 ` [PULL 16/61] memory: Fix start offset for bitmap log_clear hook Paolo Bonzini
2020-03-16 21:26 ` [PULL 17/61] qom/object: enable setter for uint types Paolo Bonzini
2020-03-16 21:26 ` [PULL 18/61] ich9: fix getter type for sci_int property Paolo Bonzini
2020-03-16 21:26 ` [PULL 19/61] ich9: Simplify ich9_lpc_initfn Paolo Bonzini
2020-03-16 21:26 ` [PULL 20/61] qom/object: Use common get/set uint helpers Paolo Bonzini
2020-03-16 21:26 ` [PULL 21/61] i386: Fix GCC warning with snprintf when HAX is enabled Paolo Bonzini
2020-03-16 21:26 ` [PULL 22/61] WHPX: Use proper synchronization primitives while processing Paolo Bonzini
2020-03-16 21:26 ` [PULL 23/61] Makefile: Align 'help' target output Paolo Bonzini
2020-03-16 21:26 ` [PULL 24/61] Makefile: Let the 'help' target list the tools targets Paolo Bonzini
2020-03-16 21:26 ` [PULL 25/61] hw/audio/fmopl: Move ENV_CURVE to .heap to save 32KiB of .bss Paolo Bonzini
2020-03-16 21:26 ` [PULL 26/61] hw/audio/intel-hda: Use memory region alias to reduce .rodata by 4.34MB Paolo Bonzini
2020-03-16 21:26 ` [PULL 27/61] hw/usb/quirks: Use smaller types to reduce .rodata by 10KiB Paolo Bonzini
2020-03-16 21:26 ` [PULL 28/61] ui/curses: Make control_characters[] array const Paolo Bonzini
2020-03-16 21:26 ` [PULL 29/61] ui/curses: Move arrays to .heap to save 74KiB of .bss Paolo Bonzini
2020-03-16 21:26 ` [PULL 30/61] qemu-cpu-models.rst: Document -noTSX, mds-no, taa-no, and tsx-ctrl Paolo Bonzini
2020-03-16 21:26 ` [PULL 31/61] softmmu/vl.c: Handle '-cpu help' and '-device help' before 'no default machine' Paolo Bonzini
2020-03-16 21:26 ` [PULL 32/61] Use -isystem for linux-headers dir Paolo Bonzini
2020-03-16 21:27 ` [PULL 33/61] exec/rom_reset: Free rom data during inmigrate skip Paolo Bonzini
2020-03-16 21:27 ` [PULL 34/61] cpus: avoid pause_all_vcpus getting stuck due to race Paolo Bonzini
2020-03-16 21:27 ` [PULL 35/61] lockable: add lock guards Paolo Bonzini
2020-03-16 21:27 ` [PULL 36/61] lockable: add QemuRecMutex support Paolo Bonzini
2020-03-16 21:27 ` [PULL 37/61] memory: Correctly return alias region type Paolo Bonzini
2020-03-16 21:27 ` [PULL 38/61] memory: Simplify memory_region_init_rom_nomigrate() to ease review Paolo Bonzini
2020-03-16 21:27 ` [PULL 39/61] scripts/cocci: Rename memory-region-{init-ram -> housekeeping} Paolo Bonzini
2020-03-16 21:27 ` [PULL 40/61] scripts/cocci: Patch to replace memory_region_init_{ram, readonly -> rom} Paolo Bonzini
2020-03-16 21:27 ` [PULL 41/61] hw/arm: Use memory_region_init_rom() with read-only regions Paolo Bonzini
2020-03-16 21:27 ` [PULL 42/61] hw/display: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 43/61] hw/m68k: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 44/61] hw/net: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 45/61] hw/pci-host: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 46/61] hw/ppc: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 47/61] hw/riscv: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 48/61] hw/sh4: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 49/61] hw/sparc: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 50/61] scripts/cocci: Patch to detect potential use of memory_region_init_rom Paolo Bonzini
2020-03-16 21:27 ` [PULL 51/61] scripts/cocci: Patch to remove unnecessary memory_region_set_readonly() Paolo Bonzini
2020-03-16 21:27 ` [PULL 52/61] scripts/cocci: Patch to let devices own their MemoryRegions Paolo Bonzini
2020-03-16 21:27 ` [PULL 53/61] hw/core: Let devices own the MemoryRegion they create Paolo Bonzini
2020-03-16 21:27 ` [PULL 54/61] hw/display: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 55/61] hw/dma: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 56/61] hw/riscv: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 57/61] hw/char: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 58/61] hw/arm/stm32: Use memory_region_init_rom() with read-only regions Paolo Bonzini
2020-03-16 21:27 ` [PULL 59/61] hw/ppc/ppc405: " Paolo Bonzini
2020-03-16 21:27 ` [PULL 60/61] hw/arm: Remove unnecessary memory_region_set_readonly() on ROM alias Paolo Bonzini
2020-03-16 21:27 ` [PULL 61/61] hw/arm: Let devices own the MemoryRegion they create Paolo Bonzini
2020-03-16 23:58 ` [PULL 00/61] Misc patches for soft freeze no-reply
2020-03-17  0:27 ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1584394048-44994-8-git-send-email-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=sunilmut@microsoft.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).