:p
atchew
Login
This patch serie originates from "Disable domctl-op via CONFIG_MGMT_HYPERCALLS" [1], and focuses on consolidating vm event subsystem (i.e. VM_EVENT), and its derived features, like memory paging, etc. [1] https://www.mail-archive.com/xen-devel@lists.xenproject.org/msg200843.html Penny Zheng (7): xen/svm: limit the scope of "rc" xen/vm_event: introduce vm_event_is_enabled() xen/monitor: wrap monitor_op under CONFIG_VM_EVENT xen/p2m: move xenmem_access_to_p2m_access() to common p2m.c xen/x86: move declaration from mem_access.h to altp2m.h xen/mem_access: wrap memory access when VM_EVENT=n xen/vm_event: consolidate CONFIG_VM_EVENT xen/arch/x86/Makefile | 2 +- xen/arch/x86/hvm/Kconfig | 1 - xen/arch/x86/hvm/Makefile | 4 +- xen/arch/x86/hvm/emulate.c | 67 +++++++------- xen/arch/x86/hvm/hvm.c | 123 ++++++++++++++++---------- xen/arch/x86/hvm/svm/intr.c | 2 +- xen/arch/x86/hvm/svm/svm.c | 82 +++++++++++------ xen/arch/x86/hvm/vmx/intr.c | 2 +- xen/arch/x86/hvm/vmx/vmx.c | 73 +++++++++------ xen/arch/x86/include/asm/altp2m.h | 10 +++ xen/arch/x86/include/asm/hvm/hvm.h | 18 ++-- xen/arch/x86/include/asm/mem_access.h | 20 ++--- xen/arch/x86/include/asm/monitor.h | 9 ++ xen/arch/x86/include/asm/vm_event.h | 8 ++ xen/arch/x86/mm/mem_access.c | 36 -------- xen/arch/x86/mm/mem_sharing.c | 3 + xen/arch/x86/mm/p2m.c | 38 ++++++++ xen/common/Kconfig | 7 +- xen/include/xen/vm_event.h | 7 ++ 19 files changed, 319 insertions(+), 193 deletions(-) -- 2.34.1
Feature monitor_op is based on vm event subsystem, so monitor.o shall be wrapped under CONFIG_VM_EVENT. The following functions are only invoked by monitor-op, so they all shall be wrapped with CONFIG_VM_EVENT (otherwise they will become unreachable and violate Misra rule 2.1 when VM_EVENT=n): - hvm_enable_msr_interception - hvm_function_table.enable_msr_interception - hvm_has_set_descriptor_access_existing - hvm_function_table.set_descriptor_access_existi - arch_monitor_get_capabilities Function monitored_msr() still needs a stub to pass compilation when VM_EVENT=n. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> --- v3 -> v4: - a new commit split from previous "xen/vm_event: consolidate CONFIG_VM_EVENT" - Another blank line ahead of the #ifdef - Move hvm_enable_msr_interception() up into the earlier #ifdef - only arch_monitor_get_capabilities() needs wrapping, as this static inline function calls hvm_has_set_descriptor_access_exiting(), which is declared only when VM_EVENT=y --- xen/arch/x86/hvm/Makefile | 2 +- xen/arch/x86/hvm/svm/svm.c | 8 +++++++- xen/arch/x86/hvm/vmx/vmx.c | 10 ++++++++++ xen/arch/x86/include/asm/hvm/hvm.h | 18 +++++++++++------- xen/arch/x86/include/asm/monitor.h | 9 +++++++++ 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += io.o obj-y += ioreq.o obj-y += irq.o obj-y += mmio.o -obj-y += monitor.o +obj-$(CONFIG_VM_EVENT) += monitor.o obj-y += mtrr.o obj-y += nestedhvm.o obj-y += pmtimer.o diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -XXX,XX +XXX,XX @@ void svm_intercept_msr(struct vcpu *v, uint32_t msr, int flags) __clear_bit(msr * 2 + 1, msr_bit); } +#ifdef CONFIG_VM_EVENT static void cf_check svm_enable_msr_interception(struct domain *d, uint32_t msr) { struct vcpu *v; @@ -XXX,XX +XXX,XX @@ static void cf_check svm_enable_msr_interception(struct domain *d, uint32_t msr) for_each_vcpu ( d, v ) svm_intercept_msr(v, msr, MSR_INTERCEPT_WRITE); } +#endif /* CONFIG_VM_EVENT */ static void svm_save_dr(struct vcpu *v) { @@ -XXX,XX +XXX,XX @@ static void cf_check svm_set_rdtsc_exiting(struct vcpu *v, bool enable) vmcb_set_general2_intercepts(vmcb, general2_intercepts); } +#ifdef CONFIG_VM_EVENT static void cf_check svm_set_descriptor_access_exiting( struct vcpu *v, bool enable) { @@ -XXX,XX +XXX,XX @@ static void cf_check svm_set_descriptor_access_exiting( vmcb_set_general1_intercepts(vmcb, general1_intercepts); } +#endif /* CONFIG_VM_EVENT */ static unsigned int cf_check svm_get_insn_bytes(struct vcpu *v, uint8_t *buf) { @@ -XXX,XX +XXX,XX @@ static struct hvm_function_table __initdata_cf_clobber svm_function_table = { .fpu_dirty_intercept = svm_fpu_dirty_intercept, .msr_read_intercept = svm_msr_read_intercept, .msr_write_intercept = svm_msr_write_intercept, +#ifdef CONFIG_VM_EVENT .enable_msr_interception = svm_enable_msr_interception, - .set_rdtsc_exiting = svm_set_rdtsc_exiting, .set_descriptor_access_exiting = svm_set_descriptor_access_exiting, +#endif + .set_rdtsc_exiting = svm_set_rdtsc_exiting, .get_insn_bytes = svm_get_insn_bytes, .nhvm_vcpu_initialise = nsvm_vcpu_initialise, diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_set_rdtsc_exiting(struct vcpu *v, bool enable) vmx_vmcs_exit(v); } +#ifdef CONFIG_VM_EVENT static void cf_check vmx_set_descriptor_access_exiting( struct vcpu *v, bool enable) { @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_set_descriptor_access_exiting( vmx_update_secondary_exec_control(v); vmx_vmcs_exit(v); } +#endif /* CONFIG_VM_EVENT */ static void cf_check vmx_init_hypercall_page(void *p) { @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_handle_eoi(uint8_t vector, int isr) printk_once(XENLOG_WARNING "EOI for %02x but SVI=%02x\n", vector, old_svi); } +#ifdef CONFIG_VM_EVENT static void cf_check vmx_enable_msr_interception(struct domain *d, uint32_t msr) { struct vcpu *v; @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_enable_msr_interception(struct domain *d, uint32_t msr) for_each_vcpu ( d, v ) vmx_set_msr_intercept(v, msr, VMX_MSR_W); } +#endif /* CONFIG_VM_EVENT */ #ifdef CONFIG_ALTP2M @@ -XXX,XX +XXX,XX @@ static struct hvm_function_table __initdata_cf_clobber vmx_function_table = { .nhvm_domain_relinquish_resources = nvmx_domain_relinquish_resources, .update_vlapic_mode = vmx_vlapic_msr_changed, .nhvm_hap_walk_L1_p2m = nvmx_hap_walk_L1_p2m, +#ifdef CONFIG_VM_EVENT .enable_msr_interception = vmx_enable_msr_interception, +#endif #ifdef CONFIG_ALTP2M .altp2m_vcpu_update_p2m = vmx_vcpu_update_eptp, .altp2m_vcpu_update_vmfunc_ve = vmx_vcpu_update_vmfunc_ve, @@ -XXX,XX +XXX,XX @@ const struct hvm_function_table * __init start_vmx(void) vmx_function_table.caps.singlestep = cpu_has_monitor_trap_flag; +#ifdef CONFIG_VM_EVENT if ( cpu_has_vmx_dt_exiting ) vmx_function_table.set_descriptor_access_exiting = vmx_set_descriptor_access_exiting; +#endif /* * Do not enable EPT when (!cpu_has_vmx_pat), to prevent security hole @@ -XXX,XX +XXX,XX @@ void __init vmx_fill_funcs(void) if ( !cpu_has_xen_ibt ) return; +#ifdef CONFIG_VM_EVENT vmx_function_table.set_descriptor_access_exiting = vmx_set_descriptor_access_exiting; +#endif vmx_function_table.update_eoi_exit_bitmap = vmx_update_eoi_exit_bitmap; vmx_function_table.process_isr = vmx_process_isr; diff --git a/xen/arch/x86/include/asm/hvm/hvm.h b/xen/arch/x86/include/asm/hvm/hvm.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/hvm/hvm.h +++ b/xen/arch/x86/include/asm/hvm/hvm.h @@ -XXX,XX +XXX,XX @@ struct hvm_function_table { void (*handle_cd)(struct vcpu *v, unsigned long value); void (*set_info_guest)(struct vcpu *v); void (*set_rdtsc_exiting)(struct vcpu *v, bool enable); + +#ifdef CONFIG_VM_EVENT void (*set_descriptor_access_exiting)(struct vcpu *v, bool enable); + void (*enable_msr_interception)(struct domain *d, uint32_t msr); +#endif /* Nested HVM */ int (*nhvm_vcpu_initialise)(struct vcpu *v); @@ -XXX,XX +XXX,XX @@ struct hvm_function_table { paddr_t *L1_gpa, unsigned int *page_order, uint8_t *p2m_acc, struct npfec npfec); - void (*enable_msr_interception)(struct domain *d, uint32_t msr); - #ifdef CONFIG_ALTP2M /* Alternate p2m */ void (*altp2m_vcpu_update_p2m)(struct vcpu *v); @@ -XXX,XX +XXX,XX @@ static inline bool using_svm(void) #define hvm_long_mode_active(v) (!!((v)->arch.hvm.guest_efer & EFER_LMA)) +#ifdef CONFIG_VM_EVENT static inline bool hvm_has_set_descriptor_access_exiting(void) { return hvm_funcs.set_descriptor_access_exiting; } +static inline void hvm_enable_msr_interception(struct domain *d, uint32_t msr) +{ + alternative_vcall(hvm_funcs.enable_msr_interception, d, msr); +} +#endif /* CONFIG_VM_EVENT */ + static inline void hvm_domain_creation_finished(struct domain *d) { if ( hvm_funcs.domain_creation_finished ) @@ -XXX,XX +XXX,XX @@ static inline int nhvm_hap_walk_L1_p2m( v, L2_gpa, L1_gpa, page_order, p2m_acc, npfec); } -static inline void hvm_enable_msr_interception(struct domain *d, uint32_t msr) -{ - alternative_vcall(hvm_funcs.enable_msr_interception, d, msr); -} - static inline bool hvm_is_singlestep_supported(void) { return hvm_funcs.caps.singlestep; diff --git a/xen/arch/x86/include/asm/monitor.h b/xen/arch/x86/include/asm/monitor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/monitor.h +++ b/xen/arch/x86/include/asm/monitor.h @@ -XXX,XX +XXX,XX @@ int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop) return rc; } +#ifdef CONFIG_VM_EVENT static inline uint32_t arch_monitor_get_capabilities(struct domain *d) { uint32_t capabilities = 0; @@ -XXX,XX +XXX,XX @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d) return capabilities; } +#endif /* CONFIG_VM_EVENT */ int arch_monitor_domctl_event(struct domain *d, struct xen_domctl_monitor_op *mop); @@ -XXX,XX +XXX,XX @@ static inline void arch_monitor_cleanup_domain(struct domain *d) {} #endif +#ifdef CONFIG_VM_EVENT bool monitored_msr(const struct domain *d, u32 msr); +#else +static inline bool monitored_msr(const struct domain *d, u32 msr) +{ + return false; +} +#endif bool monitored_msr_onchangeonly(const struct domain *d, u32 msr); #endif /* __ASM_X86_MONITOR_H__ */ -- 2.34.1
Memory access and ALTP2M are two seperate features, while both depending on helper xenmem_access_to_p2m_access(). So it betters lives in common p2m.c, other than mem_access.c which will be compiled out when VM_EVENT=n && ALTP2M=y. Coding style has been corrected at the same time. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> --- v3 -> v4: - new commit --- xen/arch/x86/mm/mem_access.c | 36 ---------------------------------- xen/arch/x86/mm/p2m.c | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_access.c +++ b/xen/arch/x86/mm/mem_access.c @@ -XXX,XX +XXX,XX @@ static int set_mem_access(struct domain *d, struct p2m_domain *p2m, return rc; } -bool xenmem_access_to_p2m_access(const struct p2m_domain *p2m, - xenmem_access_t xaccess, - p2m_access_t *paccess) -{ - static const p2m_access_t memaccess[] = { -#define ACCESS(ac) [XENMEM_access_##ac] = p2m_access_##ac - ACCESS(n), - ACCESS(r), - ACCESS(w), - ACCESS(rw), - ACCESS(x), - ACCESS(rx), - ACCESS(wx), - ACCESS(rwx), - ACCESS(rx2rw), - ACCESS(n2rwx), - ACCESS(r_pw), -#undef ACCESS - }; - - switch ( xaccess ) - { - case 0 ... ARRAY_SIZE(memaccess) - 1: - xaccess = array_index_nospec(xaccess, ARRAY_SIZE(memaccess)); - *paccess = memaccess[xaccess]; - break; - case XENMEM_access_default: - *paccess = p2m->default_access; - break; - default: - return false; - } - - return true; -} - /* * Set access type for a region of gfns. * If gfn == INVALID_GFN, sets the default access type. diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_log_dirty_range(struct domain *d, unsigned long begin_pfn, guest_flush_tlb_mask(d, d->dirty_cpumask); } +bool xenmem_access_to_p2m_access(const struct p2m_domain *p2m, + xenmem_access_t xaccess, + p2m_access_t *paccess) +{ + static const p2m_access_t memaccess[] = { +#define ACCESS(ac) [XENMEM_access_##ac] = p2m_access_##ac + ACCESS(n), + ACCESS(r), + ACCESS(w), + ACCESS(rw), + ACCESS(x), + ACCESS(rx), + ACCESS(wx), + ACCESS(rwx), + ACCESS(rx2rw), + ACCESS(n2rwx), + ACCESS(r_pw), +#undef ACCESS + }; + + switch ( xaccess ) + { + case 0 ... ARRAY_SIZE(memaccess) - 1: + xaccess = array_index_nospec(xaccess, ARRAY_SIZE(memaccess)); + *paccess = memaccess[xaccess]; + break; + + case XENMEM_access_default: + *paccess = p2m->default_access; + break; + + default: + return false; + } + + return true; +} + /* * Local variables: * mode: C -- 2.34.1
Memory access and ALTP2M are two seperate features, and each could be controlled via VM_EVENT or ALTP2M. In order to avoid implicit declaration when ALTP2M=y and VM_EVENT=n on compiling hvm.o/altp2m.o, we move declaration of the following functions from <asm/mem_access.h> to <asm/altp2m.h>: - p2m_set_suppress_ve - p2m_set_suppress_ve_multi - p2m_get_suppress_ve Potential error on altp2m.c also breaks Misra Rule 8.4. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> --- v3 -> v4: - new commit --- xen/arch/x86/include/asm/altp2m.h | 10 ++++++++++ xen/arch/x86/include/asm/mem_access.h | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ void altp2m_vcpu_destroy(struct vcpu *v); int altp2m_vcpu_enable_ve(struct vcpu *v, gfn_t gfn); void altp2m_vcpu_disable_ve(struct vcpu *v); +int p2m_set_suppress_ve(struct domain *d, gfn_t gfn, bool suppress_ve, + unsigned int altp2m_idx); + +struct xen_hvm_altp2m_suppress_ve_multi; +int p2m_set_suppress_ve_multi(struct domain *d, + struct xen_hvm_altp2m_suppress_ve_multi *sve); + +int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, + unsigned int altp2m_idx); + #else static inline bool altp2m_is_eptp_valid(const struct domain *d, diff --git a/xen/arch/x86/include/asm/mem_access.h b/xen/arch/x86/include/asm/mem_access.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/mem_access.h +++ b/xen/arch/x86/include/asm/mem_access.h @@ -XXX,XX +XXX,XX @@ bool p2m_mem_access_emulate_check(struct vcpu *v, /* Sanity check for mem_access hardware support */ bool p2m_mem_access_sanity_check(const struct domain *d); -int p2m_set_suppress_ve(struct domain *d, gfn_t gfn, bool suppress_ve, - unsigned int altp2m_idx); - -struct xen_hvm_altp2m_suppress_ve_multi; -int p2m_set_suppress_ve_multi(struct domain *d, - struct xen_hvm_altp2m_suppress_ve_multi *sve); - -int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, - unsigned int altp2m_idx); - #endif /*__ASM_X86_MEM_ACCESS_H__ */ /* -- 2.34.1
Feature memory access is based on vm event subsystem, and it could be disabled in the future. So a few switch-blocks in do_altp2m_op() need IS_ENABLED(CONFIG_VM_EVENT) wrapping to pass compilation when ALTP2M=y and VM_EVENT=n(, hence MEM_ACCESS=n), like HVMOP_altp2m_set_mem_access, etc. Function p2m_mem_access_check() still needs stub when VM_EVENT=n to pass compilation. Although local variable "req_ptr" still remains NULL throughout its lifetime, with the change of NULL assignment, we will face runtime undefined error only when CONFIG_USBAN is on. So we strengthen the condition check via adding vm_event_is_enabled() for the special case. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> --- v3 -> v4: - a new commit split from previous "xen/vm_event: consolidate CONFIG_VM_EVENT" - use IS_ENABLED() to replace #ifdef - remove unnecessary changes in compat_altp2m_op() - strengthen the condition check to fix runtime undefined error when CONFIG_USBAN=y --- xen/arch/x86/hvm/hvm.c | 97 +++++++++++++++------------ xen/arch/x86/include/asm/mem_access.h | 10 +++ 2 files changed, 65 insertions(+), 42 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ #include <asm/i387.h> #include <asm/mc146818rtc.h> #include <asm/mce.h> +#include <asm/mem_access.h> #include <asm/monitor.h> #include <asm/msr.h> #include <asm/mtrr.h> @@ -XXX,XX +XXX,XX @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, #endif } - if ( req_ptr ) + if ( req_ptr && vm_event_is_enabled(curr) ) { if ( monitor_traps(curr, sync, req_ptr) < 0 ) rc = 0; @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( break; case HVMOP_altp2m_set_mem_access: - if ( a.u.mem_access.pad ) - rc = -EINVAL; - else - rc = p2m_set_mem_access(d, _gfn(a.u.mem_access.gfn), 1, 0, 0, - a.u.mem_access.access, - a.u.mem_access.view); + if ( IS_ENABLED(CONFIG_VM_EVENT) ) + { + if ( a.u.mem_access.pad ) + rc = -EINVAL; + else + rc = p2m_set_mem_access(d, _gfn(a.u.mem_access.gfn), 1, 0, 0, + a.u.mem_access.access, + a.u.mem_access.view); + } break; case HVMOP_altp2m_set_mem_access_multi: - if ( a.u.set_mem_access_multi.pad || - a.u.set_mem_access_multi.opaque > a.u.set_mem_access_multi.nr ) + if ( IS_ENABLED(CONFIG_VM_EVENT) ) { - rc = -EINVAL; - break; - } + if ( a.u.set_mem_access_multi.pad || + a.u.set_mem_access_multi.opaque > + a.u.set_mem_access_multi.nr ) + { + rc = -EINVAL; + break; + } - /* - * Unlike XENMEM_access_op_set_access_multi, we don't need any bits of - * the 'continuation' counter to be zero (to stash a command in). - * However, 0x40 is a good 'stride' to make sure that we make - * a reasonable amount of forward progress before yielding, - * so use a mask of 0x3F here. - */ - rc = p2m_set_mem_access_multi(d, a.u.set_mem_access_multi.pfn_list, - a.u.set_mem_access_multi.access_list, - a.u.set_mem_access_multi.nr, - a.u.set_mem_access_multi.opaque, - 0x3F, - a.u.set_mem_access_multi.view); - if ( rc > 0 ) - { - a.u.set_mem_access_multi.opaque = rc; - rc = -ERESTART; - if ( __copy_field_to_guest(guest_handle_cast(arg, xen_hvm_altp2m_op_t), - &a, u.set_mem_access_multi.opaque) ) - rc = -EFAULT; + /* + * Unlike XENMEM_access_op_set_access_multi, we don't need any + * bits of the 'continuation' counter to be zero (to stash a + * command in). + * However, 0x40 is a good 'stride' to make sure that we make + * a reasonable amount of forward progress before yielding, + * so use a mask of 0x3F here. + */ + rc = p2m_set_mem_access_multi(d, a.u.set_mem_access_multi.pfn_list, + a.u.set_mem_access_multi.access_list, + a.u.set_mem_access_multi.nr, + a.u.set_mem_access_multi.opaque, + 0x3F, + a.u.set_mem_access_multi.view); + if ( rc > 0 ) + { + a.u.set_mem_access_multi.opaque = rc; + rc = -ERESTART; + if ( __copy_field_to_guest( + guest_handle_cast(arg, xen_hvm_altp2m_op_t), + &a, u.set_mem_access_multi.opaque) ) + rc = -EFAULT; + } } break; case HVMOP_altp2m_get_mem_access: - if ( a.u.mem_access.pad ) - rc = -EINVAL; - else + if ( IS_ENABLED(CONFIG_VM_EVENT) ) { - xenmem_access_t access; - - rc = p2m_get_mem_access(d, _gfn(a.u.mem_access.gfn), &access, - a.u.mem_access.view); - if ( !rc ) + if ( a.u.mem_access.pad ) + rc = -EINVAL; + else { - a.u.mem_access.access = access; - rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + xenmem_access_t access; + + rc = p2m_get_mem_access(d, _gfn(a.u.mem_access.gfn), &access, + a.u.mem_access.view); + if ( !rc ) + { + a.u.mem_access.access = access; + rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + } } } break; diff --git a/xen/arch/x86/include/asm/mem_access.h b/xen/arch/x86/include/asm/mem_access.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/mem_access.h +++ b/xen/arch/x86/include/asm/mem_access.h @@ -XXX,XX +XXX,XX @@ #ifndef __ASM_X86_MEM_ACCESS_H__ #define __ASM_X86_MEM_ACCESS_H__ +#ifdef CONFIG_VM_EVENT /* * Setup vm_event request based on the access (gla is -1ull if not available). * Handles the rw2rx conversion. Boolean return value indicates if event type @@ -XXX,XX +XXX,XX @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla, struct npfec npfec, struct vm_event_st **req_ptr); +#else +static inline bool p2m_mem_access_check(paddr_t gpa, unsigned long gla, + struct npfec npfec, + struct vm_event_st **req_ptr) +{ + *req_ptr = NULL; + return false; +} +#endif /* CONFIG_VM_EVENT */ /* Check for emulation and mark vcpu for skipping one instruction * upon rescheduling if required. */ -- 2.34.1
File hvm/vm_event.c and x86/vm_event.c are the extend to vm_event handling routines, and its compilation shall be guarded by CONFIG_VM_EVENT too. Although CONFIG_VM_EVENT is right now forcibly enabled on x86 via MEM_ACCESS_ALWAYS_ON, we could disable it through disabling CONFIG_MGMT_HYPERCALLS later. So we remove MEM_ACCESS_ALWAYS_ON and make VM_EVENT=y on default only on x86 to retain the same. The following functions are developed on the basis of vm event framework, or only invoked by vm_event.c, so they all shall be wrapped with CONFIG_VM_EVENT (otherwise they will become unreachable and violate Misra rule 2.1 when VM_EVENT=n): - hvm_toggle_singlestep - hvm_fast_singlestep - hvm_emulate_one_vm_event - hvmemul_write{,cmpxchg,rep_ins,rep_outs,rep_movs,rep_stos,read_io,write_io}_discard And Function vm_event_check_ring() needs stub to pass compilation when VM_EVENT=n. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> --- v1 -> v2: - split out XSM changes - remove unnecessary stubs - move "struct p2m_domain" declaration ahead of the #ifdef --- v2 -> v3: - move .enable_msr_interception and .set_descriptor_access_exiting together - with the introduction of "vm_event_is_enabled()", all hvm_monitor_xxx() stubs are no longer needed - change to use in-place stubs in do_altp2m_op() - no need to add stub for monitor_traps(), __vm_event_claim_slot(), vm_event_put_request() and vm_event_vcpu_pause() - remove MEM_ACCESS_ALWAYS_ON - return default p2m_access_rwx for xenmem_access_to_p2m_access() when VM_EVENT=n - add wrapping for hvm_emulate_one_vm_event/ hvmemul_write{,cmpxchg,rep_ins,rep_outs,rep_movs,rep_stos,read_io,write_io}_discard --- xen/arch/x86/Makefile | 2 +- xen/arch/x86/hvm/Kconfig | 1 - xen/arch/x86/hvm/Makefile | 2 +- xen/arch/x86/hvm/emulate.c | 58 ++++++++++++++++++++------------------ xen/arch/x86/hvm/hvm.c | 2 ++ xen/common/Kconfig | 7 ++--- xen/include/xen/vm_event.h | 7 +++++ 7 files changed, 44 insertions(+), 35 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += usercopy.o obj-y += x86_emulate.o obj-$(CONFIG_TBOOT) += tboot.o obj-y += hpet.o -obj-y += vm_event.o +obj-$(CONFIG_VM_EVENT) += vm_event.o obj-y += xstate.o ifneq ($(CONFIG_PV_SHIM_EXCLUSIVE),y) diff --git a/xen/arch/x86/hvm/Kconfig b/xen/arch/x86/hvm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/Kconfig +++ b/xen/arch/x86/hvm/Kconfig @@ -XXX,XX +XXX,XX @@ menuconfig HVM default !PV_SHIM select COMPAT select IOREQ_SERVER - select MEM_ACCESS_ALWAYS_ON help Interfaces to support HVM domains. HVM domains require hardware virtualisation extensions (e.g. Intel VT-x, AMD SVM), but can boot diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += save.o obj-y += stdvga.o obj-y += vioapic.o obj-y += vlapic.o -obj-y += vm_event.o +obj-$(CONFIG_VM_EVENT) += vm_event.o obj-y += vmsi.o obj-y += vpic.o obj-y += vpt.o diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -XXX,XX +XXX,XX @@ static int cf_check hvmemul_blk( return rc; } +#ifdef CONFIG_VM_EVENT static int cf_check hvmemul_write_discard( enum x86_segment seg, unsigned long offset, @@ -XXX,XX +XXX,XX @@ static int cf_check hvmemul_cache_op_discard( { return X86EMUL_OKAY; } +#endif /* CONFIG_VM_EVENT */ static int cf_check hvmemul_cmpxchg( enum x86_segment seg, @@ -XXX,XX +XXX,XX @@ static const struct x86_emulate_ops hvm_emulate_ops = { .vmfunc = hvmemul_vmfunc, }; -static const struct x86_emulate_ops hvm_emulate_ops_no_write = { - .read = hvmemul_read, - .insn_fetch = hvmemul_insn_fetch, - .write = hvmemul_write_discard, - .cmpxchg = hvmemul_cmpxchg_discard, - .rep_ins = hvmemul_rep_ins_discard, - .rep_outs = hvmemul_rep_outs_discard, - .rep_movs = hvmemul_rep_movs_discard, - .rep_stos = hvmemul_rep_stos_discard, - .read_segment = hvmemul_read_segment, - .write_segment = hvmemul_write_segment, - .read_io = hvmemul_read_io_discard, - .write_io = hvmemul_write_io_discard, - .read_cr = hvmemul_read_cr, - .write_cr = hvmemul_write_cr, - .read_xcr = hvmemul_read_xcr, - .write_xcr = hvmemul_write_xcr, - .read_msr = hvmemul_read_msr, - .write_msr = hvmemul_write_msr_discard, - .cache_op = hvmemul_cache_op_discard, - .tlb_op = hvmemul_tlb_op, - .cpuid = x86emul_cpuid, - .get_fpu = hvmemul_get_fpu, - .put_fpu = hvmemul_put_fpu, - .vmfunc = hvmemul_vmfunc, -}; - /* * Note that passing VIO_no_completion into this function serves as kind * of (but not fully) an "auto select completion" indicator. When there's @@ -XXX,XX +XXX,XX @@ int hvm_emulate_one( return _hvm_emulate_one(hvmemul_ctxt, &hvm_emulate_ops, completion); } +#ifdef CONFIG_VM_EVENT +static const struct x86_emulate_ops hvm_emulate_ops_no_write = { + .read = hvmemul_read, + .insn_fetch = hvmemul_insn_fetch, + .write = hvmemul_write_discard, + .cmpxchg = hvmemul_cmpxchg_discard, + .rep_ins = hvmemul_rep_ins_discard, + .rep_outs = hvmemul_rep_outs_discard, + .rep_movs = hvmemul_rep_movs_discard, + .rep_stos = hvmemul_rep_stos_discard, + .read_segment = hvmemul_read_segment, + .write_segment = hvmemul_write_segment, + .read_io = hvmemul_read_io_discard, + .write_io = hvmemul_write_io_discard, + .read_cr = hvmemul_read_cr, + .write_cr = hvmemul_write_cr, + .read_xcr = hvmemul_read_xcr, + .write_xcr = hvmemul_write_xcr, + .read_msr = hvmemul_read_msr, + .write_msr = hvmemul_write_msr_discard, + .cache_op = hvmemul_cache_op_discard, + .tlb_op = hvmemul_tlb_op, + .cpuid = x86emul_cpuid, + .get_fpu = hvmemul_get_fpu, + .put_fpu = hvmemul_put_fpu, + .vmfunc = hvmemul_vmfunc, +}; + void hvm_emulate_one_vm_event(enum emul_kind kind, unsigned int trapnr, unsigned int errcode) { @@ -XXX,XX +XXX,XX @@ void hvm_emulate_one_vm_event(enum emul_kind kind, unsigned int trapnr, hvm_emulate_writeback(&ctx); } +#endif /* CONFIG_VM_EVENT */ void hvm_emulate_init_once( struct hvm_emulate_ctxt *hvmemul_ctxt, diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ int hvm_debug_op(struct vcpu *v, int32_t op) return rc; } +#ifdef CONFIG_VM_EVENT void hvm_toggle_singlestep(struct vcpu *v) { ASSERT(atomic_read(&v->pause_count)); @@ -XXX,XX +XXX,XX @@ void hvm_fast_singlestep(struct vcpu *v, uint16_t p2midx) v->arch.hvm.fast_single_step.p2midx = p2midx; } #endif +#endif /* CONFIG_VM_EVENT */ /* * Segment caches in VMCB/VMCS are inconsistent about which bits are checked, diff --git a/xen/common/Kconfig b/xen/common/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -XXX,XX +XXX,XX @@ config HAS_VMAP config LIBFDT bool -config MEM_ACCESS_ALWAYS_ON - bool - config VM_EVENT - def_bool MEM_ACCESS_ALWAYS_ON - prompt "Memory Access and VM events" if !MEM_ACCESS_ALWAYS_ON + bool "Memory Access and VM events" depends on HVM + default X86 help Framework to configure memory access types for guests and receive diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/vm_event.h +++ b/xen/include/xen/vm_event.h @@ -XXX,XX +XXX,XX @@ struct vm_event_domain }; /* Returns whether a ring has been set up */ +#ifdef CONFIG_VM_EVENT bool vm_event_check_ring(struct vm_event_domain *ved); +#else +static inline bool vm_event_check_ring(struct vm_event_domain *ved) +{ + return false; +} +#endif /* CONFIG_VM_EVENT */ /* Returns 0 on success, -ENOSYS if there is no ring, -EBUSY if there is no * available space and the caller is a foreign domain. If the guest itself -- 2.34.1
This patch serie originates from "Disable domctl-op via CONFIG_MGMT_HYPERCALLS" [1], and focuses on consolidating vm event subsystem (i.e. VM_EVENT), and its derived features, like memory paging, etc. [1] https://www.mail-archive.com/xen-devel@lists.xenproject.org/msg200843.html --- Happy 2026! Sorry for the late response to this patch serie and the domctl one. v4 is just doing a rebase on the latest staging, and one comment fix. I still need 2 acks for commit "xen/p2m: move xenmem_access_to_p2m_access() to common p2m.c" and "xen/mem_access: wrap memory access when VM_EVENT=n". --- Penny Zheng (6): xen/x86: move declaration from mem_access.h to altp2m.h x86/vm_event: introduce vm_event_is_enabled() x86/monitor: wrap monitor_op under CONFIG_VM_EVENT xen/p2m: move xenmem_access_to_p2m_access() to common p2m.c xen/mem_access: wrap memory access when VM_EVENT=n xen/vm_event: consolidate CONFIG_VM_EVENT xen/arch/x86/Makefile | 2 +- xen/arch/x86/hvm/Kconfig | 1 - xen/arch/x86/hvm/Makefile | 4 +- xen/arch/x86/hvm/emulate.c | 67 ++++++++++++------------ xen/arch/x86/hvm/hvm.c | 51 ++++++++++++++++--- xen/arch/x86/hvm/svm/intr.c | 2 +- xen/arch/x86/hvm/svm/svm.c | 54 ++++++++++++-------- xen/arch/x86/hvm/vmx/intr.c | 2 +- xen/arch/x86/hvm/vmx/vmx.c | 73 ++++++++++++++++++--------- xen/arch/x86/include/asm/altp2m.h | 10 ++++ xen/arch/x86/include/asm/hvm/hvm.h | 18 ++++--- xen/arch/x86/include/asm/mem_access.h | 20 ++++---- xen/arch/x86/include/asm/monitor.h | 9 ++++ xen/arch/x86/include/asm/vm_event.h | 5 ++ xen/arch/x86/mm/mem_access.c | 36 ------------- xen/arch/x86/mm/mem_sharing.c | 3 ++ xen/arch/x86/mm/p2m.c | 40 +++++++++++++++ xen/common/Kconfig | 7 +-- xen/include/xen/mem_access.h | 5 -- xen/include/xen/p2m-common.h | 3 ++ xen/include/xen/vm_event.h | 7 +++ 21 files changed, 266 insertions(+), 153 deletions(-) -- 2.34.1
Memory access and ALTP2M are two seperate features, and each could be controlled via VM_EVENT or ALTP2M. In order to avoid implicit declaration when ALTP2M=y and VM_EVENT=n on compiling hvm.o/altp2m.o, we move declaration of the following functions from <asm/mem_access.h> to <asm/altp2m.h>: - p2m_set_suppress_ve - p2m_set_suppress_ve_multi - p2m_get_suppress_ve Potential error on altp2m.c also breaks Misra Rule 8.4. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com> --- xen/arch/x86/include/asm/altp2m.h | 10 ++++++++++ xen/arch/x86/include/asm/mem_access.h | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/xen/arch/x86/include/asm/altp2m.h b/xen/arch/x86/include/asm/altp2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/altp2m.h +++ b/xen/arch/x86/include/asm/altp2m.h @@ -XXX,XX +XXX,XX @@ void altp2m_vcpu_destroy(struct vcpu *v); int altp2m_vcpu_enable_ve(struct vcpu *v, gfn_t gfn); void altp2m_vcpu_disable_ve(struct vcpu *v); +int p2m_set_suppress_ve(struct domain *d, gfn_t gfn, bool suppress_ve, + unsigned int altp2m_idx); + +struct xen_hvm_altp2m_suppress_ve_multi; +int p2m_set_suppress_ve_multi(struct domain *d, + struct xen_hvm_altp2m_suppress_ve_multi *sve); + +int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, + unsigned int altp2m_idx); + #else static inline bool altp2m_is_eptp_valid(const struct domain *d, diff --git a/xen/arch/x86/include/asm/mem_access.h b/xen/arch/x86/include/asm/mem_access.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/mem_access.h +++ b/xen/arch/x86/include/asm/mem_access.h @@ -XXX,XX +XXX,XX @@ bool p2m_mem_access_emulate_check(struct vcpu *v, /* Sanity check for mem_access hardware support */ bool p2m_mem_access_sanity_check(const struct domain *d); -int p2m_set_suppress_ve(struct domain *d, gfn_t gfn, bool suppress_ve, - unsigned int altp2m_idx); - -struct xen_hvm_altp2m_suppress_ve_multi; -int p2m_set_suppress_ve_multi(struct domain *d, - struct xen_hvm_altp2m_suppress_ve_multi *sve); - -int p2m_get_suppress_ve(struct domain *d, gfn_t gfn, bool *suppress_ve, - unsigned int altp2m_idx); - #endif /*__ASM_X86_MEM_ACCESS_H__ */ /* -- 2.34.1
Feature monitor_op is based on vm event subsystem, so monitor.o shall be wrapped under CONFIG_VM_EVENT. The following functions are only invoked by monitor-op, so they all shall be wrapped with CONFIG_VM_EVENT (otherwise they will become unreachable and violate Misra rule 2.1 when VM_EVENT=n): - hvm_enable_msr_interception - hvm_function_table.enable_msr_interception - hvm_has_set_descriptor_access_existing - hvm_function_table.set_descriptor_access_existi - arch_monitor_get_capabilities Function monitored_msr() still needs a stub to pass compilation when VM_EVENT=n. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> Acked-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com> --- xen/arch/x86/hvm/Makefile | 2 +- xen/arch/x86/hvm/svm/svm.c | 8 +++++++- xen/arch/x86/hvm/vmx/vmx.c | 10 ++++++++++ xen/arch/x86/include/asm/hvm/hvm.h | 18 +++++++++++------- xen/arch/x86/include/asm/monitor.h | 9 +++++++++ 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += io.o obj-y += ioreq.o obj-y += irq.o obj-y += mmio.o -obj-y += monitor.o +obj-$(CONFIG_VM_EVENT) += monitor.o obj-y += mtrr.o obj-y += nestedhvm.o obj-y += pmtimer.o diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -XXX,XX +XXX,XX @@ void svm_intercept_msr(struct vcpu *v, uint32_t msr, int flags) __clear_bit(msr * 2 + 1, msr_bit); } +#ifdef CONFIG_VM_EVENT static void cf_check svm_enable_msr_interception(struct domain *d, uint32_t msr) { struct vcpu *v; @@ -XXX,XX +XXX,XX @@ static void cf_check svm_enable_msr_interception(struct domain *d, uint32_t msr) for_each_vcpu ( d, v ) svm_intercept_msr(v, msr, MSR_INTERCEPT_WRITE); } +#endif /* CONFIG_VM_EVENT */ static void svm_save_dr(struct vcpu *v) { @@ -XXX,XX +XXX,XX @@ static void cf_check svm_set_rdtsc_exiting(struct vcpu *v, bool enable) vmcb_set_general2_intercepts(vmcb, general2_intercepts); } +#ifdef CONFIG_VM_EVENT static void cf_check svm_set_descriptor_access_exiting( struct vcpu *v, bool enable) { @@ -XXX,XX +XXX,XX @@ static void cf_check svm_set_descriptor_access_exiting( vmcb_set_general1_intercepts(vmcb, general1_intercepts); } +#endif /* CONFIG_VM_EVENT */ static unsigned int cf_check svm_get_insn_bytes(struct vcpu *v, uint8_t *buf) { @@ -XXX,XX +XXX,XX @@ static struct hvm_function_table __initdata_cf_clobber svm_function_table = { .fpu_dirty_intercept = svm_fpu_dirty_intercept, .msr_read_intercept = svm_msr_read_intercept, .msr_write_intercept = svm_msr_write_intercept, +#ifdef CONFIG_VM_EVENT .enable_msr_interception = svm_enable_msr_interception, - .set_rdtsc_exiting = svm_set_rdtsc_exiting, .set_descriptor_access_exiting = svm_set_descriptor_access_exiting, +#endif + .set_rdtsc_exiting = svm_set_rdtsc_exiting, .get_insn_bytes = svm_get_insn_bytes, .nhvm_vcpu_initialise = nsvm_vcpu_initialise, diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_set_rdtsc_exiting(struct vcpu *v, bool enable) vmx_vmcs_exit(v); } +#ifdef CONFIG_VM_EVENT static void cf_check vmx_set_descriptor_access_exiting( struct vcpu *v, bool enable) { @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_set_descriptor_access_exiting( vmx_update_secondary_exec_control(v); vmx_vmcs_exit(v); } +#endif /* CONFIG_VM_EVENT */ static void cf_check vmx_init_hypercall_page(void *p) { @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_handle_eoi(uint8_t vector, int isr) printk_once(XENLOG_WARNING "EOI for %02x but SVI=%02x\n", vector, old_svi); } +#ifdef CONFIG_VM_EVENT static void cf_check vmx_enable_msr_interception(struct domain *d, uint32_t msr) { struct vcpu *v; @@ -XXX,XX +XXX,XX @@ static void cf_check vmx_enable_msr_interception(struct domain *d, uint32_t msr) for_each_vcpu ( d, v ) vmx_set_msr_intercept(v, msr, VMX_MSR_W); } +#endif /* CONFIG_VM_EVENT */ #ifdef CONFIG_ALTP2M @@ -XXX,XX +XXX,XX @@ static struct hvm_function_table __initdata_cf_clobber vmx_function_table = { .nhvm_domain_relinquish_resources = nvmx_domain_relinquish_resources, .update_vlapic_mode = vmx_vlapic_msr_changed, .nhvm_hap_walk_L1_p2m = nvmx_hap_walk_L1_p2m, +#ifdef CONFIG_VM_EVENT .enable_msr_interception = vmx_enable_msr_interception, +#endif #ifdef CONFIG_ALTP2M .altp2m_vcpu_update_p2m = vmx_vcpu_update_eptp, .altp2m_vcpu_update_vmfunc_ve = vmx_vcpu_update_vmfunc_ve, @@ -XXX,XX +XXX,XX @@ const struct hvm_function_table * __init start_vmx(void) vmx_function_table.caps.singlestep = cpu_has_monitor_trap_flag; +#ifdef CONFIG_VM_EVENT if ( cpu_has_vmx_dt_exiting ) vmx_function_table.set_descriptor_access_exiting = vmx_set_descriptor_access_exiting; +#endif /* * Do not enable EPT when (!cpu_has_vmx_pat), to prevent security hole @@ -XXX,XX +XXX,XX @@ void __init vmx_fill_funcs(void) if ( !cpu_has_xen_ibt ) return; +#ifdef CONFIG_VM_EVENT vmx_function_table.set_descriptor_access_exiting = vmx_set_descriptor_access_exiting; +#endif vmx_function_table.update_eoi_exit_bitmap = vmx_update_eoi_exit_bitmap; vmx_function_table.process_isr = vmx_process_isr; diff --git a/xen/arch/x86/include/asm/hvm/hvm.h b/xen/arch/x86/include/asm/hvm/hvm.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/hvm/hvm.h +++ b/xen/arch/x86/include/asm/hvm/hvm.h @@ -XXX,XX +XXX,XX @@ struct hvm_function_table { void (*handle_cd)(struct vcpu *v, unsigned long value); void (*set_info_guest)(struct vcpu *v); void (*set_rdtsc_exiting)(struct vcpu *v, bool enable); + +#ifdef CONFIG_VM_EVENT void (*set_descriptor_access_exiting)(struct vcpu *v, bool enable); + void (*enable_msr_interception)(struct domain *d, uint32_t msr); +#endif /* Nested HVM */ int (*nhvm_vcpu_initialise)(struct vcpu *v); @@ -XXX,XX +XXX,XX @@ struct hvm_function_table { paddr_t *L1_gpa, unsigned int *page_order, uint8_t *p2m_acc, struct npfec npfec); - void (*enable_msr_interception)(struct domain *d, uint32_t msr); - #ifdef CONFIG_ALTP2M /* Alternate p2m */ void (*altp2m_vcpu_update_p2m)(struct vcpu *v); @@ -XXX,XX +XXX,XX @@ static inline bool using_svm(void) #define hvm_long_mode_active(v) (!!((v)->arch.hvm.guest_efer & EFER_LMA)) +#ifdef CONFIG_VM_EVENT static inline bool hvm_has_set_descriptor_access_exiting(void) { return hvm_funcs.set_descriptor_access_exiting; } +static inline void hvm_enable_msr_interception(struct domain *d, uint32_t msr) +{ + alternative_vcall(hvm_funcs.enable_msr_interception, d, msr); +} +#endif /* CONFIG_VM_EVENT */ + static inline void hvm_domain_creation_finished(struct domain *d) { if ( hvm_funcs.domain_creation_finished ) @@ -XXX,XX +XXX,XX @@ static inline int nhvm_hap_walk_L1_p2m( v, L2_gpa, L1_gpa, page_order, p2m_acc, npfec); } -static inline void hvm_enable_msr_interception(struct domain *d, uint32_t msr) -{ - alternative_vcall(hvm_funcs.enable_msr_interception, d, msr); -} - static inline bool hvm_is_singlestep_supported(void) { return hvm_funcs.caps.singlestep; diff --git a/xen/arch/x86/include/asm/monitor.h b/xen/arch/x86/include/asm/monitor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/monitor.h +++ b/xen/arch/x86/include/asm/monitor.h @@ -XXX,XX +XXX,XX @@ int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop) return rc; } +#ifdef CONFIG_VM_EVENT static inline uint32_t arch_monitor_get_capabilities(struct domain *d) { uint32_t capabilities = 0; @@ -XXX,XX +XXX,XX @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d) return capabilities; } +#endif /* CONFIG_VM_EVENT */ int arch_monitor_domctl_event(struct domain *d, struct xen_domctl_monitor_op *mop); @@ -XXX,XX +XXX,XX @@ static inline void arch_monitor_cleanup_domain(struct domain *d) {} #endif +#ifdef CONFIG_VM_EVENT bool monitored_msr(const struct domain *d, u32 msr); +#else +static inline bool monitored_msr(const struct domain *d, u32 msr) +{ + return false; +} +#endif bool monitored_msr_onchangeonly(const struct domain *d, u32 msr); #endif /* __ASM_X86_MONITOR_H__ */ -- 2.34.1
Memory access and ALTP2M are two seperate features, while both depending on helper xenmem_access_to_p2m_access(). So it betters lives in common p2m.c, other than mem_access.c which will be compiled out when VM_EVENT=n && ALTP2M=y. Guard xenmem_access_to_p2m_access() with VM_EVENT || ALTP2M, otherwise it will become unreachable when both VM_EVENT=n and ALTP2M=n, and hence violating Misra rule 2.1 We also need to move declaration from mem_access.h to p2m-common.h An extra blank line is inserted after each case-block to correct coding style at the same time. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> Acked-by: Jan Beulich <jbeulich@suse.com> --- v1 -> v3: - Guard xenmem_access_to_p2m_access() with VM_EVENT || ALTP2M - Move declaration from mem_access.h to p2m-common.h - refine commit message --- xen/arch/x86/mm/mem_access.c | 36 -------------------------------- xen/arch/x86/mm/p2m.c | 40 ++++++++++++++++++++++++++++++++++++ xen/include/xen/mem_access.h | 5 ----- xen/include/xen/p2m-common.h | 3 +++ 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/mem_access.c +++ b/xen/arch/x86/mm/mem_access.c @@ -XXX,XX +XXX,XX @@ static int set_mem_access(struct domain *d, struct p2m_domain *p2m, return rc; } -bool xenmem_access_to_p2m_access(const struct p2m_domain *p2m, - xenmem_access_t xaccess, - p2m_access_t *paccess) -{ - static const p2m_access_t memaccess[] = { -#define ACCESS(ac) [XENMEM_access_##ac] = p2m_access_##ac - ACCESS(n), - ACCESS(r), - ACCESS(w), - ACCESS(rw), - ACCESS(x), - ACCESS(rx), - ACCESS(wx), - ACCESS(rwx), - ACCESS(rx2rw), - ACCESS(n2rwx), - ACCESS(r_pw), -#undef ACCESS - }; - - switch ( xaccess ) - { - case 0 ... ARRAY_SIZE(memaccess) - 1: - xaccess = array_index_nospec(xaccess, ARRAY_SIZE(memaccess)); - *paccess = memaccess[xaccess]; - break; - case XENMEM_access_default: - *paccess = p2m->default_access; - break; - default: - return false; - } - - return true; -} - /* * Set access type for a region of gfns. * If gfn == INVALID_GFN, sets the default access type. diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_log_dirty_range(struct domain *d, unsigned long begin_pfn, guest_flush_tlb_mask(d, d->dirty_cpumask); } +#if defined(CONFIG_VM_EVENT) || defined(CONFIG_ALTP2M) +bool xenmem_access_to_p2m_access(const struct p2m_domain *p2m, + xenmem_access_t xaccess, + p2m_access_t *paccess) +{ + static const p2m_access_t memaccess[] = { +#define ACCESS(ac) [XENMEM_access_##ac] = p2m_access_##ac + ACCESS(n), + ACCESS(r), + ACCESS(w), + ACCESS(rw), + ACCESS(x), + ACCESS(rx), + ACCESS(wx), + ACCESS(rwx), + ACCESS(rx2rw), + ACCESS(n2rwx), + ACCESS(r_pw), +#undef ACCESS + }; + + switch ( xaccess ) + { + case 0 ... ARRAY_SIZE(memaccess) - 1: + xaccess = array_index_nospec(xaccess, ARRAY_SIZE(memaccess)); + *paccess = memaccess[xaccess]; + break; + + case XENMEM_access_default: + *paccess = p2m->default_access; + break; + + default: + return false; + } + + return true; +} +#endif /* VM_EVENT || ALTP2M */ + /* * Local variables: * mode: C diff --git a/xen/include/xen/mem_access.h b/xen/include/xen/mem_access.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/mem_access.h +++ b/xen/include/xen/mem_access.h @@ -XXX,XX +XXX,XX @@ typedef enum { /* NOTE: Assumed to be only 4 bits right now on x86. */ } p2m_access_t; -struct p2m_domain; -bool xenmem_access_to_p2m_access(const struct p2m_domain *p2m, - xenmem_access_t xaccess, - p2m_access_t *paccess); - /* * Set access type for a region of gfns. * If gfn == INVALID_GFN, sets the default access type. diff --git a/xen/include/xen/p2m-common.h b/xen/include/xen/p2m-common.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/p2m-common.h +++ b/xen/include/xen/p2m-common.h @@ -XXX,XX +XXX,XX @@ int __must_check check_get_page_from_gfn(struct domain *d, gfn_t gfn, bool readonly, p2m_type_t *p2mt_p, struct page_info **page_p); +bool xenmem_access_to_p2m_access(const struct p2m_domain *p2m, + xenmem_access_t xaccess, + p2m_access_t *paccess); #endif /* _XEN_P2M_COMMON_H */ -- 2.34.1
Feature memory access is based on vm event subsystem, and it could be disabled in the future. So a few switch-blocks in do_altp2m_op() need vm_event_is_enabled() condition check to pass compilation when ALTP2M=y and VM_EVENT=n(, hence MEM_ACCESS=n), like HVMOP_altp2m_set_mem_access, etc. Function p2m_mem_access_check() still needs stub when VM_EVENT=n to pass compilation. Although local variable "req_ptr" still remains NULL throughout its lifetime, with the change of NULL assignment, we will face runtime undefined error only when CONFIG_USBAN is on. So we strengthen the condition check via adding vm_event_is_enabled() for the special case. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> Acked-by: Jan Beulich <jbeulich@suse.com> --- v1 -> v3: - a comment next to the excessive condition - use vm_event_is_enabled() instead - avoid heavy churn by using the inverted condition plus break --- v3 - v4: - refine comment --- xen/arch/x86/hvm/hvm.c | 26 +++++++++++++++++++++++++- xen/arch/x86/include/asm/mem_access.h | 10 ++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ #include <asm/i387.h> #include <asm/mc146818rtc.h> #include <asm/mce.h> +#include <asm/mem_access.h> #include <asm/monitor.h> #include <asm/msr.h> #include <asm/mtrr.h> @@ -XXX,XX +XXX,XX @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, #endif } - if ( req_ptr ) + /* + * req_ptr being constant NULL when !CONFIG_VM_EVENT, CONFIG_UBSAN=y + * builds have been observed to still hit undefined-ness at runtime. + * Hence do a seemingly redundant vm_event_is_enabled() check here. + */ + if ( req_ptr && vm_event_is_enabled(curr) ) { if ( monitor_traps(curr, sync, req_ptr) < 0 ) rc = 0; @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( break; case HVMOP_altp2m_set_mem_access: + if ( !vm_event_is_enabled(current) ) + { + rc = -EOPNOTSUPP; + break; + } + if ( a.u.mem_access.pad ) rc = -EINVAL; else @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( break; case HVMOP_altp2m_set_mem_access_multi: + if ( !vm_event_is_enabled(current) ) + { + rc = -EOPNOTSUPP; + break; + } + if ( a.u.set_mem_access_multi.pad || a.u.set_mem_access_multi.opaque > a.u.set_mem_access_multi.nr ) { @@ -XXX,XX +XXX,XX @@ static int do_altp2m_op( break; case HVMOP_altp2m_get_mem_access: + if ( !vm_event_is_enabled(current) ) + { + rc = -EOPNOTSUPP; + break; + } + if ( a.u.mem_access.pad ) rc = -EINVAL; else diff --git a/xen/arch/x86/include/asm/mem_access.h b/xen/arch/x86/include/asm/mem_access.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/include/asm/mem_access.h +++ b/xen/arch/x86/include/asm/mem_access.h @@ -XXX,XX +XXX,XX @@ #ifndef __ASM_X86_MEM_ACCESS_H__ #define __ASM_X86_MEM_ACCESS_H__ +#ifdef CONFIG_VM_EVENT /* * Setup vm_event request based on the access (gla is -1ull if not available). * Handles the rw2rx conversion. Boolean return value indicates if event type @@ -XXX,XX +XXX,XX @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla, struct npfec npfec, struct vm_event_st **req_ptr); +#else +static inline bool p2m_mem_access_check(paddr_t gpa, unsigned long gla, + struct npfec npfec, + struct vm_event_st **req_ptr) +{ + *req_ptr = NULL; + return false; +} +#endif /* CONFIG_VM_EVENT */ /* Check for emulation and mark vcpu for skipping one instruction * upon rescheduling if required. */ -- 2.34.1
File hvm/vm_event.c and x86/vm_event.c are the extend to vm_event handling routines, and its compilation shall be guarded by CONFIG_VM_EVENT too. Although CONFIG_VM_EVENT is right now forcibly enabled on x86 via MEM_ACCESS_ALWAYS_ON, we could disable it through disabling CONFIG_MGMT_HYPERCALLS later. So we remove MEM_ACCESS_ALWAYS_ON and make VM_EVENT=y on default only on x86 to retain the same. The following functions are developed on the basis of vm event framework, or only invoked by vm_event.c, so they all shall be wrapped with CONFIG_VM_EVENT (otherwise they will become unreachable and violate Misra rule 2.1 when VM_EVENT=n): - hvm_toggle_singlestep - hvm_fast_singlestep - hvm_emulate_one_vm_event - hvmemul_write{,cmpxchg,rep_ins,rep_outs,rep_movs,rep_stos,read_io,write_io}_discard And Function vm_event_check_ring() needs stub to pass compilation when VM_EVENT=n. Signed-off-by: Penny Zheng <Penny.Zheng@amd.com> Acked-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com> --- As the last commit, plz be commited either in the last, or shall be commited together with prereq commit 8d708e98ad, 8b4147009f, dbfccb5918, ae931f63a0, 37ec0e2b75. --- xen/arch/x86/Makefile | 2 +- xen/arch/x86/hvm/Kconfig | 1 - xen/arch/x86/hvm/Makefile | 2 +- xen/arch/x86/hvm/emulate.c | 58 ++++++++++++++++++++------------------ xen/arch/x86/hvm/hvm.c | 2 ++ xen/common/Kconfig | 7 ++--- xen/include/xen/vm_event.h | 7 +++++ 7 files changed, 44 insertions(+), 35 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_INTEL) += tsx.o obj-y += x86_emulate.o obj-$(CONFIG_TBOOT) += tboot.o obj-y += hpet.o -obj-y += vm_event.o +obj-$(CONFIG_VM_EVENT) += vm_event.o obj-y += xstate.o ifneq ($(CONFIG_PV_SHIM_EXCLUSIVE),y) diff --git a/xen/arch/x86/hvm/Kconfig b/xen/arch/x86/hvm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/Kconfig +++ b/xen/arch/x86/hvm/Kconfig @@ -XXX,XX +XXX,XX @@ menuconfig HVM default !PV_SHIM select COMPAT select IOREQ_SERVER - select MEM_ACCESS_ALWAYS_ON help Interfaces to support HVM domains. HVM domains require hardware virtualisation extensions (e.g. Intel VT-x, AMD SVM), but can boot diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += save.o obj-y += stdvga.o obj-y += vioapic.o obj-y += vlapic.o -obj-y += vm_event.o +obj-$(CONFIG_VM_EVENT) += vm_event.o obj-y += vmsi.o obj-y += vpic.o obj-y += vpt.o diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -XXX,XX +XXX,XX @@ static int cf_check hvmemul_blk( return rc; } +#ifdef CONFIG_VM_EVENT static int cf_check hvmemul_write_discard( enum x86_segment seg, unsigned long offset, @@ -XXX,XX +XXX,XX @@ static int cf_check hvmemul_cache_op_discard( { return X86EMUL_OKAY; } +#endif /* CONFIG_VM_EVENT */ static int cf_check hvmemul_cmpxchg( enum x86_segment seg, @@ -XXX,XX +XXX,XX @@ static const struct x86_emulate_ops hvm_emulate_ops = { .vmfunc = hvmemul_vmfunc, }; -static const struct x86_emulate_ops hvm_emulate_ops_no_write = { - .read = hvmemul_read, - .insn_fetch = hvmemul_insn_fetch, - .write = hvmemul_write_discard, - .cmpxchg = hvmemul_cmpxchg_discard, - .rep_ins = hvmemul_rep_ins_discard, - .rep_outs = hvmemul_rep_outs_discard, - .rep_movs = hvmemul_rep_movs_discard, - .rep_stos = hvmemul_rep_stos_discard, - .read_segment = hvmemul_read_segment, - .write_segment = hvmemul_write_segment, - .read_io = hvmemul_read_io_discard, - .write_io = hvmemul_write_io_discard, - .read_cr = hvmemul_read_cr, - .write_cr = hvmemul_write_cr, - .read_xcr = hvmemul_read_xcr, - .write_xcr = hvmemul_write_xcr, - .read_msr = hvmemul_read_msr, - .write_msr = hvmemul_write_msr_discard, - .cache_op = hvmemul_cache_op_discard, - .tlb_op = hvmemul_tlb_op, - .cpuid = x86emul_cpuid, - .get_fpu = hvmemul_get_fpu, - .put_fpu = hvmemul_put_fpu, - .vmfunc = hvmemul_vmfunc, -}; - /* * Note that passing VIO_no_completion into this function serves as kind * of (but not fully) an "auto select completion" indicator. When there's @@ -XXX,XX +XXX,XX @@ int hvm_emulate_one( return _hvm_emulate_one(hvmemul_ctxt, &hvm_emulate_ops, completion); } +#ifdef CONFIG_VM_EVENT +static const struct x86_emulate_ops hvm_emulate_ops_no_write = { + .read = hvmemul_read, + .insn_fetch = hvmemul_insn_fetch, + .write = hvmemul_write_discard, + .cmpxchg = hvmemul_cmpxchg_discard, + .rep_ins = hvmemul_rep_ins_discard, + .rep_outs = hvmemul_rep_outs_discard, + .rep_movs = hvmemul_rep_movs_discard, + .rep_stos = hvmemul_rep_stos_discard, + .read_segment = hvmemul_read_segment, + .write_segment = hvmemul_write_segment, + .read_io = hvmemul_read_io_discard, + .write_io = hvmemul_write_io_discard, + .read_cr = hvmemul_read_cr, + .write_cr = hvmemul_write_cr, + .read_xcr = hvmemul_read_xcr, + .write_xcr = hvmemul_write_xcr, + .read_msr = hvmemul_read_msr, + .write_msr = hvmemul_write_msr_discard, + .cache_op = hvmemul_cache_op_discard, + .tlb_op = hvmemul_tlb_op, + .cpuid = x86emul_cpuid, + .get_fpu = hvmemul_get_fpu, + .put_fpu = hvmemul_put_fpu, + .vmfunc = hvmemul_vmfunc, +}; + void hvm_emulate_one_vm_event(enum emul_kind kind, unsigned int trapnr, unsigned int errcode) { @@ -XXX,XX +XXX,XX @@ void hvm_emulate_one_vm_event(enum emul_kind kind, unsigned int trapnr, hvm_emulate_writeback(&ctx); } +#endif /* CONFIG_VM_EVENT */ void hvm_emulate_init_once( struct hvm_emulate_ctxt *hvmemul_ctxt, diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -XXX,XX +XXX,XX @@ int hvm_debug_op(struct vcpu *v, int32_t op) return rc; } +#ifdef CONFIG_VM_EVENT void hvm_toggle_singlestep(struct vcpu *v) { ASSERT(atomic_read(&v->pause_count)); @@ -XXX,XX +XXX,XX @@ void hvm_fast_singlestep(struct vcpu *v, uint16_t p2midx) v->arch.hvm.fast_single_step.p2midx = p2midx; } #endif +#endif /* CONFIG_VM_EVENT */ /* * Segment caches in VMCB/VMCS are inconsistent about which bits are checked, diff --git a/xen/common/Kconfig b/xen/common/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -XXX,XX +XXX,XX @@ config HAS_VMAP config LIBFDT bool -config MEM_ACCESS_ALWAYS_ON - bool - config VM_EVENT - def_bool MEM_ACCESS_ALWAYS_ON - prompt "Memory Access and VM events" if !MEM_ACCESS_ALWAYS_ON + bool "Memory Access and VM events" depends on HVM + default X86 help Framework to configure memory access types for guests and receive diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/xen/vm_event.h +++ b/xen/include/xen/vm_event.h @@ -XXX,XX +XXX,XX @@ struct vm_event_domain }; /* Returns whether a ring has been set up */ +#ifdef CONFIG_VM_EVENT bool vm_event_check_ring(struct vm_event_domain *ved); +#else +static inline bool vm_event_check_ring(struct vm_event_domain *ved) +{ + return false; +} +#endif /* CONFIG_VM_EVENT */ /* Returns 0 on success, -ENOSYS if there is no ring, -EBUSY if there is no * available space and the caller is a foreign domain. If the guest itself -- 2.34.1