From nobody Sun Feb 8 17:21:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org ARC-Seal: i=1; a=rsa-sha256; t=1592849562; cv=none; d=zohomail.com; s=zohoarc; b=fW3NCc4pb3n2kQdxEFvHrhh3Z+kmwG/lY5xEJ8TtCAe1eoQ7hvkwxQV3d+3SgZ4IHAZI9r7yiontVfeYrQKJlbrG/fH7JsVhT/Rj387u/vtfofuaX/Gz7ZnIgYiyN+Ror593Mt4QnzzgXTkaRkH+d97ytOuU/kicEK7ZeHQlSDU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1592849562; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=1coGTOoQMNGlF8vqBOXgeppVf9dVgtyf4JfYaXBHmDs=; b=LKi/fZucuCuYtgGpg0nKEX3fD5m2n+kyINzciYXG9InXHyWxibHw1dK34AKEV2A9kvwJScr7DzvL5fKyaTDVsVQ+qV2Ecrx1ICex0iYl/60Pa6EkP5DTiLa/4d3hXA2gtqnepIKYibf2McN4QYzd3cA0fR+s2cmDIFVMf/VegVM= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1592849562977661.9541187895529; Mon, 22 Jun 2020 11:12:42 -0700 (PDT) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1jnQvb-0003Jz-Jo; Mon, 22 Jun 2020 18:12:19 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1jnQva-0003Jq-SP for xen-devel@lists.xenproject.org; Mon, 22 Jun 2020 18:12:18 +0000 Received: from bagnar.nask.net.pl (unknown [195.187.242.196]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id e7d7e682-b4b3-11ea-bb8b-bc764e2007e4; Mon, 22 Jun 2020 18:12:17 +0000 (UTC) Received: from bagnar.nask.net.pl (unknown [172.16.9.10]) by bagnar.nask.net.pl (Postfix) with ESMTP id A7E73A28C2; Mon, 22 Jun 2020 20:12:16 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by bagnar.nask.net.pl (Postfix) with ESMTP id 9477FA28AD; Mon, 22 Jun 2020 20:12:15 +0200 (CEST) Received: from bagnar.nask.net.pl ([127.0.0.1]) by localhost (bagnar.nask.net.pl [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id JNOa44oL45Ms; Mon, 22 Jun 2020 20:12:14 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by bagnar.nask.net.pl (Postfix) with ESMTP id 8F3F9A28DD; Mon, 22 Jun 2020 20:12:14 +0200 (CEST) Received: from bagnar.nask.net.pl ([127.0.0.1]) by localhost (bagnar.nask.net.pl [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id N2e-sZ1Fgu28; Mon, 22 Jun 2020 20:12:14 +0200 (CEST) Received: from belindir.nask.net.pl (belindir-ext.nask.net.pl [195.187.242.210]) by bagnar.nask.net.pl (Postfix) with ESMTP id 65731A289F; Mon, 22 Jun 2020 20:12:14 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by belindir.nask.net.pl (Postfix) with ESMTP id 4F90421CD8; Mon, 22 Jun 2020 20:11:44 +0200 (CEST) Received: from belindir.nask.net.pl ([127.0.0.1]) by localhost (belindir.nask.net.pl [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id GWabTm1LrnFz; Mon, 22 Jun 2020 20:11:38 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by belindir.nask.net.pl (Postfix) with ESMTP id 41A6021CBB; Mon, 22 Jun 2020 20:11:38 +0200 (CEST) Received: from belindir.nask.net.pl ([127.0.0.1]) by localhost (belindir.nask.net.pl [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id eoPR0vu2eetH; Mon, 22 Jun 2020 20:11:38 +0200 (CEST) Received: from belindir.nask.net.pl (belindir.nask.net.pl [172.16.10.10]) by belindir.nask.net.pl (Postfix) with ESMTP id 21A9521760; Mon, 22 Jun 2020 20:11:38 +0200 (CEST) X-Inumbo-ID: e7d7e682-b4b3-11ea-bb8b-bc764e2007e4 X-Virus-Scanned: amavisd-new at bagnar.nask.net.pl X-Virus-Scanned: amavisd-new at belindir.nask.net.pl Date: Mon, 22 Jun 2020 20:11:38 +0200 (CEST) From: =?utf-8?Q?Micha=C5=82_Leszczy=C5=84ski?= To: xen-devel@lists.xenproject.org Message-ID: <97440747.11443782.1592849498089.JavaMail.zimbra@cert.pl> In-Reply-To: <1617453791.11443328.1592849168658.JavaMail.zimbra@cert.pl> References: <1617453791.11443328.1592849168658.JavaMail.zimbra@cert.pl> Subject: [PATCH v3 4/7] x86/vmx: add do_vmtrace_op MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Originating-IP: [172.16.10.10] X-Mailer: Zimbra 8.6.0_GA_1194 (ZimbraWebClient - GC83 (Win)/8.6.0_GA_1194) Thread-Topic: x86/vmx: add do_vmtrace_op Thread-Index: fAatEklvenYpYrSWj77J6AQD/dj+xNwDcrpl X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Kevin Tian , Stefano Stabellini , Julien Grall , Jun Nakajima , Wei Liu , Andrew Cooper , Ian Jackson , George Dunlap , "Kang, Luwei" , Jan Beulich , Tamas K Lengyel , Roger Pau =?utf-8?Q?Monn=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" Content-Type: text/plain; charset="utf-8" Provide an interface for privileged domains to manage external IPT monitoring. Guest IPT state will be preserved across vmentry/vmexit using ipt_state structure. Signed-off-by: Michal Leszczynski --- xen/arch/x86/hvm/hvm.c | 168 +++++++++++++++++++++++++++++ xen/arch/x86/hvm/vmx/vmx.c | 31 ++++++ xen/arch/x86/mm.c | 28 +++++ xen/common/domain.c | 3 + xen/include/asm-x86/hvm/vmx/vmcs.h | 3 + xen/include/asm-x86/hvm/vmx/vmx.h | 14 +++ xen/include/public/domctl.h | 1 + xen/include/public/hvm/hvm_op.h | 26 +++++ xen/include/public/hvm/params.h | 2 +- xen/include/public/memory.h | 1 + xen/include/xen/sched.h | 4 + xen/include/xlat.lst | 1 + 12 files changed, 281 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 5bb47583b3..5899df52c3 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -606,6 +607,57 @@ static int hvm_print_line( return X86EMUL_OKAY; } =20 +static int vmtrace_alloc_buffers(struct vcpu *v, uint64_t size) +{ + struct page_info *pg; + struct pt_state *pt; + + if ( size < PAGE_SIZE || size > GB(4) || (size & (size - 1)) ) + { + /* + * We don't accept trace buffer size smaller than single page + * and the upper bound is defined as 4GB in the specification. + * The buffer size must be also a power of 2. + */ + return -EINVAL; + } + + if ( vmx_add_host_load_msr(v, MSR_RTIT_CTL, 0) ) + return -EFAULT; + + pg =3D alloc_domheap_pages(v->domain, get_order_from_bytes(size), + MEMF_no_refcount); + + if ( !pg ) + return -ENOMEM; + + pt =3D xzalloc(struct pt_state); + + if ( !pt ) + return -ENOMEM; + + pt->output_base =3D page_to_maddr(pg); + pt->output_mask.raw =3D size - 1; + + v->arch.hvm.vmx.pt_state =3D pt; + + return 0; +} + +static void vmtrace_destroy_buffers(struct vcpu *v) +{ + struct pt_state *pt =3D v->arch.hvm.vmx.pt_state; + + if ( pt ) + { + free_domheap_pages(maddr_to_page(pt->output_base), + get_order_from_bytes(pt->output_mask.size + 1)); + + xfree(pt); + v->arch.hvm.vmx.pt_state =3D NULL; + } +} + int hvm_domain_initialise(struct domain *d) { unsigned int nr_gsis; @@ -747,7 +799,10 @@ void hvm_domain_relinquish_resources(struct domain *d) hpet_deinit(d); =20 for_each_vcpu ( d, v ) + { + vmtrace_destroy_buffers(v); hvmemul_cache_destroy(v); + } } =20 void hvm_domain_destroy(struct domain *d) @@ -1594,6 +1649,13 @@ int hvm_vcpu_initialise(struct vcpu *v) hvm_set_guest_tsc(v, 0); } =20 + if ( d->vmtrace_pt_size ) + { + rc =3D vmtrace_alloc_buffers(v, d->vmtrace_pt_size); + if ( rc !=3D 0 ) + goto fail1; + } + return 0; =20 fail6: @@ -4949,6 +5011,108 @@ static int compat_altp2m_op( return rc; } =20 +CHECK_hvm_vmtrace_op; + +static int do_vmtrace_op(XEN_GUEST_HANDLE_PARAM(void) arg) +{ + struct xen_hvm_vmtrace_op a; + struct domain *d; + int rc; + struct vcpu *v; + struct pt_state *pt; + + if ( !hvm_pt_supported() ) + return -EOPNOTSUPP; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + if ( a.pad1 || a.pad2 ) + return -EINVAL; + + rc =3D rcu_lock_live_remote_domain_by_id(a.domain, &d); + + if ( rc ) + goto out; + + if ( !is_hvm_domain(d) ) + { + rc =3D -EOPNOTSUPP; + goto out; + } + + if ( a.vcpu >=3D d->max_vcpus ) + { + rc =3D -EINVAL; + goto out; + } + + v =3D domain_vcpu(d, a.vcpu); + pt =3D v->arch.hvm.vmx.pt_state; + + if ( !pt ) + { + /* PT must be first initialized upon domain creation. */ + rc =3D -EINVAL; + goto out; + } + + switch ( a.cmd ) + { + case HVMOP_vmtrace_pt_enable: + vcpu_pause(v); + spin_lock(&d->vmtrace_lock); + if ( vmx_add_guest_msr(v, MSR_RTIT_CTL, + RTIT_CTL_TRACEEN | RTIT_CTL_OS | + RTIT_CTL_USR | RTIT_CTL_BRANCH_EN) ) + { + rc =3D -EFAULT; + goto out; + } + + pt->active =3D 1; + spin_unlock(&d->vmtrace_lock); + vcpu_unpause(v); + break; + + case HVMOP_vmtrace_pt_disable: + vcpu_pause(v); + spin_lock(&d->vmtrace_lock); + + if ( vmx_del_msr(v, MSR_RTIT_CTL, VMX_MSR_GUEST) ) + { + rc =3D -EFAULT; + goto out; + } + + pt->active =3D 0; + spin_unlock(&d->vmtrace_lock); + vcpu_unpause(v); + break; + + case HVMOP_vmtrace_pt_get_offset: + a.offset =3D pt->output_mask.offset; + + if ( __copy_field_to_guest(guest_handle_cast(arg, xen_hvm_vmtrace_= op_t), &a, offset) ) + { + rc =3D -EFAULT; + goto out; + } + break; + + default: + rc =3D -EOPNOTSUPP; + goto out; + } + + rc =3D 0; + + out: + rcu_unlock_domain(d); + + return rc; +} + static int hvmop_get_mem_type( XEN_GUEST_HANDLE_PARAM(xen_hvm_get_mem_type_t) arg) { @@ -5101,6 +5265,10 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PA= RAM(void) arg) rc =3D current->hcall_compat ? compat_altp2m_op(arg) : do_altp2m_o= p(arg); break; =20 + case HVMOP_vmtrace: + rc =3D do_vmtrace_op(arg); + break; + default: { gdprintk(XENLOG_DEBUG, "Bad HVM op %ld.\n", op); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index ab19d9424e..3798a58d0f 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -508,11 +508,24 @@ static void vmx_restore_host_msrs(void) =20 static void vmx_save_guest_msrs(struct vcpu *v) { + uint64_t rtit_ctl; + /* * We cannot cache SHADOW_GS_BASE while the VCPU runs, as it can * be updated at any time via SWAPGS, which we cannot trap. */ v->arch.hvm.vmx.shadow_gs =3D rdgsshadow(); + + if ( unlikely(v->arch.hvm.vmx.pt_state && + v->arch.hvm.vmx.pt_state->active) ) + { + rdmsrl(MSR_RTIT_CTL, rtit_ctl); + BUG_ON(rtit_ctl & RTIT_CTL_TRACEEN); + + rdmsrl(MSR_RTIT_STATUS, v->arch.hvm.vmx.pt_state->status); + rdmsrl(MSR_RTIT_OUTPUT_MASK, + v->arch.hvm.vmx.pt_state->output_mask.raw); + } } =20 static void vmx_restore_guest_msrs(struct vcpu *v) @@ -524,6 +537,17 @@ static void vmx_restore_guest_msrs(struct vcpu *v) =20 if ( cpu_has_msr_tsc_aux ) wrmsr_tsc_aux(v->arch.msrs->tsc_aux); + + if ( unlikely(v->arch.hvm.vmx.pt_state && + v->arch.hvm.vmx.pt_state->active) ) + { + wrmsrl(MSR_RTIT_OUTPUT_BASE, + v->arch.hvm.vmx.pt_state->output_base); + wrmsrl(MSR_RTIT_OUTPUT_MASK, + v->arch.hvm.vmx.pt_state->output_mask.raw); + wrmsrl(MSR_RTIT_STATUS, + v->arch.hvm.vmx.pt_state->status); + } } =20 void vmx_update_cpu_exec_control(struct vcpu *v) @@ -3674,6 +3698,13 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) =20 hvm_invalidate_regs_fields(regs); =20 + if ( unlikely(v->arch.hvm.vmx.pt_state && + v->arch.hvm.vmx.pt_state->active) ) + { + rdmsrl(MSR_RTIT_OUTPUT_MASK, + v->arch.hvm.vmx.pt_state->output_mask.raw); + } + if ( paging_mode_hap(v->domain) ) { /* diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index e376fc7e8f..10fc26d13e 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -142,6 +142,7 @@ #include #include #include +#include =20 #include #include @@ -4624,6 +4625,33 @@ int arch_acquire_resource(struct domain *d, unsigned= int type, } break; } + + case XENMEM_resource_vmtrace_buf: + { + mfn_t mfn; + unsigned int i; + struct pt_state *pt; + rc =3D -EINVAL; + + if ( id >=3D d->max_vcpus ) + break; + + pt =3D d->vcpu[id]->arch.hvm.vmx.pt_state; + + if ( !pt ) + break; + + mfn =3D _mfn(pt->output_base >> PAGE_SHIFT); + + if ( frame + nr_frames > (pt->output_mask.size >> PAGE_SHIFT) + 1 ) + break; + + rc =3D 0; + for ( i =3D 0; i < nr_frames; i++ ) + mfn_list[i] =3D mfn_x(mfn_add(mfn, frame + i)); + + break; + } #endif =20 default: diff --git a/xen/common/domain.c b/xen/common/domain.c index 7cc9526139..52ccd678f4 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -414,6 +414,7 @@ struct domain *domain_create(domid_t domid, d->shutdown_code =3D SHUTDOWN_CODE_INVALID; =20 spin_lock_init(&d->pbuf_lock); + spin_lock_init(&d->vmtrace_lock); =20 rwlock_init(&d->vnuma_rwlock); =20 @@ -441,6 +442,8 @@ struct domain *domain_create(domid_t domid, d->nr_pirqs =3D min(d->nr_pirqs, nr_irqs); =20 radix_tree_init(&d->pirq_tree); + + d->vmtrace_pt_size =3D config->vmtrace_pt_size; } =20 if ( (err =3D arch_domain_create(d, config)) !=3D 0 ) diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/v= mx/vmcs.h index 0e9a0b8de6..64c0d82614 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -186,6 +186,9 @@ struct vmx_vcpu { * pCPU and wakeup the related vCPU. */ struct pi_blocking_vcpu pi_blocking; + + /* State of processor trace feature */ + struct pt_state *pt_state; }; =20 int vmx_create_vmcs(struct vcpu *v); diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vm= x/vmx.h index 111ccd7e61..be7213d3c0 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -689,4 +689,18 @@ typedef union ldt_or_tr_instr_info { }; } ldt_or_tr_instr_info_t; =20 +/* Processor Trace state per vCPU */ +struct pt_state { + bool_t active; + uint64_t status; + uint64_t output_base; + union { + uint64_t raw; + struct { + uint32_t size; + uint32_t offset; + }; + } output_mask; +}; + #endif /* __ASM_X86_HVM_VMX_VMX_H__ */ diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 59bdc28c89..054892befe 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -92,6 +92,7 @@ struct xen_domctl_createdomain { uint32_t max_evtchn_port; int32_t max_grant_frames; int32_t max_maptrack_frames; + uint64_t vmtrace_pt_size; =20 struct xen_arch_domainconfig arch; }; diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_o= p.h index 870ec52060..6d8841668e 100644 --- a/xen/include/public/hvm/hvm_op.h +++ b/xen/include/public/hvm/hvm_op.h @@ -382,6 +382,32 @@ struct xen_hvm_altp2m_op { typedef struct xen_hvm_altp2m_op xen_hvm_altp2m_op_t; DEFINE_XEN_GUEST_HANDLE(xen_hvm_altp2m_op_t); =20 +#if defined(__XEN__) || defined(__XEN_TOOLS__) + +/* HVMOP_vmtrace: Perform VM tracing related operation */ +#define HVMOP_vmtrace 26 + +struct xen_hvm_vmtrace_op { + /* IN variable */ + uint32_t cmd; +/* Enable/disable external vmtrace for given domain */ +#define HVMOP_vmtrace_pt_enable 1 +#define HVMOP_vmtrace_pt_disable 2 +#define HVMOP_vmtrace_pt_get_offset 3 + domid_t domain; + uint16_t pad1; + uint32_t vcpu; + uint32_t pad2; + uint64_t size; + + /* OUT variable */ + uint64_t offset; +}; +typedef struct xen_hvm_vmtrace_op xen_hvm_vmtrace_op_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_vmtrace_op_t); + +#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ + #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ =20 /* diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/param= s.h index 0a91bfa749..22f6185e01 100644 --- a/xen/include/public/hvm/params.h +++ b/xen/include/public/hvm/params.h @@ -300,6 +300,6 @@ #define XEN_HVM_MCA_CAP_LMCE (xen_mk_ullong(1) << 0) #define XEN_HVM_MCA_CAP_MASK XEN_HVM_MCA_CAP_LMCE =20 -#define HVM_NR_PARAMS 39 +#define HVM_NR_PARAMS 40 =20 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index dbd35305df..f823c784c3 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -620,6 +620,7 @@ struct xen_mem_acquire_resource { =20 #define XENMEM_resource_ioreq_server 0 #define XENMEM_resource_grant_table 1 +#define XENMEM_resource_vmtrace_buf 2 =20 /* * IN - a type-specific resource identifier, which must be zero diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index ac53519d7f..48f0a61bbd 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -457,6 +457,10 @@ struct domain unsigned pbuf_idx; spinlock_t pbuf_lock; =20 + /* Used by vmtrace features */ + spinlock_t vmtrace_lock; + uint64_t vmtrace_pt_size; + /* OProfile support. */ struct xenoprof *xenoprof; =20 diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst index 0921d4a8d0..c15529a43f 100644 --- a/xen/include/xlat.lst +++ b/xen/include/xlat.lst @@ -83,6 +83,7 @@ ? dm_op_set_pci_link_route hvm/dm_op.h ? dm_op_track_dirty_vram hvm/dm_op.h ! hvm_altp2m_set_mem_access_multi hvm/hvm_op.h +? hvm_vmtrace_op hvm/hvm_op.h ? vcpu_hvm_context hvm/hvm_vcpu.h ? vcpu_hvm_x86_32 hvm/hvm_vcpu.h ? vcpu_hvm_x86_64 hvm/hvm_vcpu.h --=20 2.20.1