void compat_show_guest_stack(struct vcpu *v, struct cpu_user_regs *regs, int debug_stack_lines) { unsigned int i, *stack, addr, mask = STACK_SIZE; stack = (unsigned int *)(unsigned long)regs->_esp; printk("Guest stack trace from esp=%08lx:\n ", (unsigned long)stack); if ( !__compat_access_ok(v->domain, stack, sizeof(*stack)) ) { printk("Guest-inaccessible memory.\n"); return; } if ( v != current ) { struct vcpu *vcpu; unsigned long mfn; ASSERT(guest_kernel_mode(v, regs)); mfn = read_cr3() >> PAGE_SHIFT; for_each_vcpu( v->domain, vcpu ) if ( pagetable_get_pfn(vcpu->arch.guest_table) == mfn ) break; if ( !vcpu ) { stack = do_page_walk(v, (unsigned long)stack); if ( (unsigned long)stack < PAGE_SIZE ) { printk("Inaccessible guest memory.\n"); return; } mask = PAGE_SIZE; } } for ( i = 0; i < debug_stack_lines * 8; i++ ) { if ( (((long)stack - 1) ^ ((long)(stack + 1) - 1)) & mask ) break; if ( __get_user(addr, stack) ) { if ( i != 0 ) printk("\n "); printk("Fault while accessing guest memory."); i = 1; break; } if ( (i != 0) && ((i % 8) == 0) ) printk("\n "); printk(" %08x", addr); stack++; } if ( i == 0 ) printk("Stack empty."); printk("\n"); }
enum mc_disposition arch_do_multicall_call(struct mc_state *state) { struct vcpu *curr = current; unsigned long op; if ( !is_pv_32bit_vcpu(curr) ) { struct multicall_entry *call = &state->call; op = call->op; if ( (op < ARRAY_SIZE(pv_hypercall_table)) && pv_hypercall_table[op].native ) call->result = pv_hypercall_table[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; op = call->op; if ( (op < ARRAY_SIZE(pv_hypercall_table)) && pv_hypercall_table[op].compat ) call->result = pv_hypercall_table[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 return unlikely(op == __HYPERVISOR_iret) ? mc_exit : likely(guest_kernel_mode(curr, guest_cpu_user_regs())) ? mc_continue : mc_preempt; }
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); }