Skip to content

Commit

Permalink
Introduce "hcall" pointer to indicate pending hypercall.
Browse files Browse the repository at this point in the history
Currently we look at the "trapnum" to see if the Guest wants a
hypercall.  But once the hypercall is done we have to reset trapnum to
a bogus value, otherwise if we exit to userspace and return, we'd run
the same hypercall twice (that was a nasty bug to find!).

This has two main effects:

1) When Jes's patch changes the hypercall args to be a generic "struct
   hcall_args" we simply change the type of "lg->hcall".  It's set by
   arch code, so if it has to copy args or something it can do so, and
   point "hcall" into lg->arch somewhere.

2) Async hypercalls only get run when an actual hypercall is pending.
   This simplfies the code a little and is a more logical semantic.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
Rusty Russell committed Oct 23, 2007
1 parent 4614a3a commit cc6d4fb
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 38 deletions.
8 changes: 4 additions & 4 deletions drivers/lguest/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,10 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
{
/* We stop running once the Guest is dead. */
while (!lg->dead) {
/* First we run any hypercalls the Guest wants done: either in
* the hypercall ring in "struct lguest_data", or directly by
* using int 31 (LGUEST_TRAP_ENTRY). */
do_hypercalls(lg);
/* First we run any hypercalls the Guest wants done. */
if (lg->hcall)
do_hypercalls(lg);

/* It's possible the Guest did a SEND_DMA hypercall to the
* Launcher, in which case we return from the read() now. */
if (lg->dma_is_pending) {
Expand Down
48 changes: 20 additions & 28 deletions drivers/lguest/hypercalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,19 +241,6 @@ static void initialize(struct lguest *lg)
* is one other way we can do things for the Guest, as we see in
* emulate_insn(). */

/*H:110 Tricky point: we mark the hypercall as "done" once we've done it.
* Normally we don't need to do this: the Guest will run again and update the
* trap number before we come back around the run_guest() loop to
* do_hypercalls().
*
* However, if we are signalled or the Guest sends DMA to the Launcher, that
* loop will exit without running the Guest. When it comes back it would try
* to re-run the hypercall. */
static void clear_hcall(struct lguest *lg)
{
lg->regs->trapnum = 255;
}

/*H:100
* Hypercalls
*
Expand All @@ -262,16 +249,12 @@ static void clear_hcall(struct lguest *lg)
*/
void do_hypercalls(struct lguest *lg)
{
/* Not initialized yet? */
/* Not initialized yet? This hypercall must do it. */
if (unlikely(!lg->lguest_data)) {
/* Did the Guest make a hypercall? We might have come back for
* some other reason (an interrupt, a different trap). */
if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
/* Set up the "struct lguest_data" */
initialize(lg);
/* The hypercall is done. */
clear_hcall(lg);
}
/* Set up the "struct lguest_data" */
initialize(lg);
/* Hcall is done. */
lg->hcall = NULL;
return;
}

Expand All @@ -281,12 +264,21 @@ void do_hypercalls(struct lguest *lg)
do_async_hcalls(lg);

/* If we stopped reading the hypercall ring because the Guest did a
* SEND_DMA to the Launcher, we want to return now. Otherwise if the
* Guest asked us to do a hypercall, we do it. */
if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
do_hcall(lg, lg->regs);
/* The hypercall is done. */
clear_hcall(lg);
* SEND_DMA to the Launcher, we want to return now. Otherwise we do
* the hypercall. */
if (!lg->dma_is_pending) {
do_hcall(lg, lg->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 DMA 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. */
lg->hcall = NULL;
}
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/lguest/lg.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ struct lguest
u32 esp1;
u8 ss1;

/* If a hypercall was asked for, this points to the arguments. */
struct lguest_regs *hcall;

/* Do we need to stop what we're doing and return to userspace? */
int break_out;
wait_queue_head_t break_wq;
Expand Down
13 changes: 7 additions & 6 deletions drivers/lguest/x86/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,14 @@ void lguest_arch_handle_trap(struct lguest *lg)
return;
break;
case 32 ... 255:
/* These 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 fall through to loop
* around: */
/* These 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();
case LGUEST_TRAP_ENTRY: /* Handled before re-entering Guest */
return;
case LGUEST_TRAP_ENTRY:
lg->hcall = lg->regs;
return;
}

Expand Down

0 comments on commit cc6d4fb

Please sign in to comment.