[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v5 24/28] xen/x86: allow HVM guests to use hypercalls to bring up vCPUs
Allow the usage of the VCPUOP_initialise, VCPUOP_up, VCPUOP_down and VCPUOP_is_up hypercalls from HVM guests. This patch introduces a new structure (vcpu_hvm_context) that should be used in conjuction with the VCPUOP_initialise hypercall in order to initialize vCPUs for HVM guests. Signed-off-by: Roger Pau Monnà <roger.pau@xxxxxxxxxx> Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Cc: Ian Campbell <ian.campbell@xxxxxxxxxx> Cc: Stefano Stabellini <stefano.stabellini@xxxxxxxxxx> --- Changes since v4: - Don't assume mode is 64B, add an explicit check. - Don't set TF_kernel_mode, it is only needed for PV guests. - Don't set CR0_ET unconditionally. --- xen/arch/arm/domain.c | 24 ++++++ xen/arch/x86/domain.c | 164 +++++++++++++++++++++++++++++++++++++ xen/arch/x86/hvm/hvm.c | 8 ++ xen/common/domain.c | 16 +--- xen/include/public/hvm/hvm_vcpu.h | 168 ++++++++++++++++++++++++++++++++++++++ xen/include/xen/domain.h | 2 + 6 files changed, 367 insertions(+), 15 deletions(-) create mode 100644 xen/include/public/hvm/hvm_vcpu.h diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index b2bfc7d..b20035d 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -752,6 +752,30 @@ int arch_set_info_guest( return 0; } +int arch_initialize_vcpu(struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg) +{ + struct vcpu_guest_context *ctxt; + struct domain *d = current->domain; + int rc; + + if ( (ctxt = alloc_vcpu_guest_context()) == NULL ) + return -ENOMEM; + + if ( copy_from_guest(ctxt, arg, 1) ) + { + free_vcpu_guest_context(ctxt); + return -EFAULT; + } + + domain_lock(d); + rc = v->is_initialised ? -EEXIST : arch_set_info_guest(v, ctxt); + domain_unlock(d); + + free_vcpu_guest_context(ctxt); + + return rc; +} + int arch_vcpu_reset(struct vcpu *v) { vcpu_end_shutdown_deferral(v); diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 8fe95f7..23ff14c 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -37,6 +37,7 @@ #include <xen/wait.h> #include <xen/guest_access.h> #include <public/sysctl.h> +#include <public/hvm/hvm_vcpu.h> #include <asm/regs.h> #include <asm/mc146818rtc.h> #include <asm/system.h> @@ -1140,6 +1141,169 @@ int arch_set_info_guest( #undef c } +/* Called by VCPUOP_initialise for HVM guests. */ +static int arch_set_info_hvm_guest(struct vcpu *v, vcpu_hvm_context_t *ctx) +{ + struct segment_register seg; + +#define get_context_seg(ctx, seg, f) \ + (ctx)->mode == VCPU_HVM_MODE_16B ? (ctx)->cpu_regs.x86_16.seg##_##f : \ + (ctx)->mode == VCPU_HVM_MODE_32B ? (ctx)->cpu_regs.x86_32.seg##_##f : \ + (ctx)->mode == VCPU_HVM_MODE_64B ? (ctx)->cpu_regs.x86_64.seg##_##f : \ + ({ panic("Invalid vCPU mode %u requested\n", (ctx)->mode); 0; }) + +#define get_context_gpr(ctx, gpr) \ + (ctx)->mode == VCPU_HVM_MODE_16B ? (ctx)->cpu_regs.x86_16.gpr : \ + (ctx)->mode == VCPU_HVM_MODE_32B ? (ctx)->cpu_regs.x86_32.e##gpr : \ + (ctx)->mode == VCPU_HVM_MODE_64B ? (ctx)->cpu_regs.x86_64.r##gpr : \ + ({ panic("Invalid vCPU mode %u requested\n", (ctx)->mode); 0; }) + +#define get_context_field(ctx, field) \ + (ctx)->mode == VCPU_HVM_MODE_16B ? (ctx)->cpu_regs.x86_16.field : \ + (ctx)->mode == VCPU_HVM_MODE_32B ? (ctx)->cpu_regs.x86_32.field : \ + (ctx)->mode == VCPU_HVM_MODE_64B ? (ctx)->cpu_regs.x86_64.field : \ + ({ panic("Invalid vCPU mode %u requested\n", (ctx)->mode); 0; }) + + if ( ctx->mode != VCPU_HVM_MODE_16B && ctx->mode != VCPU_HVM_MODE_32B && + ctx->mode != VCPU_HVM_MODE_64B ) + return -EINVAL; + + memset(&seg, 0, sizeof(seg)); + + if ( !paging_mode_hap(v->domain) ) + v->arch.guest_table = pagetable_null(); + + v->arch.user_regs.rax = get_context_gpr(ctx, ax); + v->arch.user_regs.rcx = get_context_gpr(ctx, cx); + v->arch.user_regs.rdx = get_context_gpr(ctx, dx); + v->arch.user_regs.rbx = get_context_gpr(ctx, bx); + v->arch.user_regs.rsp = get_context_gpr(ctx, sp); + v->arch.user_regs.rbp = get_context_gpr(ctx, bp); + v->arch.user_regs.rsi = get_context_gpr(ctx, si); + v->arch.user_regs.rdi = get_context_gpr(ctx, di); + v->arch.user_regs.rip = get_context_gpr(ctx, ip); + v->arch.user_regs.rflags = get_context_gpr(ctx, flags); + + v->arch.hvm_vcpu.guest_cr[0] = get_context_field(ctx, cr0); + hvm_update_guest_cr(v, 0); + v->arch.hvm_vcpu.guest_cr[4] = get_context_field(ctx, cr4); + hvm_update_guest_cr(v, 4); + + switch ( ctx->mode ) + { + case VCPU_HVM_MODE_32B: + v->arch.hvm_vcpu.guest_efer = ctx->cpu_regs.x86_32.efer; + hvm_update_guest_efer(v); + v->arch.hvm_vcpu.guest_cr[3] = ctx->cpu_regs.x86_32.cr3; + hvm_update_guest_cr(v, 3); + break; + + case VCPU_HVM_MODE_64B: + v->arch.user_regs.r8 = ctx->cpu_regs.x86_64.r8; + v->arch.user_regs.r9 = ctx->cpu_regs.x86_64.r9; + v->arch.user_regs.r10 = ctx->cpu_regs.x86_64.r10; + v->arch.user_regs.r11 = ctx->cpu_regs.x86_64.r11; + v->arch.user_regs.r12 = ctx->cpu_regs.x86_64.r12; + v->arch.user_regs.r13 = ctx->cpu_regs.x86_64.r13; + v->arch.user_regs.r14 = ctx->cpu_regs.x86_64.r14; + v->arch.user_regs.r15 = ctx->cpu_regs.x86_64.r15; + v->arch.hvm_vcpu.guest_efer = ctx->cpu_regs.x86_64.efer; + hvm_update_guest_efer(v); + v->arch.hvm_vcpu.guest_cr[3] = ctx->cpu_regs.x86_64.cr3; + hvm_update_guest_cr(v, 3); + break; + } + + if ( hvm_paging_enabled(v) && !paging_mode_hap(v->domain) ) + { + /* Shadow-mode CR3 change. Check PDBR and update refcounts. */ + struct page_info *page = get_page_from_gfn(v->domain, + v->arch.hvm_vcpu.guest_cr[3] >> PAGE_SHIFT, + NULL, P2M_ALLOC); + if ( !page ) + { + gdprintk(XENLOG_ERR, "Invalid CR3\n"); + domain_crash(v->domain); + return -EINVAL; + } + + v->arch.guest_table = pagetable_from_page(page); + } + + seg.base = get_context_seg(ctx, cs, base); + seg.limit = get_context_seg(ctx, cs, limit); + seg.attr.bytes = get_context_seg(ctx, cs, ar); + hvm_set_segment_register(v, x86_seg_cs, &seg); + + seg.base = get_context_seg(ctx, ds, base); + seg.limit = get_context_seg(ctx, ds, limit); + seg.attr.bytes = get_context_seg(ctx, ds, ar); + hvm_set_segment_register(v, x86_seg_ds, &seg); + + seg.base = get_context_seg(ctx, ss, base); + seg.limit = get_context_seg(ctx, ss, limit); + seg.attr.bytes = get_context_seg(ctx, ss, ar); + hvm_set_segment_register(v, x86_seg_ss, &seg); + + seg.base = get_context_seg(ctx, tr, base); + seg.limit = get_context_seg(ctx, tr, limit); + seg.attr.bytes = get_context_seg(ctx, tr, ar); + hvm_set_segment_register(v, x86_seg_tr, &seg); + + /* Sync AP's TSC with BSP's. */ + v->arch.hvm_vcpu.cache_tsc_offset = + v->domain->vcpu[0]->arch.hvm_vcpu.cache_tsc_offset; + hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset, + v->domain->arch.hvm_domain.sync_tsc); + + v->arch.hvm_vcpu.msr_tsc_adjust = 0; + + paging_update_paging_modes(v); + + v->is_initialised = 1; + set_bit(_VPF_down, &v->pause_flags); + + return 0; +#undef get_context_field +#undef get_context_gpr +#undef get_context_seg +} + +int arch_initialize_vcpu(struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg) +{ + struct vcpu_guest_context *ctxt; + struct vcpu_hvm_context hvm_ctx; + struct domain *d = current->domain; + int rc; + + if ( is_hvm_vcpu(v) ) + { + if ( copy_from_guest(&hvm_ctx, arg, 1) ) + return -EFAULT; + + domain_lock(d); + rc = v->is_initialised ? -EEXIST : arch_set_info_hvm_guest(v, &hvm_ctx); + domain_unlock(d); + } else { + if ( (ctxt = alloc_vcpu_guest_context()) == NULL ) + return -ENOMEM; + + if ( copy_from_guest(ctxt, arg, 1) ) + { + free_vcpu_guest_context(ctxt); + return -EFAULT; + } + + domain_lock(d); + rc = v->is_initialised ? -EEXIST : arch_set_info_guest(v, ctxt); + domain_unlock(d); + + free_vcpu_guest_context(ctxt); + } + + return rc; +} + int arch_vcpu_reset(struct vcpu *v) { if ( is_pv_vcpu(v) ) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 1640b58..8856c72 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -4980,6 +4980,10 @@ static long hvm_vcpu_op( case VCPUOP_stop_singleshot_timer: case VCPUOP_register_vcpu_info: case VCPUOP_register_vcpu_time_memory_area: + case VCPUOP_initialise: + case VCPUOP_up: + case VCPUOP_down: + case VCPUOP_is_up: rc = do_vcpu_op(cmd, vcpuid, arg); break; default: @@ -5038,6 +5042,10 @@ static long hvm_vcpu_op_compat32( case VCPUOP_stop_singleshot_timer: case VCPUOP_register_vcpu_info: case VCPUOP_register_vcpu_time_memory_area: + case VCPUOP_initialise: + case VCPUOP_up: + case VCPUOP_down: + case VCPUOP_is_up: rc = compat_vcpu_op(cmd, vcpuid, arg); break; default: diff --git a/xen/common/domain.c b/xen/common/domain.c index 1b9fcfc..f97e7f4 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -1173,7 +1173,6 @@ long do_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg) { struct domain *d = current->domain; struct vcpu *v; - struct vcpu_guest_context *ctxt; long rc = 0; if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL ) @@ -1185,20 +1184,7 @@ long do_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg) if ( v->vcpu_info == &dummy_vcpu_info ) return -EINVAL; - if ( (ctxt = alloc_vcpu_guest_context()) == NULL ) - return -ENOMEM; - - if ( copy_from_guest(ctxt, arg, 1) ) - { - free_vcpu_guest_context(ctxt); - return -EFAULT; - } - - domain_lock(d); - rc = v->is_initialised ? -EEXIST : arch_set_info_guest(v, ctxt); - domain_unlock(d); - - free_vcpu_guest_context(ctxt); + rc = arch_initialize_vcpu(v, arg); if ( rc == -ERESTART ) rc = hypercall_create_continuation(__HYPERVISOR_vcpu_op, "iuh", diff --git a/xen/include/public/hvm/hvm_vcpu.h b/xen/include/public/hvm/hvm_vcpu.h new file mode 100644 index 0000000..db86edd --- /dev/null +++ b/xen/include/public/hvm/hvm_vcpu.h @@ -0,0 +1,168 @@ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __XEN_PUBLIC_HVM_HVM_VCPU_H__ +#define __XEN_PUBLIC_HVM_HVM_VCPU_H__ + +#include "../xen.h" + +struct vcpu_hvm_x86_16 { + uint16_t ax; + uint16_t cx; + uint16_t dx; + uint16_t bx; + uint16_t sp; + uint16_t bp; + uint16_t si; + uint16_t di; + uint16_t ip; + uint16_t flags; + + uint32_t cr0; + uint32_t cr4; + + uint32_t cs_base; + uint32_t ds_base; + uint32_t ss_base; + uint32_t tr_base; + uint32_t cs_limit; + uint32_t ds_limit; + uint32_t ss_limit; + uint32_t tr_limit; + uint16_t cs_ar; + uint16_t ds_ar; + uint16_t ss_ar; + uint16_t tr_ar; +}; + +struct vcpu_hvm_x86_32 { + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t eip; + uint16_t eflags; + + uint32_t cr0; + uint32_t cr3; + uint32_t cr4; + uint64_t efer; + + uint32_t cs_base; + uint32_t ds_base; + uint32_t ss_base; + uint32_t tr_base; + uint32_t cs_limit; + uint32_t ds_limit; + uint32_t ss_limit; + uint32_t tr_limit; + uint16_t cs_ar; + uint16_t ds_ar; + uint16_t ss_ar; + uint16_t tr_ar; +}; + +struct vcpu_hvm_x86_64 { + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + uint64_t rsp; + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; + uint64_t rflags; + + uint64_t cr0; + uint64_t cr3; + uint64_t cr4; + uint64_t efer; + + uint32_t cs_base; + uint32_t ds_base; + uint32_t ss_base; + uint32_t tr_base; + uint32_t cs_limit; + uint32_t ds_limit; + uint32_t ss_limit; + uint32_t tr_limit; + uint16_t cs_ar; + uint16_t ds_ar; + uint16_t ss_ar; + uint16_t tr_ar; +}; + +/* + * The layout of the _ar fields of the segment registers is the + * following: + * + * Bits [0,3]: type (bits 40-43). + * Bit 4: s (descriptor type, bit 44). + * Bit [5,6]: dpl (descriptor privilege level, bits 45-46). + * Bit 7: p (segment-present, bit 47). + * Bit 8: avl (available for system software, bit 52). + * Bit 9: l (64-bit code segment, bit 53). + * Bit 10: db (meaning depends on the segment, bit 54). + * Bit 11: g (granularity, bit 55) + * + * A more complete description of the meaning of this fields can be + * obtained from the Intel SDM, Volume 3, section 3.4.5. + */ + +struct vcpu_hvm_context { +#define VCPU_HVM_MODE_16B 0 /* 16bit fields of the structure will be used. */ +#define VCPU_HVM_MODE_32B 1 /* 32bit fields of the structure will be used. */ +#define VCPU_HVM_MODE_64B 2 /* 64bit fields of the structure will be used. */ + uint32_t mode; + + /* CPU registers. */ + union { + struct vcpu_hvm_x86_16 x86_16; + struct vcpu_hvm_x86_32 x86_32; + struct vcpu_hvm_x86_64 x86_64; + } cpu_regs; +}; +typedef struct vcpu_hvm_context vcpu_hvm_context_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_hvm_context_t); + +#endif /* __XEN_PUBLIC_HVM_HVM_VCPU_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h index 848db8a..21690be 100644 --- a/xen/include/xen/domain.h +++ b/xen/include/xen/domain.h @@ -68,6 +68,8 @@ void arch_domain_unpause(struct domain *d); int arch_set_info_guest(struct vcpu *, vcpu_guest_context_u); void arch_get_info_guest(struct vcpu *, vcpu_guest_context_u); +int arch_initialize_vcpu(struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg); + int domain_relinquish_resources(struct domain *d); void dump_pageframe_info(struct domain *d); -- 1.9.5 (Apple Git-50.3) _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |