void __trace_hypercall_entry(void) { struct cpu_user_regs *regs = guest_cpu_user_regs(); unsigned long args[6]; if ( is_pv_32bit_vcpu(current) ) { args[0] = regs->ebx; args[1] = regs->ecx; args[2] = regs->edx; args[3] = regs->esi; args[4] = regs->edi; args[5] = regs->ebp; } else { args[0] = regs->rdi; args[1] = regs->rsi; args[2] = regs->rdx; args[3] = regs->r10; args[4] = regs->r8; args[5] = regs->r9; } __trace_hypercall(TRC_PV_HYPERCALL_V2, regs->eax, args); }
static void __trace_multicall_call(multicall_entry_t *call) { unsigned long args[6]; int i; for ( i = 0; i < ARRAY_SIZE(args); i++ ) args[i] = call->args[i]; __trace_hypercall(TRC_PV_HYPERCALL_SUBCALL, call->op, args); }
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); }
static void __trace_multicall_call(multicall_entry_t *call) { __trace_hypercall(TRC_PV_HYPERCALL_SUBCALL, call->op, call->args); }