[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] x86/hypercall: Split out PV hypercall infrastructure
commit 0c221ae9d745de138850c6903a5861e2582df863 Author: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> AuthorDate: Mon Feb 13 11:49:33 2017 +0000 Commit: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> CommitDate: Thu Feb 16 14:15:25 2017 +0000 x86/hypercall: Split out PV hypercall infrastructure Repurpose arch/x86/hypercall.c to be common x86 hypercall infrastructure, and move the PV specific routines to arch/x86/pv/hypercall.c This is purely code motion. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Acked-by: Jan Beulich <jbeulich@xxxxxxxx> --- xen/arch/x86/Makefile | 1 + xen/arch/x86/hypercall.c | 226 +------------------------------------- xen/arch/x86/pv/Makefile | 1 + xen/arch/x86/pv/hypercall.c | 257 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 261 insertions(+), 224 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 007dced..10f519e 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -4,6 +4,7 @@ subdir-y += genapic subdir-y += hvm subdir-y += mm subdir-$(CONFIG_XENOPROF) += oprofile +subdir-y += pv subdir-y += x86_64 alternative-y := alternative.init.o diff --git a/xen/arch/x86/hypercall.c b/xen/arch/x86/hypercall.c index c0718f8..f807332 100644 --- a/xen/arch/x86/hypercall.c +++ b/xen/arch/x86/hypercall.c @@ -1,6 +1,8 @@ /****************************************************************************** * arch/x86/hypercall.c * + * Common x86 hypercall infrastructure. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,9 +19,7 @@ * Copyright (c) 2015,2016 Citrix Systems Ltd. */ -#include <xen/compiler.h> #include <xen/hypercall.h> -#include <xen/trace.h> #define ARGS(x, n) \ [ __HYPERVISOR_ ## x ] = { n, n } @@ -74,228 +74,6 @@ const hypercall_args_t hypercall_args_table[NR_hypercalls] = #undef COMP #undef ARGS -#define HYPERCALL(x) \ - [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x, \ - (hypercall_fn_t *) do_ ## x } -#define COMPAT_CALL(x) \ - [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x, \ - (hypercall_fn_t *) compat_ ## x } - -#define do_arch_1 paging_domctl_continuation - -static const hypercall_table_t pv_hypercall_table[] = { - COMPAT_CALL(set_trap_table), - HYPERCALL(mmu_update), - COMPAT_CALL(set_gdt), - HYPERCALL(stack_switch), - COMPAT_CALL(set_callbacks), - HYPERCALL(fpu_taskswitch), - HYPERCALL(sched_op_compat), - COMPAT_CALL(platform_op), - HYPERCALL(set_debugreg), - HYPERCALL(get_debugreg), - COMPAT_CALL(update_descriptor), - COMPAT_CALL(memory_op), - COMPAT_CALL(multicall), - COMPAT_CALL(update_va_mapping), - COMPAT_CALL(set_timer_op), - HYPERCALL(event_channel_op_compat), - COMPAT_CALL(xen_version), - HYPERCALL(console_io), - COMPAT_CALL(physdev_op_compat), - COMPAT_CALL(grant_table_op), - COMPAT_CALL(vm_assist), - COMPAT_CALL(update_va_mapping_otherdomain), - COMPAT_CALL(iret), - COMPAT_CALL(vcpu_op), - HYPERCALL(set_segment_base), - COMPAT_CALL(mmuext_op), - COMPAT_CALL(xsm_op), - COMPAT_CALL(nmi_op), - COMPAT_CALL(sched_op), - COMPAT_CALL(callback_op), -#ifdef CONFIG_XENOPROF - COMPAT_CALL(xenoprof_op), -#endif - HYPERCALL(event_channel_op), - COMPAT_CALL(physdev_op), - HYPERCALL(hvm_op), - HYPERCALL(sysctl), - HYPERCALL(domctl), -#ifdef CONFIG_KEXEC - COMPAT_CALL(kexec_op), -#endif -#ifdef CONFIG_TMEM - HYPERCALL(tmem_op), -#endif - HYPERCALL(xenpmu_op), - COMPAT_CALL(dm_op), - HYPERCALL(mca), - HYPERCALL(arch_1), -}; - -#undef do_arch_1 -#undef COMPAT_CALL -#undef HYPERCALL - -void pv_hypercall(struct cpu_user_regs *regs) -{ - struct vcpu *curr = current; - unsigned long eax; - - ASSERT(guest_kernel_mode(curr, regs)); - - eax = is_pv_32bit_vcpu(curr) ? regs->_eax : regs->rax; - - BUILD_BUG_ON(ARRAY_SIZE(pv_hypercall_table) > - ARRAY_SIZE(hypercall_args_table)); - - if ( (eax >= ARRAY_SIZE(pv_hypercall_table)) || - !pv_hypercall_table[eax].native ) - { - regs->rax = -ENOSYS; - return; - } - - curr->hcall_preempted = false; - - if ( !is_pv_32bit_vcpu(curr) ) - { - unsigned long rdi = regs->rdi; - unsigned long rsi = regs->rsi; - unsigned long rdx = regs->rdx; - unsigned long r10 = regs->r10; - unsigned long r8 = regs->r8; - unsigned long r9 = regs->r9; - -#ifndef NDEBUG - /* Deliberately corrupt parameter regs not used by this hypercall. */ - switch ( hypercall_args_table[eax].native ) - { - case 0: rdi = 0xdeadbeefdeadf00dUL; - case 1: rsi = 0xdeadbeefdeadf00dUL; - case 2: rdx = 0xdeadbeefdeadf00dUL; - case 3: r10 = 0xdeadbeefdeadf00dUL; - case 4: r8 = 0xdeadbeefdeadf00dUL; - case 5: r9 = 0xdeadbeefdeadf00dUL; - } -#endif - if ( unlikely(tb_init_done) ) - { - unsigned long args[6] = { rdi, rsi, rdx, r10, r8, r9 }; - - __trace_hypercall(TRC_PV_HYPERCALL_V2, eax, args); - } - - regs->rax = pv_hypercall_table[eax].native(rdi, rsi, rdx, r10, r8, r9); - -#ifndef NDEBUG - if ( !curr->hcall_preempted ) - { - /* Deliberately corrupt parameter regs used by this hypercall. */ - switch ( hypercall_args_table[eax].native ) - { - case 6: regs->r9 = 0xdeadbeefdeadf00dUL; - case 5: regs->r8 = 0xdeadbeefdeadf00dUL; - case 4: regs->r10 = 0xdeadbeefdeadf00dUL; - case 3: regs->rdx = 0xdeadbeefdeadf00dUL; - case 2: regs->rsi = 0xdeadbeefdeadf00dUL; - case 1: regs->rdi = 0xdeadbeefdeadf00dUL; - } - } -#endif - } - else - { - unsigned int ebx = regs->_ebx; - unsigned int ecx = regs->_ecx; - unsigned int edx = regs->_edx; - unsigned int esi = regs->_esi; - unsigned int edi = regs->_edi; - unsigned int ebp = regs->_ebp; - -#ifndef NDEBUG - /* Deliberately corrupt parameter regs not used by this hypercall. */ - switch ( hypercall_args_table[eax].compat ) - { - case 0: ebx = 0xdeadf00d; - case 1: ecx = 0xdeadf00d; - case 2: edx = 0xdeadf00d; - case 3: esi = 0xdeadf00d; - case 4: edi = 0xdeadf00d; - case 5: ebp = 0xdeadf00d; - } -#endif - - if ( unlikely(tb_init_done) ) - { - unsigned long args[6] = { ebx, ecx, edx, esi, edi, ebp }; - - __trace_hypercall(TRC_PV_HYPERCALL_V2, eax, args); - } - - curr->hcall_compat = true; - regs->_eax = pv_hypercall_table[eax].compat(ebx, ecx, edx, esi, edi, ebp); - curr->hcall_compat = false; - -#ifndef NDEBUG - if ( !curr->hcall_preempted ) - { - /* Deliberately corrupt parameter regs used by this hypercall. */ - switch ( hypercall_args_table[eax].compat ) - { - case 6: regs->_ebp = 0xdeadf00d; - case 5: regs->_edi = 0xdeadf00d; - case 4: regs->_esi = 0xdeadf00d; - case 3: regs->_edx = 0xdeadf00d; - case 2: regs->_ecx = 0xdeadf00d; - case 1: regs->_ebx = 0xdeadf00d; - } - } -#endif - } - - /* - * PV guests use SYSCALL or INT $0x82 to make a hypercall, both of which - * have trap semantics. If the hypercall has been preempted, rewind the - * instruction pointer to reexecute the instruction. - */ - if ( curr->hcall_preempted ) - regs->rip -= 2; - - perfc_incr(hypercalls); -} - -void arch_do_multicall_call(struct mc_state *state) -{ - if ( !is_pv_32bit_vcpu(current) ) - { - struct multicall_entry *call = &state->call; - - if ( (call->op < ARRAY_SIZE(pv_hypercall_table)) && - pv_hypercall_table[call->op].native ) - call->result = pv_hypercall_table[call->op].native( - call->args[0], call->args[1], call->args[2], - call->args[3], call->args[4], call->args[5]); - else - call->result = -ENOSYS; - } -#ifdef CONFIG_COMPAT - else - { - struct compat_multicall_entry *call = &state->compat_call; - - if ( (call->op < ARRAY_SIZE(pv_hypercall_table)) && - pv_hypercall_table[call->op].compat ) - call->result = pv_hypercall_table[call->op].compat( - call->args[0], call->args[1], call->args[2], - call->args[3], call->args[4], call->args[5]); - else - call->result = -ENOSYS; - } -#endif -} - /* * Local variables: * mode: C diff --git a/xen/arch/x86/pv/Makefile b/xen/arch/x86/pv/Makefile new file mode 100644 index 0000000..de21937 --- /dev/null +++ b/xen/arch/x86/pv/Makefile @@ -0,0 +1 @@ +obj-y += hypercall.o diff --git a/xen/arch/x86/pv/hypercall.c b/xen/arch/x86/pv/hypercall.c new file mode 100644 index 0000000..9144f2e --- /dev/null +++ b/xen/arch/x86/pv/hypercall.c @@ -0,0 +1,257 @@ +/****************************************************************************** + * arch/x86/pv/hypercall.c + * + * PV hypercall dispatching routines + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses/>. + * + * Copyright (c) 2017 Citrix Systems Ltd. + */ + +#include <xen/compiler.h> +#include <xen/hypercall.h> +#include <xen/trace.h> + +#define HYPERCALL(x) \ + [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x, \ + (hypercall_fn_t *) do_ ## x } +#define COMPAT_CALL(x) \ + [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x, \ + (hypercall_fn_t *) compat_ ## x } + +#define do_arch_1 paging_domctl_continuation + +static const hypercall_table_t pv_hypercall_table[] = { + COMPAT_CALL(set_trap_table), + HYPERCALL(mmu_update), + COMPAT_CALL(set_gdt), + HYPERCALL(stack_switch), + COMPAT_CALL(set_callbacks), + HYPERCALL(fpu_taskswitch), + HYPERCALL(sched_op_compat), + COMPAT_CALL(platform_op), + HYPERCALL(set_debugreg), + HYPERCALL(get_debugreg), + COMPAT_CALL(update_descriptor), + COMPAT_CALL(memory_op), + COMPAT_CALL(multicall), + COMPAT_CALL(update_va_mapping), + COMPAT_CALL(set_timer_op), + HYPERCALL(event_channel_op_compat), + COMPAT_CALL(xen_version), + HYPERCALL(console_io), + COMPAT_CALL(physdev_op_compat), + COMPAT_CALL(grant_table_op), + COMPAT_CALL(vm_assist), + COMPAT_CALL(update_va_mapping_otherdomain), + COMPAT_CALL(iret), + COMPAT_CALL(vcpu_op), + HYPERCALL(set_segment_base), + COMPAT_CALL(mmuext_op), + COMPAT_CALL(xsm_op), + COMPAT_CALL(nmi_op), + COMPAT_CALL(sched_op), + COMPAT_CALL(callback_op), +#ifdef CONFIG_XENOPROF + COMPAT_CALL(xenoprof_op), +#endif + HYPERCALL(event_channel_op), + COMPAT_CALL(physdev_op), + HYPERCALL(hvm_op), + HYPERCALL(sysctl), + HYPERCALL(domctl), +#ifdef CONFIG_KEXEC + COMPAT_CALL(kexec_op), +#endif +#ifdef CONFIG_TMEM + HYPERCALL(tmem_op), +#endif + HYPERCALL(xenpmu_op), + COMPAT_CALL(dm_op), + HYPERCALL(mca), + HYPERCALL(arch_1), +}; + +#undef do_arch_1 +#undef COMPAT_CALL +#undef HYPERCALL + +void pv_hypercall(struct cpu_user_regs *regs) +{ + struct vcpu *curr = current; + unsigned long eax; + + ASSERT(guest_kernel_mode(curr, regs)); + + eax = is_pv_32bit_vcpu(curr) ? regs->_eax : regs->rax; + + BUILD_BUG_ON(ARRAY_SIZE(pv_hypercall_table) > + ARRAY_SIZE(hypercall_args_table)); + + if ( (eax >= ARRAY_SIZE(pv_hypercall_table)) || + !pv_hypercall_table[eax].native ) + { + regs->rax = -ENOSYS; + return; + } + + curr->hcall_preempted = false; + + if ( !is_pv_32bit_vcpu(curr) ) + { + unsigned long rdi = regs->rdi; + unsigned long rsi = regs->rsi; + unsigned long rdx = regs->rdx; + unsigned long r10 = regs->r10; + unsigned long r8 = regs->r8; + unsigned long r9 = regs->r9; + +#ifndef NDEBUG + /* Deliberately corrupt parameter regs not used by this hypercall. */ + switch ( hypercall_args_table[eax].native ) + { + case 0: rdi = 0xdeadbeefdeadf00dUL; + case 1: rsi = 0xdeadbeefdeadf00dUL; + case 2: rdx = 0xdeadbeefdeadf00dUL; + case 3: r10 = 0xdeadbeefdeadf00dUL; + case 4: r8 = 0xdeadbeefdeadf00dUL; + case 5: r9 = 0xdeadbeefdeadf00dUL; + } +#endif + if ( unlikely(tb_init_done) ) + { + unsigned long args[6] = { rdi, rsi, rdx, r10, r8, r9 }; + + __trace_hypercall(TRC_PV_HYPERCALL_V2, eax, args); + } + + regs->rax = pv_hypercall_table[eax].native(rdi, rsi, rdx, r10, r8, r9); + +#ifndef NDEBUG + if ( !curr->hcall_preempted ) + { + /* Deliberately corrupt parameter regs used by this hypercall. */ + switch ( hypercall_args_table[eax].native ) + { + case 6: regs->r9 = 0xdeadbeefdeadf00dUL; + case 5: regs->r8 = 0xdeadbeefdeadf00dUL; + case 4: regs->r10 = 0xdeadbeefdeadf00dUL; + case 3: regs->rdx = 0xdeadbeefdeadf00dUL; + case 2: regs->rsi = 0xdeadbeefdeadf00dUL; + case 1: regs->rdi = 0xdeadbeefdeadf00dUL; + } + } +#endif + } + else + { + unsigned int ebx = regs->_ebx; + unsigned int ecx = regs->_ecx; + unsigned int edx = regs->_edx; + unsigned int esi = regs->_esi; + unsigned int edi = regs->_edi; + unsigned int ebp = regs->_ebp; + +#ifndef NDEBUG + /* Deliberately corrupt parameter regs not used by this hypercall. */ + switch ( hypercall_args_table[eax].compat ) + { + case 0: ebx = 0xdeadf00d; + case 1: ecx = 0xdeadf00d; + case 2: edx = 0xdeadf00d; + case 3: esi = 0xdeadf00d; + case 4: edi = 0xdeadf00d; + case 5: ebp = 0xdeadf00d; + } +#endif + + if ( unlikely(tb_init_done) ) + { + unsigned long args[6] = { ebx, ecx, edx, esi, edi, ebp }; + + __trace_hypercall(TRC_PV_HYPERCALL_V2, eax, args); + } + + curr->hcall_compat = true; + regs->_eax = pv_hypercall_table[eax].compat(ebx, ecx, edx, esi, edi, ebp); + curr->hcall_compat = false; + +#ifndef NDEBUG + if ( !curr->hcall_preempted ) + { + /* Deliberately corrupt parameter regs used by this hypercall. */ + switch ( hypercall_args_table[eax].compat ) + { + case 6: regs->_ebp = 0xdeadf00d; + case 5: regs->_edi = 0xdeadf00d; + case 4: regs->_esi = 0xdeadf00d; + case 3: regs->_edx = 0xdeadf00d; + case 2: regs->_ecx = 0xdeadf00d; + case 1: regs->_ebx = 0xdeadf00d; + } + } +#endif + } + + /* + * PV guests use SYSCALL or INT $0x82 to make a hypercall, both of which + * have trap semantics. If the hypercall has been preempted, rewind the + * instruction pointer to reexecute the instruction. + */ + if ( curr->hcall_preempted ) + regs->rip -= 2; + + perfc_incr(hypercalls); +} + +void arch_do_multicall_call(struct mc_state *state) +{ + if ( !is_pv_32bit_vcpu(current) ) + { + struct multicall_entry *call = &state->call; + + if ( (call->op < ARRAY_SIZE(pv_hypercall_table)) && + pv_hypercall_table[call->op].native ) + call->result = pv_hypercall_table[call->op].native( + call->args[0], call->args[1], call->args[2], + call->args[3], call->args[4], call->args[5]); + else + call->result = -ENOSYS; + } +#ifdef CONFIG_COMPAT + else + { + struct compat_multicall_entry *call = &state->compat_call; + + if ( (call->op < ARRAY_SIZE(pv_hypercall_table)) && + pv_hypercall_table[call->op].compat ) + call->result = pv_hypercall_table[call->op].compat( + call->args[0], call->args[1], call->args[2], + call->args[3], call->args[4], call->args[5]); + else + call->result = -ENOSYS; + } +#endif +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |