[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86/hvm: hypercall adjustments
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Date 1179221308 -3600 # Node ID f4390e34ad120afd4f7d65789d2394b7c6dfd7a5 # Parent eb027b704dc55bb7f6e01a4b068c1ac407331ec1 x86/hvm: hypercall adjustments - share more code between 32- and 64-bit variants - properly handle continuations for 32-bit guests on 64-bit hv - properly handle preemption (this must *not* rely on regs->eip, as - other code may overwrite the value there by calling - hvm_store_cpu_guest_regs() - deny hypercall access when called from guest in vm86 mode, which requires that ???_guest_x86_mode() make real and vm86 modes distinguishable Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx> --- xen/arch/x86/domain.c | 9 ++ xen/arch/x86/hvm/hvm.c | 121 +++++++++++++++++----------------------- xen/arch/x86/hvm/platform.c | 3 xen/arch/x86/hvm/svm/svm.c | 24 ++----- xen/arch/x86/hvm/vmx/vmx.c | 29 ++------- xen/include/asm-x86/hypercall.h | 9 ++ 6 files changed, 90 insertions(+), 105 deletions(-) diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Tue May 15 10:13:11 2007 +0100 +++ b/xen/arch/x86/domain.c Tue May 15 10:28:28 2007 +0100 @@ -38,6 +38,7 @@ #include <asm/mpspec.h> #include <asm/ldt.h> #include <asm/paging.h> +#include <asm/hypercall.h> #include <asm/hvm/hvm.h> #include <asm/hvm/support.h> #include <asm/msr.h> @@ -1231,6 +1232,8 @@ void sync_vcpu_execstate(struct vcpu *v) __arg; \ }) +DEFINE_PER_CPU(char, hc_preempted); + unsigned long hypercall_create_continuation( unsigned int op, const char *format, ...) { @@ -1262,7 +1265,9 @@ unsigned long hypercall_create_continuat regs->eip -= 2; /* re-execute 'syscall' / 'int 0x82' */ #ifdef __x86_64__ - if ( !is_pv_32on64_domain(current->domain) ) + if ( !is_hvm_vcpu(current) ? + !is_pv_32on64_vcpu(current) : + (hvm_guest_x86_mode(current) == 8) ) { for ( i = 0; *p != '\0'; i++ ) { @@ -1298,6 +1303,8 @@ unsigned long hypercall_create_continuat } } } + + this_cpu(hc_preempted) = 1; } va_end(args); diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Tue May 15 10:13:11 2007 +0100 +++ b/xen/arch/x86/hvm/hvm.c Tue May 15 10:28:28 2007 +0100 @@ -663,7 +663,7 @@ typedef unsigned long hvm_hypercall_t( #if defined(__i386__) -static hvm_hypercall_t *hvm_hypercall_table[NR_hypercalls] = { +static hvm_hypercall_t *hvm_hypercall32_table[NR_hypercalls] = { HYPERCALL(memory_op), HYPERCALL(multicall), HYPERCALL(xen_version), @@ -672,21 +672,6 @@ static hvm_hypercall_t *hvm_hypercall_ta HYPERCALL(hvm_op) }; -static void __hvm_do_hypercall(struct cpu_user_regs *pregs) -{ - if ( (pregs->eax >= NR_hypercalls) || !hvm_hypercall_table[pregs->eax] ) - { - if ( pregs->eax != __HYPERVISOR_grant_table_op ) - gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d bad hypercall %d.\n", - current->domain->domain_id, current->vcpu_id, pregs->eax); - pregs->eax = -ENOSYS; - return; - } - - pregs->eax = hvm_hypercall_table[pregs->eax]( - pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi); -} - #else /* defined(__x86_64__) */ static long do_memory_op_compat32(int cmd, XEN_GUEST_HANDLE(void) arg) @@ -746,49 +731,38 @@ static hvm_hypercall_t *hvm_hypercall32_ HYPERCALL(hvm_op) }; -static void __hvm_do_hypercall(struct cpu_user_regs *pregs) -{ - pregs->rax = (uint32_t)pregs->eax; /* mask in case compat32 caller */ - if ( (pregs->rax >= NR_hypercalls) || !hvm_hypercall64_table[pregs->rax] ) - { - if ( pregs->rax != __HYPERVISOR_grant_table_op ) - gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d bad hypercall %ld.\n", - current->domain->domain_id, current->vcpu_id, pregs->rax); - pregs->rax = -ENOSYS; - return; - } - - if ( current->arch.paging.mode->guest_levels == 4 ) - { - pregs->rax = hvm_hypercall64_table[pregs->rax](pregs->rdi, - pregs->rsi, - pregs->rdx, - pregs->r10, - pregs->r8); - } - else - { - pregs->eax = hvm_hypercall32_table[pregs->eax]((uint32_t)pregs->ebx, - (uint32_t)pregs->ecx, - (uint32_t)pregs->edx, - (uint32_t)pregs->esi, - (uint32_t)pregs->edi); - } -} - #endif /* defined(__x86_64__) */ int hvm_do_hypercall(struct cpu_user_regs *regs) { - int flush, preempted; - unsigned long old_eip; - - hvm_store_cpu_guest_regs(current, regs, NULL); - - if ( unlikely(ring_3(regs)) ) - { - regs->eax = -EPERM; - return 0; + int flush, mode = hvm_guest_x86_mode(current); + uint32_t eax = regs->eax; + + switch ( mode ) + { +#ifdef __x86_64__ + case 8: +#endif + case 4: + case 2: + hvm_store_cpu_guest_regs(current, regs, NULL); + if ( unlikely(ring_3(regs)) ) + { + default: + regs->eax = -EPERM; + return HVM_HCALL_completed; + } + case 0: + break; + } + + if ( (eax >= NR_hypercalls) || !hvm_hypercall32_table[eax] ) + { + if ( eax != __HYPERVISOR_grant_table_op ) + gdprintk(XENLOG_WARNING, "HVM vcpu %d:%d bad hypercall %u.\n", + current->domain->domain_id, current->vcpu_id, eax); + regs->eax = -ENOSYS; + return HVM_HCALL_completed; } /* @@ -796,20 +770,29 @@ int hvm_do_hypercall(struct cpu_user_reg * For now we also need to flush when pages are added, as qemu-dm is not * yet capable of faulting pages into an existing valid mapcache bucket. */ - flush = ((uint32_t)regs->eax == __HYPERVISOR_memory_op); - - /* Check for preemption: RIP will be modified from this dummy value. */ - old_eip = regs->eip; - regs->eip = 0xF0F0F0FF; - - __hvm_do_hypercall(regs); - - preempted = (regs->eip != 0xF0F0F0FF); - regs->eip = old_eip; - - hvm_load_cpu_guest_regs(current, regs); - - return (preempted ? HVM_HCALL_preempted : + flush = (eax == __HYPERVISOR_memory_op); + this_cpu(hc_preempted) = 0; + +#ifdef __x86_64__ + if ( mode == 8 ) + { + regs->rax = hvm_hypercall64_table[eax](regs->rdi, + regs->rsi, + regs->rdx, + regs->r10, + regs->r8); + } + else +#endif + { + regs->eax = hvm_hypercall32_table[eax]((uint32_t)regs->ebx, + (uint32_t)regs->ecx, + (uint32_t)regs->edx, + (uint32_t)regs->esi, + (uint32_t)regs->edi); + } + + return (this_cpu(hc_preempted) ? HVM_HCALL_preempted : flush ? HVM_HCALL_invalidate : HVM_HCALL_completed); } diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/hvm/platform.c --- a/xen/arch/x86/hvm/platform.c Tue May 15 10:13:11 2007 +0100 +++ b/xen/arch/x86/hvm/platform.c Tue May 15 10:28:28 2007 +0100 @@ -1037,6 +1037,9 @@ void handle_mmio(unsigned long gpa) df = regs->eflags & X86_EFLAGS_DF ? 1 : 0; address_bytes = hvm_guest_x86_mode(v); + if (address_bytes < 2) + /* real or vm86 modes */ + address_bytes = 2; inst_addr = hvm_get_segment_base(v, x86_seg_cs) + regs->eip; inst_len = hvm_instruction_length(inst_addr, address_bytes); if ( inst_len <= 0 ) diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Tue May 15 10:13:11 2007 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Tue May 15 10:28:28 2007 +0100 @@ -554,14 +554,6 @@ static inline void svm_restore_dr(struct __restore_debug_registers(v); } -static int svm_realmode(struct vcpu *v) -{ - unsigned long cr0 = v->arch.hvm_svm.cpu_shadow_cr0; - unsigned long eflags = v->arch.hvm_svm.vmcb->rflags; - - return (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE); -} - static int svm_interrupts_enabled(struct vcpu *v) { unsigned long eflags = v->arch.hvm_svm.vmcb->rflags; @@ -572,13 +564,13 @@ static int svm_guest_x86_mode(struct vcp { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - if ( svm_long_mode_enabled(v) && vmcb->cs.attr.fields.l ) + if ( unlikely(!(v->arch.hvm_svm.cpu_shadow_cr0 & X86_CR0_PE)) ) + return 0; + if ( unlikely(vmcb->rflags & X86_EFLAGS_VM) ) + return 1; + if ( svm_long_mode_enabled(v) && likely(vmcb->cs.attr.fields.l) ) return 8; - - if ( svm_realmode(v) ) - return 2; - - return (vmcb->cs.attr.fields.db ? 4 : 2); + return (likely(vmcb->cs.attr.fields.db) ? 4 : 2); } static void svm_update_host_cr3(struct vcpu *v) @@ -1950,7 +1942,9 @@ static int svm_cr_access(struct vcpu *v, case INSTR_SMSW: value = v->arch.hvm_svm.cpu_shadow_cr0 & 0xFFFF; modrm = buffer[index+2]; - addr_size = svm_guest_x86_mode( v ); + addr_size = svm_guest_x86_mode(v); + if ( addr_size < 2 ) + addr_size = 2; if ( likely((modrm & 0xC0) >> 6 == 3) ) { gpreg = decode_src_reg(prefix, modrm); diff -r eb027b704dc5 -r f4390e34ad12 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Tue May 15 10:13:11 2007 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Tue May 15 10:28:28 2007 +0100 @@ -994,31 +994,20 @@ static void vmx_init_hypercall_page(stru *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */ } -static int vmx_realmode(struct vcpu *v) -{ - unsigned long rflags; +static int vmx_guest_x86_mode(struct vcpu *v) +{ + unsigned int cs_ar_bytes; ASSERT(v == current); - rflags = __vmread(GUEST_RFLAGS); - return rflags & X86_EFLAGS_VM; -} - -static int vmx_guest_x86_mode(struct vcpu *v) -{ - unsigned long cs_ar_bytes; - - ASSERT(v == current); - + if ( unlikely(!(v->arch.hvm_vmx.cpu_shadow_cr0 & X86_CR0_PE)) ) + return 0; + if ( unlikely(__vmread(GUEST_RFLAGS) & X86_EFLAGS_VM) ) + return 1; cs_ar_bytes = __vmread(GUEST_CS_AR_BYTES); - - if ( vmx_long_mode_enabled(v) && (cs_ar_bytes & (1u<<13)) ) + if ( vmx_long_mode_enabled(v) && likely(cs_ar_bytes & (1u<<13)) ) return 8; - - if ( vmx_realmode(v) ) - return 2; - - return ((cs_ar_bytes & (1u<<14)) ? 4 : 2); + return (likely(cs_ar_bytes & (1u<<14)) ? 4 : 2); } static int vmx_pae_enabled(struct vcpu *v) diff -r eb027b704dc5 -r f4390e34ad12 xen/include/asm-x86/hypercall.h --- a/xen/include/asm-x86/hypercall.h Tue May 15 10:13:11 2007 +0100 +++ b/xen/include/asm-x86/hypercall.h Tue May 15 10:28:28 2007 +0100 @@ -14,6 +14,15 @@ * invocation of do_mmu_update() is resuming a previously preempted call. */ #define MMU_UPDATE_PREEMPTED (~(~0U>>1)) + +/* + * This gets set to a non-zero value whenever hypercall_create_continuation() + * is used (outside of multicall context; in multicall context the second call + * from do_multicall() itself will have this effect). Internal callers of + * hypercall handlers interested in this condition must clear the flag prior + * to invoking the respective handler(s). + */ +DECLARE_PER_CPU(char, hc_preempted); extern long do_event_channel_op_compat( _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |