#define VMX_BASIC_INOUT                0x0040000000000000LLU
 
 /* MSR_IA32_VMX_MISC bits */
+#define MSR_IA32_VMX_MISC_INTEL_PT                 (1ULL << 14)
 #define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29)
 #define MSR_IA32_VMX_MISC_PREEMPTION_TIMER_SCALE   0x1F
 /* AMD-V MSRs */
 
 #define SECONDARY_EXEC_ENCLS_EXITING           0x00008000
 #define SECONDARY_EXEC_RDSEED_EXITING          0x00010000
 #define SECONDARY_EXEC_ENABLE_PML               0x00020000
+#define SECONDARY_EXEC_PT_CONCEAL_VMX          0x00080000
 #define SECONDARY_EXEC_XSAVES                  0x00100000
+#define SECONDARY_EXEC_PT_USE_GPA              0x01000000
 #define SECONDARY_EXEC_MODE_BASED_EPT_EXEC     0x00400000
 #define SECONDARY_EXEC_TSC_SCALING              0x02000000
 
 #define VM_EXIT_LOAD_IA32_EFER                  0x00200000
 #define VM_EXIT_SAVE_VMX_PREEMPTION_TIMER       0x00400000
 #define VM_EXIT_CLEAR_BNDCFGS                   0x00800000
+#define VM_EXIT_PT_CONCEAL_PIP                 0x01000000
+#define VM_EXIT_CLEAR_IA32_RTIT_CTL            0x02000000
 
 #define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR      0x00036dff
 
 #define VM_ENTRY_LOAD_IA32_PAT                 0x00004000
 #define VM_ENTRY_LOAD_IA32_EFER                 0x00008000
 #define VM_ENTRY_LOAD_BNDCFGS                   0x00010000
+#define VM_ENTRY_PT_CONCEAL_PIP                        0x00020000
+#define VM_ENTRY_LOAD_IA32_RTIT_CTL            0x00040000
 
 #define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR     0x000011ff
 
        GUEST_PDPTR3_HIGH               = 0x00002811,
        GUEST_BNDCFGS                   = 0x00002812,
        GUEST_BNDCFGS_HIGH              = 0x00002813,
+       GUEST_IA32_RTIT_CTL             = 0x00002814,
+       GUEST_IA32_RTIT_CTL_HIGH        = 0x00002815,
        HOST_IA32_PAT                   = 0x00002c00,
        HOST_IA32_PAT_HIGH              = 0x00002c01,
        HOST_IA32_EFER                  = 0x00002c02,
 
 extern bool __read_mostly enable_unrestricted_guest;
 extern bool __read_mostly enable_ept_ad_bits;
 extern bool __read_mostly enable_pml;
