/* The syscall vector it wants must be unused by Host. */
bool check_syscall_vector(struct lguest *lg)
{
	u32 vector;

	if (get_user(vector, &lg->lguest_data->syscall_vec))
		return false;

	return could_be_syscall(vector);
}
/*H:250 Here's the hard part: returning to the Host every time a trap happens
 * and then calling deliver_trap() and re-entering the Guest is slow.
 * Particularly because Guest userspace system calls are traps (usually trap
 * 128).
 *
 * So we'd like to set up the IDT to tell the CPU to deliver traps directly
 * into the Guest.  This is possible, but the complexities cause the size of
 * this file to double!  However, 150 lines of code is worth writing for taking
 * system calls down from 1750ns to 270ns.  Plus, if lguest didn't do it, all
 * the other hypervisors would beat it up at lunchtime.
 *
 * This routine indicates if a particular trap number could be delivered
 * directly. */
static int direct_trap(unsigned int num)
{
	/* Hardware interrupts don't go to the Guest at all (except system
	 * call). */
	if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num))
		return 0;

	/* The Host needs to see page faults (for shadow paging and to save the
	 * fault address), general protection faults (in/out emulation) and
	 * device not available (TS handling), and of course, the hypercall
	 * trap. */
	return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY;
}
示例#3
0
文件: core.c 项目: AshishNamdev/linux
/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
void lguest_arch_handle_trap(struct lg_cpu *cpu)
{
	unsigned long iomem_addr;

	switch (cpu->regs->trapnum) {
	case 13: /* We've intercepted a General Protection Fault. */
		/* Hand to Launcher to emulate those pesky IN and OUT insns */
		if (cpu->regs->errcode == 0) {
			setup_emulate_insn(cpu);
			return;
		}
		break;
	case 14: /* We've intercepted a Page Fault. */
		/*
		 * The Guest accessed a virtual address that wasn't mapped.
		 * This happens a lot: we don't actually set up most of the page
		 * tables for the Guest at all when we start: as it runs it asks
		 * for more and more, and we set them up as required. In this
		 * case, we don't even tell the Guest that the fault happened.
		 *
		 * The errcode tells whether this was a read or a write, and
		 * whether kernel or userspace code.
		 */
		if (demand_page(cpu, cpu->arch.last_pagefault,
				cpu->regs->errcode, &iomem_addr))
			return;

		/* Was this an access to memory mapped IO? */
		if (iomem_addr) {
			/* Tell Launcher, let it handle it. */
			setup_iomem_insn(cpu, iomem_addr);
			return;
		}

		/*
		 * OK, it's really not there (or not OK): the Guest needs to
		 * know.  We write out the cr2 value so it knows where the
		 * fault occurred.
		 *
		 * Note that if the Guest were really messed up, this could
		 * happen before it's done the LHCALL_LGUEST_INIT hypercall, so
		 * lg->lguest_data could be NULL
		 */
		if (cpu->lg->lguest_data &&
		    put_user(cpu->arch.last_pagefault,
			     &cpu->lg->lguest_data->cr2))
			kill_guest(cpu, "Writing cr2");
		break;
	case 7: /* We've intercepted a Device Not Available fault. */
		/* No special handling is needed here. */
		break;
	case 32 ... 255:
		/* This might be a syscall. */
		if (could_be_syscall(cpu->regs->trapnum))
			break;

		/*
		 * Other values mean a real interrupt occurred, in which case
		 * the Host handler has already been run. We just do a
		 * friendly check if another process should now be run, then
		 * return to run the Guest again.
		 */
		cond_resched();
		return;
	case LGUEST_TRAP_ENTRY:
		/*
		 * Our 'struct hcall_args' maps directly over our regs: we set
		 * up the pointer now to indicate a hypercall is pending.
		 */
		cpu->hcall = (struct hcall_args *)cpu->regs;
		return;
	}

	/* We didn't handle the trap, so it needs to go to the Guest. */
	if (!deliver_trap(cpu, cpu->regs->trapnum))
		/*
		 * If the Guest doesn't have a handler (either it hasn't
		 * registered any yet, or it's one of the faults we don't let
		 * it handle), it dies with this cryptic error message.
		 */
		kill_guest(cpu, "unhandled trap %li at %#lx (%#lx)",
			   cpu->regs->trapnum, cpu->regs->eip,
			   cpu->regs->trapnum == 14 ? cpu->arch.last_pagefault
			   : cpu->regs->errcode);
}