xen: make VMTRACE support optional

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>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Tamas K Lengyel <tamas@tklengyel.com>
This commit is contained in:
Grygorii Strashko authored and Jan Beulich committed 2026-02-05 10:26:45 +01:00
1 parent d6a6ea77e1
commit 4202f7d0cd
14 files changed
+78 -26

No files matched your search

+4
View File
@@ -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
+12
View File
@@ -34,6 +34,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
+2
View File
@@ -306,6 +306,7 @@ static int vmx_init_vmcs_config(bool bsp)
rdmsrl(MSR_IA32_VMX_MISC, _vmx_misc_cap);
#ifdef CONFIG_VMTRACE
/* Check whether IPT is supported in VMX operation. */
if ( bsp )
vmtrace_available = cpu_has_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 )
{
+11
View File
@@ -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)
@@ -723,11 +725,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();
@@ -746,12 +750,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);
@@ -2629,6 +2635,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
@@ -2771,6 +2778,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)
{
@@ -2945,11 +2953,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,
+2
View File
@@ -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.
+12 -22
View File
@@ -236,12 +236,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);
@@ -741,6 +743,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 )
@@ -775,11 +778,20 @@ 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);
#endif
return -EOPNOTSUPP;
}
@@ -937,28 +949,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();
+2
View File
@@ -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;
+2
View File
@@ -1891,7 +1891,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;
}
+5 -3
View File
@@ -253,7 +253,9 @@ 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 +305,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:
+10
View File
@@ -135,7 +135,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;
@@ -358,6 +360,7 @@ static void free_vcpu_struct(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;
@@ -372,10 +375,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;
@@ -417,6 +422,9 @@ static int vmtrace_alloc_buffer(struct vcpu *v)
}
return -ENODATA;
#else
return 0;
#endif
}
/*
@@ -884,7 +892,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(). */
+6
View File
@@ -1259,8 +1259,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;
@@ -1302,6 +1304,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[])
@@ -1324,6 +1327,7 @@ static int acquire_vmtrace_buf(
return nr_frames;
}
#endif
/*
* Returns -errno on error, or positive in the range [1, nr_frames] on
@@ -1342,8 +1346,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();
+2 -1
View File
@@ -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 )
+4
View File
@@ -183,7 +183,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;
+4
View File
@@ -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;
@@ -626,7 +628,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 */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.