From: Grygorii Strashko <grygorii_strashko@epam.com>
To: "xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>
Cc: "Grygorii Strashko" <grygorii_strashko@epam.com>,
"Jan Beulich" <jbeulich@suse.com>,
"Andrew Cooper" <andrew.cooper3@citrix.com>,
"Roger Pau Monné" <roger.pau@citrix.com>,
"Anthony PERARD" <anthony.perard@vates.tech>,
"Michal Orzel" <michal.orzel@amd.com>,
"Julien Grall" <julien@xen.org>,
"Stefano Stabellini" <sstabellini@kernel.org>,
"Tamas K Lengyel" <tamas@tklengyel.com>,
"Alexandru Isaila" <aisaila@bitdefender.com>,
"Petre Pircalabu" <ppircalabu@bitdefender.com>,
"Teddy Astie" <teddy.astie@vates.tech>,
"Penny Zheng" <Penny.Zheng@amd.com>
Subject: [XEN][PATCH v3] xen: make VMTRACE support optional
Date: Fri, 14 Nov 2025 14:22:08 +0000 [thread overview]
Message-ID: <20251114142207.279834-1-grygorii_strashko@epam.com> (raw)
From: Grygorii Strashko <grygorii_strashko@epam.com>
The VMTRACE feature is depends on Platform/Arch HW and code support and now
can be used only on x86 HVM with Intel VT-x (INTEL_VMX) enabled.
This makes VMTRACE support optional by introducing HVM Kconfig option:
- CONFIG_VMTRACE to enable/disable the feature.
Signed-off-by: Grygorii Strashko <grygorii_strashko@epam.com>
---
changes in v3:
- drop vmtrace stubs for HVM=n case from hvm.h (VMTRACE depnds on HVM)
- hvm_vmtrace_reset() fix return err code
- add comment about using func declaration without definition
changes in v2:
- fix comments from Jan Beulich
- move CONFIG_VMTRACE in HVM
- drop HAS_VMTRACE
v2:
https://patchwork.kernel.org/project/xen-devel/patch/20251112202442.3879997-1-grygorii_strashko@epam.com/
v1:
https://patchwork.kernel.org/project/xen-devel/patch/20251031212005.1338212-1-grygorii_strashko@epam.com/
xen/arch/x86/domctl.c | 4 +++
xen/arch/x86/hvm/Kconfig | 12 +++++++++
xen/arch/x86/hvm/vmx/vmcs.c | 2 ++
xen/arch/x86/hvm/vmx/vmx.c | 11 ++++++++
xen/arch/x86/include/asm/guest-msr.h | 2 ++
xen/arch/x86/include/asm/hvm/hvm.h | 36 ++++++++++---------------
xen/arch/x86/include/asm/hvm/vmx/vmcs.h | 2 ++
xen/arch/x86/mm/mem_sharing.c | 2 ++
xen/arch/x86/vm_event.c | 7 ++---
xen/common/domain.c | 10 +++++++
xen/common/memory.c | 6 +++++
xen/common/vm_event.c | 3 ++-
xen/include/xen/domain.h | 4 +++
xen/include/xen/sched.h | 4 +++
14 files changed, 79 insertions(+), 26 deletions(-)
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 6153e3c07e2d..d9521808dcba 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -154,6 +154,7 @@ void arch_get_domain_info(const struct domain *d,
static int do_vmtrace_op(struct domain *d, struct xen_domctl_vmtrace_op *op,
XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
{
+#ifdef CONFIG_VMTRACE
struct vcpu *v;
int rc;
@@ -198,6 +199,9 @@ static int do_vmtrace_op(struct domain *d, struct xen_domctl_vmtrace_op *op,
vcpu_unpause(v);
return rc;
+#else
+ return -EOPNOTSUPP;
+#endif
}
#define MAX_IOPORTS 0x10000
diff --git a/xen/arch/x86/hvm/Kconfig b/xen/arch/x86/hvm/Kconfig
index c1a131d1851a..5c47a45c9350 100644
--- a/xen/arch/x86/hvm/Kconfig
+++ b/xen/arch/x86/hvm/Kconfig
@@ -35,6 +35,18 @@ config INTEL_VMX
If your system includes a processor with Intel VT-x support, say Y.
If in doubt, say Y.
+config VMTRACE
+ bool "HW VM tracing support"
+ depends on INTEL_VMX
+ default y
+ help
+ Enables HW VM tracing support which allows to configure HW processor
+ features (vmtrace_op) to enable capturing information about software
+ execution using dedicated hardware facilities with minimal interference
+ to the software being traced. The trace data can be retrieved using buffer
+ shared between Xen and domain
+ (see XENMEM_acquire_resource(XENMEM_resource_vmtrace_buf)).
+
config HVM_FEP
bool "HVM Forced Emulation Prefix support (UNSUPPORTED)" if UNSUPPORTED
default DEBUG
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index cd5ac8a5f0e3..2fffc2006ab0 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -307,6 +307,7 @@ static int vmx_init_vmcs_config(bool bsp)
rdmsrl(MSR_IA32_VMX_MISC, _vmx_misc_cap);
/* Check whether IPT is supported in VMX operation. */
+#ifdef CONFIG_VMTRACE
if ( bsp )
vmtrace_available = cpu_has_proc_trace &&
(_vmx_misc_cap & VMX_MISC_PROC_TRACE);
@@ -317,6 +318,7 @@ static int vmx_init_vmcs_config(bool bsp)
smp_processor_id());
return -EINVAL;
}
+#endif
if ( caps.cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS )
{
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index ee6977e94127..3f0e113b0b67 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -622,6 +622,7 @@ static void cf_check domain_creation_finished(struct domain *d)
static void vmx_init_ipt(struct vcpu *v)
{
+#ifdef CONFIG_VMTRACE
unsigned int size = v->domain->vmtrace_size;
if ( !size )
@@ -632,6 +633,7 @@ static void vmx_init_ipt(struct vcpu *v)
ASSERT(size >= PAGE_SIZE && (size & (size - 1)) == 0);
v->arch.msrs->rtit.output_limit = size - 1;
+#endif
}
static int cf_check vmx_vcpu_initialise(struct vcpu *v)
@@ -724,11 +726,13 @@ static void vmx_save_guest_msrs(struct vcpu *v)
*/
v->arch.hvm.vmx.shadow_gs = read_gs_shadow();
+#ifdef CONFIG_VMTRACE
if ( v->arch.hvm.vmx.ipt_active )
{
rdmsrl(MSR_RTIT_OUTPUT_MASK, msrs->rtit.output_mask);
rdmsrl(MSR_RTIT_STATUS, msrs->rtit.status);
}
+#endif
if ( cp->feat.pks )
msrs->pkrs = rdpkrs_and_cache();
@@ -747,12 +751,14 @@ static void vmx_restore_guest_msrs(struct vcpu *v)
if ( cpu_has_msr_tsc_aux )
wrmsr_tsc_aux(msrs->tsc_aux);
+#ifdef CONFIG_VMTRACE
if ( v->arch.hvm.vmx.ipt_active )
{
wrmsrl(MSR_RTIT_OUTPUT_BASE, page_to_maddr(v->vmtrace.pg));
wrmsrl(MSR_RTIT_OUTPUT_MASK, msrs->rtit.output_mask);
wrmsrl(MSR_RTIT_STATUS, msrs->rtit.status);
}
+#endif
if ( cp->feat.pks )
wrpkrs(msrs->pkrs);
@@ -2626,6 +2632,7 @@ static bool cf_check vmx_get_pending_event(
return true;
}
+#ifdef CONFIG_VMTRACE
/*
* We only let vmtrace agents see and modify a subset of bits in MSR_RTIT_CTL.
* These all pertain to data-emitted into the trace buffer(s). Must not
@@ -2768,6 +2775,7 @@ static int cf_check vmtrace_reset(struct vcpu *v)
v->arch.msrs->rtit.status = 0;
return 0;
}
+#endif
static uint64_t cf_check vmx_get_reg(struct vcpu *v, unsigned int reg)
{
@@ -2940,11 +2948,14 @@ static struct hvm_function_table __initdata_cf_clobber vmx_function_table = {
.altp2m_vcpu_emulate_ve = vmx_vcpu_emulate_ve,
.altp2m_vcpu_emulate_vmfunc = vmx_vcpu_emulate_vmfunc,
#endif
+
+#ifdef CONFIG_VMTRACE
.vmtrace_control = vmtrace_control,
.vmtrace_output_position = vmtrace_output_position,
.vmtrace_set_option = vmtrace_set_option,
.vmtrace_get_option = vmtrace_get_option,
.vmtrace_reset = vmtrace_reset,
+#endif
.get_reg = vmx_get_reg,
.set_reg = vmx_set_reg,
diff --git a/xen/arch/x86/include/asm/guest-msr.h b/xen/arch/x86/include/asm/guest-msr.h
index 5f0cb0a93995..702f47fe1e16 100644
--- a/xen/arch/x86/include/asm/guest-msr.h
+++ b/xen/arch/x86/include/asm/guest-msr.h
@@ -50,6 +50,7 @@ struct vcpu_msrs
};
} misc_features_enables;
+#ifdef CONFIG_VMTRACE
/*
* 0x00000560 ... 57x - MSR_RTIT_*
*
@@ -81,6 +82,7 @@ struct vcpu_msrs
};
};
} rtit;
+#endif
/*
* 0x000006e1 - MSR_PKRS - Protection Key Supervisor.
diff --git a/xen/arch/x86/include/asm/hvm/hvm.h b/xen/arch/x86/include/asm/hvm/hvm.h
index 7412256a2dab..93da4dd2dc4b 100644
--- a/xen/arch/x86/include/asm/hvm/hvm.h
+++ b/xen/arch/x86/include/asm/hvm/hvm.h
@@ -234,12 +234,14 @@ struct hvm_function_table {
int (*altp2m_vcpu_emulate_vmfunc)(const struct cpu_user_regs *regs);
#endif
+#ifdef CONFIG_VMTRACE
/* vmtrace */
int (*vmtrace_control)(struct vcpu *v, bool enable, bool reset);
int (*vmtrace_output_position)(struct vcpu *v, uint64_t *pos);
int (*vmtrace_set_option)(struct vcpu *v, uint64_t key, uint64_t value);
int (*vmtrace_get_option)(struct vcpu *v, uint64_t key, uint64_t *value);
int (*vmtrace_reset)(struct vcpu *v);
+#endif
uint64_t (*get_reg)(struct vcpu *v, unsigned int reg);
void (*set_reg)(struct vcpu *v, unsigned int reg, uint64_t val);
@@ -738,6 +740,7 @@ static inline bool altp2m_vcpu_emulate_ve(struct vcpu *v)
bool altp2m_vcpu_emulate_ve(struct vcpu *v);
#endif /* CONFIG_ALTP2M */
+#ifdef CONFIG_VMTRACE
static inline int hvm_vmtrace_control(struct vcpu *v, bool enable, bool reset)
{
if ( hvm_funcs.vmtrace_control )
@@ -772,13 +775,24 @@ static inline int hvm_vmtrace_get_option(
return -EOPNOTSUPP;
}
+#else
+/*
+ * Function declaration(s) here are used without definition(s) to make compiler
+ * happy when VMTRACE=n, compiler DCE will eliminate unused code.
+ */
+int hvm_vmtrace_output_position(struct vcpu *v, uint64_t *pos);
+#endif
static inline int hvm_vmtrace_reset(struct vcpu *v)
{
+#ifdef CONFIG_VMTRACE
if ( hvm_funcs.vmtrace_reset )
return alternative_call(hvm_funcs.vmtrace_reset, v);
return -EOPNOTSUPP;
+#else
+ return -EOPNOTSUPP;
+#endif
}
/*
@@ -934,28 +948,6 @@ static inline bool hvm_has_set_descriptor_access_exiting(void)
return false;
}
-static inline int hvm_vmtrace_control(struct vcpu *v, bool enable, bool reset)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int hvm_vmtrace_output_position(struct vcpu *v, uint64_t *pos)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int hvm_vmtrace_set_option(
- struct vcpu *v, uint64_t key, uint64_t value)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int hvm_vmtrace_get_option(
- struct vcpu *v, uint64_t key, uint64_t *value)
-{
- return -EOPNOTSUPP;
-}
-
static inline uint64_t hvm_get_reg(struct vcpu *v, unsigned int reg)
{
ASSERT_UNREACHABLE();
diff --git a/xen/arch/x86/include/asm/hvm/vmx/vmcs.h b/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
index 8ff7c8045fc6..879ec10cefd0 100644
--- a/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
+++ b/xen/arch/x86/include/asm/hvm/vmx/vmcs.h
@@ -154,8 +154,10 @@ struct vmx_vcpu {
/* Do we need to tolerate a spurious EPT_MISCONFIG VM exit? */
bool ept_spurious_misconfig;
+#ifdef CONFIG_VMTRACE
/* Processor Trace configured and enabled for the vcpu. */
bool ipt_active;
+#endif
/* Is the guest in real mode? */
uint8_t vmx_realmode;
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 4787b2796479..074f1b2562b3 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -1888,7 +1888,9 @@ static int fork(struct domain *cd, struct domain *d)
domain_pause(d);
cd->max_pages = d->max_pages;
*cd->arch.cpu_policy = *d->arch.cpu_policy;
+#ifdef CONFIG_VMTRACE
cd->vmtrace_size = d->vmtrace_size;
+#endif
cd->parent = d;
}
diff --git a/xen/arch/x86/vm_event.c b/xen/arch/x86/vm_event.c
index fc349270b9c5..e9ac1d497594 100644
--- a/xen/arch/x86/vm_event.c
+++ b/xen/arch/x86/vm_event.c
@@ -253,7 +253,8 @@ void vm_event_fill_regs(vm_event_request_t *req)
req->data.regs.x86.shadow_gs = ctxt.shadow_gs;
req->data.regs.x86.dr6 = ctxt.dr6;
- if ( hvm_vmtrace_output_position(curr, &req->data.regs.x86.vmtrace_pos) != 1 )
+ if ( IS_ENABLED(CONFIG_VMTRACE) &&
+ hvm_vmtrace_output_position(curr, &req->data.regs.x86.vmtrace_pos) != 1 )
req->data.regs.x86.vmtrace_pos = ~0;
#endif
}
@@ -303,12 +304,12 @@ void vm_event_emulate_check(struct vcpu *v, vm_event_response_t *rsp)
#endif
}
+#ifdef CONFIG_VMTRACE
void vm_event_reset_vmtrace(struct vcpu *v)
{
-#ifdef CONFIG_HVM
hvm_vmtrace_reset(v);
-#endif
}
+#endif
/*
* Local variables:
diff --git a/xen/common/domain.c b/xen/common/domain.c
index e13e01c1d272..ce4f55339fb4 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -136,7 +136,9 @@ struct vcpu *idle_vcpu[NR_CPUS] __read_mostly;
vcpu_info_t dummy_vcpu_info;
+#ifdef CONFIG_VMTRACE
bool __read_mostly vmtrace_available;
+#endif
bool __read_mostly vpmu_is_available;
@@ -318,6 +320,7 @@ static void vcpu_info_reset(struct vcpu *v)
static void vmtrace_free_buffer(struct vcpu *v)
{
+#ifdef CONFIG_VMTRACE
const struct domain *d = v->domain;
struct page_info *pg = v->vmtrace.pg;
unsigned int i;
@@ -332,10 +335,12 @@ static void vmtrace_free_buffer(struct vcpu *v)
put_page_alloc_ref(&pg[i]);
put_page_and_type(&pg[i]);
}
+#endif
}
static int vmtrace_alloc_buffer(struct vcpu *v)
{
+#ifdef CONFIG_VMTRACE
struct domain *d = v->domain;
struct page_info *pg;
unsigned int i;
@@ -377,6 +382,9 @@ static int vmtrace_alloc_buffer(struct vcpu *v)
}
return -ENODATA;
+#else
+ return 0;
+#endif
}
/*
@@ -825,7 +833,9 @@ struct domain *domain_create(domid_t domid,
ASSERT(!config->altp2m.nr);
#endif
+#ifdef CONFIG_VMTRACE
d->vmtrace_size = config->vmtrace_size;
+#endif
}
/* Sort out our idea of is_control_domain(). */
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 3688e6dd5032..66dc7f7a0a41 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -1155,8 +1155,10 @@ static unsigned int resource_max_frames(const struct domain *d,
case XENMEM_resource_ioreq_server:
return ioreq_server_max_frames(d);
+#ifdef CONFIG_VMTRACE
case XENMEM_resource_vmtrace_buf:
return d->vmtrace_size >> PAGE_SHIFT;
+#endif
default:
return 0;
@@ -1198,6 +1200,7 @@ static int acquire_ioreq_server(struct domain *d,
#endif
}
+#ifdef CONFIG_VMTRACE
static int acquire_vmtrace_buf(
struct domain *d, unsigned int id, unsigned int frame,
unsigned int nr_frames, xen_pfn_t mfn_list[])
@@ -1220,6 +1223,7 @@ static int acquire_vmtrace_buf(
return nr_frames;
}
+#endif
/*
* Returns -errno on error, or positive in the range [1, nr_frames] on
@@ -1238,8 +1242,10 @@ static int _acquire_resource(
case XENMEM_resource_ioreq_server:
return acquire_ioreq_server(d, id, frame, nr_frames, mfn_list);
+#ifdef CONFIG_VMTRACE
case XENMEM_resource_vmtrace_buf:
return acquire_vmtrace_buf(d, id, frame, nr_frames, mfn_list);
+#endif
default:
ASSERT_UNREACHABLE();
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index b2787c010890..cf0258223f50 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -441,7 +441,8 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
if ( rsp.flags & VM_EVENT_FLAG_GET_NEXT_INTERRUPT )
vm_event_monitor_next_interrupt(v);
- if ( rsp.flags & VM_EVENT_FLAG_RESET_VMTRACE )
+ if ( IS_ENABLED(CONFIG_VMTRACE) &&
+ (rsp.flags & VM_EVENT_FLAG_RESET_VMTRACE) )
vm_event_reset_vmtrace(v);
if ( rsp.flags & VM_EVENT_FLAG_VCPU_PAUSED )
diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
index 8aab05ae93c8..aa86a9f46022 100644
--- a/xen/include/xen/domain.h
+++ b/xen/include/xen/domain.h
@@ -191,7 +191,11 @@ void vnuma_destroy(struct vnuma_info *vnuma);
static inline void vnuma_destroy(struct vnuma_info *vnuma) { ASSERT(!vnuma); }
#endif
+#ifdef CONFIG_VMTRACE
extern bool vmtrace_available;
+#else
+#define vmtrace_available false
+#endif
extern bool vpmu_is_available;
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 02bdc256ce37..dcd8647e0d36 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -300,9 +300,11 @@ struct vcpu
/* vPCI per-vCPU area, used to store data for long running operations. */
struct vpci_vcpu vpci;
+#ifdef CONFIG_VMTRACE
struct {
struct page_info *pg; /* One contiguous allocation of d->vmtrace_size */
} vmtrace;
+#endif
struct arch_vcpu arch;
@@ -623,7 +625,9 @@ struct domain
unsigned int nr_altp2m; /* Number of altp2m tables. */
#endif
+#ifdef CONFIG_VMTRACE
unsigned int vmtrace_size; /* Buffer size in bytes, or 0 to disable. */
+#endif
#ifdef CONFIG_ARGO
/* Argo interdomain communication support */
--
2.34.1
next reply other threads:[~2025-11-14 14:22 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-14 14:22 Grygorii Strashko [this message]
2025-11-17 16:52 ` [XEN][PATCH v3] xen: make VMTRACE support optional Jan Beulich
2025-11-18 12:42 ` Grygorii Strashko
2025-11-18 13:39 ` Jan Beulich
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=20251114142207.279834-1-grygorii_strashko@epam.com \
--to=grygorii_strashko@epam.com \
--cc=Penny.Zheng@amd.com \
--cc=aisaila@bitdefender.com \
--cc=andrew.cooper3@citrix.com \
--cc=anthony.perard@vates.tech \
--cc=jbeulich@suse.com \
--cc=julien@xen.org \
--cc=michal.orzel@amd.com \
--cc=ppircalabu@bitdefender.com \
--cc=roger.pau@citrix.com \
--cc=sstabellini@kernel.org \
--cc=tamas@tklengyel.com \
--cc=teddy.astie@vates.tech \
--cc=xen-devel@lists.xenproject.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.