+extern int __read_mostly pt_mode;
+
+#define PT_MODE_SYSTEM         0
+#define PT_MODE_HOST_GUEST     1
 
 struct nested_vmx_msrs {
        /*
        return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
 }
 
+static inline bool cpu_has_vmx_intel_pt(void)
+{
+       u64 vmx_msr;
+
+       rdmsrl(MSR_IA32_VMX_MISC, vmx_msr);
+       return (vmx_msr & MSR_IA32_VMX_MISC_INTEL_PT) &&
+               (vmcs_config.cpu_based_2nd_exec_ctrl & SECONDARY_EXEC_PT_USE_GPA) &&
+               (vmcs_config.vmexit_ctrl & VM_EXIT_CLEAR_IA32_RTIT_CTL) &&
+               (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_RTIT_CTL);
+}
+
 #endif /* __KVM_X86_VMX_CAPS_H */
 
 static unsigned int ple_window_max        = KVM_VMX_DEFAULT_PLE_WINDOW_MAX;
 module_param(ple_window_max, uint, 0444);
 
+/* Default is SYSTEM mode, 1 for host-guest mode */
+int __read_mostly pt_mode = PT_MODE_SYSTEM;
+module_param(pt_mode, int, S_IRUGO);
+
 static DEFINE_STATIC_KEY_FALSE(vmx_l1d_should_flush);
 static DEFINE_STATIC_KEY_FALSE(vmx_l1d_flush_cond);
 static DEFINE_MUTEX(vmx_l1d_flush_mutex);
                        SECONDARY_EXEC_RDRAND_EXITING |
                        SECONDARY_EXEC_ENABLE_PML |
                        SECONDARY_EXEC_TSC_SCALING |
+                       SECONDARY_EXEC_PT_USE_GPA |
+                       SECONDARY_EXEC_PT_CONCEAL_VMX |
                        SECONDARY_EXEC_ENABLE_VMFUNC |
                        SECONDARY_EXEC_ENCLS_EXITING;
                if (adjust_vmx_controls(min2, opt2,
              VM_EXIT_SAVE_IA32_PAT |
              VM_EXIT_LOAD_IA32_PAT |
              VM_EXIT_LOAD_IA32_EFER |
-             VM_EXIT_CLEAR_BNDCFGS;
+             VM_EXIT_CLEAR_BNDCFGS |
+             VM_EXIT_PT_CONCEAL_PIP |
+             VM_EXIT_CLEAR_IA32_RTIT_CTL;
        if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
                                &_vmexit_control) < 0)
                return -EIO;
        opt = VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL |
              VM_ENTRY_LOAD_IA32_PAT |
              VM_ENTRY_LOAD_IA32_EFER |
-             VM_ENTRY_LOAD_BNDCFGS;
+             VM_ENTRY_LOAD_BNDCFGS |
+             VM_ENTRY_PT_CONCEAL_PIP |
+             VM_ENTRY_LOAD_IA32_RTIT_CTL;
        if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS,
                                &_vmentry_control) < 0)
                return -EIO;
 
        u32 exec_control = vmcs_config.cpu_based_2nd_exec_ctrl;
 
+       if (pt_mode == PT_MODE_SYSTEM)
+               exec_control &= ~(SECONDARY_EXEC_PT_USE_GPA | SECONDARY_EXEC_PT_CONCEAL_VMX);
        if (!cpu_need_virtualize_apic_accesses(vcpu))
                exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
        if (vmx->vpid == 0)
 
        kvm_mce_cap_supported |= MCG_LMCE_P;
 
+       if (pt_mode != PT_MODE_SYSTEM && pt_mode != PT_MODE_HOST_GUEST)
+               return -EINVAL;
+       if (!enable_ept || !cpu_has_vmx_intel_pt())
+               pt_mode = PT_MODE_SYSTEM;
+
        if (nested) {
                nested_vmx_setup_ctls_msrs(&vmcs_config.nested,
                                           vmx_capability.ept, enable_apicv);
 
 #include <linux/kvm_host.h>
 
 #include <asm/kvm.h>
+#include <asm/intel_pt.h>
 
 #include "capabilities.h"
 #include "ops.h"
 
 static inline u32 vmx_vmentry_ctrl(void)
 {
+       u32 vmentry_ctrl = vmcs_config.vmentry_ctrl;
+       if (pt_mode == PT_MODE_SYSTEM)
+               vmentry_ctrl &= ~(VM_EXIT_PT_CONCEAL_PIP | VM_EXIT_CLEAR_IA32_RTIT_CTL);
        /* Loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically */
-       return vmcs_config.vmentry_ctrl &
+       return vmentry_ctrl &
                ~(VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | VM_ENTRY_LOAD_IA32_EFER);
 }
 
 static inline u32 vmx_vmexit_ctrl(void)
 {
+       u32 vmexit_ctrl = vmcs_config.vmexit_ctrl;
+       if (pt_mode == PT_MODE_SYSTEM)
+               vmexit_ctrl &= ~(VM_ENTRY_PT_CONCEAL_PIP | VM_ENTRY_LOAD_IA32_RTIT_CTL);
        /* Loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically */
        return vmcs_config.vmexit_ctrl &
                ~(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | VM_EXIT_LOAD_IA32_EFER);