Example #1
0
/*H:100
 * Hypercalls
 *
 * Remember from the Guest, hypercalls come in two flavors: normal and
 * asynchronous.  This file handles both of types.
 */
void do_hypercalls(struct lg_cpu *cpu)
{
    /* Not initialized yet?  This hypercall must do it. */
    if (unlikely(!cpu->lg->lguest_data)) {
        /* Set up the "struct lguest_data" */
        initialize(cpu);
        /* Hcall is done. */
        cpu->hcall = NULL;
        return;
    }

    /* The Guest has initialized.
     *
     * Look in the hypercall ring for the async hypercalls: */
    do_async_hcalls(cpu);

    /* If we stopped reading the hypercall ring because the Guest did a
     * NOTIFY to the Launcher, we want to return now.  Otherwise we do
     * the hypercall. */
    if (!cpu->pending_notify) {
        do_hcall(cpu, cpu->hcall);
        /* Tricky point: we reset the hcall pointer to mark the
         * hypercall as "done".  We use the hcall pointer rather than
         * the trap number to indicate a hypercall is pending.
         * Normally it doesn't matter: the Guest will run again and
         * update the trap number before we come back here.
         *
         * However, if we are signalled or the Guest sends I/O to the
         * Launcher, the run_guest() loop will exit without running the
         * Guest.  When it comes back it would try to re-run the
         * hypercall.  Finding that bug sucked. */
        cpu->hcall = NULL;
    }
}
Example #2
0
/*H:124
 * Asynchronous hypercalls are easy: we just look in the array in the
 * Guest's "struct lguest_data" to see if any new ones are marked "ready".
 *
 * We are careful to do these in order: obviously we respect the order the
 * Guest put them in the ring, but we also promise the Guest that they will
 * happen before any normal hypercall (which is why we check this before
 * checking for a normal hcall).
 */
static void do_async_hcalls(struct lg_cpu *cpu)
{
	unsigned int i;
	u8 st[LHCALL_RING_SIZE];

	/* For simplicity, we copy the entire call status array in at once. */
	if (copy_from_user(&st, &cpu->lg->lguest_data->hcall_status, sizeof(st)))
		return;

	/* We process "struct lguest_data"s hcalls[] ring once. */
	for (i = 0; i < ARRAY_SIZE(st); i++) {
		struct hcall_args args;
		/*
		 * We remember where we were up to from last time.  This makes
		 * sure that the hypercalls are done in the order the Guest
		 * places them in the ring.
		 */
		unsigned int n = cpu->next_hcall;

		/* 0xFF means there's no call here (yet). */
		if (st[n] == 0xFF)
			break;

		/*
		 * OK, we have hypercall.  Increment the "next_hcall" cursor,
		 * and wrap back to 0 if we reach the end.
		 */
		if (++cpu->next_hcall == LHCALL_RING_SIZE)
			cpu->next_hcall = 0;

		/*
		 * Copy the hypercall arguments into a local copy of the
		 * hcall_args struct.
		 */
		if (copy_from_user(&args, &cpu->lg->lguest_data->hcalls[n],
				   sizeof(struct hcall_args))) {
			kill_guest(cpu, "Fetching async hypercalls");
			break;
		}

		/* Do the hypercall, same as a normal one. */
		do_hcall(cpu, &args);

		/* Mark the hypercall done. */
		if (put_user(0xFF, &cpu->lg->lguest_data->hcall_status[n])) {
			kill_guest(cpu, "Writing result for async hypercall");
			break;
		}

		/*
		 * Stop doing hypercalls if they want to notify the Launcher:
		 * it needs to service this first.
		 */
		if (cpu->pending_notify)
			break;
	}
}
void do_hypercalls(struct lg_cpu *cpu)
{
	
	if (unlikely(!cpu->lg->lguest_data)) {
		
		initialize(cpu);
		
		cpu->hcall = NULL;
		return;
	}

	do_async_hcalls(cpu);

	if (!cpu->pending_notify) {
		do_hcall(cpu, cpu->hcall);
		cpu->hcall = NULL;
	}
}
static void do_async_hcalls(struct lg_cpu *cpu)
{
	unsigned int i;
	u8 st[LHCALL_RING_SIZE];

	
	if (copy_from_user(&st, &cpu->lg->lguest_data->hcall_status, sizeof(st)))
		return;

	
	for (i = 0; i < ARRAY_SIZE(st); i++) {
		struct hcall_args args;
		unsigned int n = cpu->next_hcall;

		
		if (st[n] == 0xFF)
			break;

		if (++cpu->next_hcall == LHCALL_RING_SIZE)
			cpu->next_hcall = 0;

		if (copy_from_user(&args, &cpu->lg->lguest_data->hcalls[n],
				   sizeof(struct hcall_args))) {
			kill_guest(cpu, "Fetching async hypercalls");
			break;
		}

		
		do_hcall(cpu, &args);

		
		if (put_user(0xFF, &cpu->lg->lguest_data->hcall_status[n])) {
			kill_guest(cpu, "Writing result for async hypercall");
			break;
		}

		if (cpu->pending_notify)
			break;
	}
}