aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2007-10-21 21:03:30 -0400
committerRusty Russell <rusty@rustcorp.com.au>2007-10-23 01:49:52 -0400
commitcc6d4fbcef328acdc9fa7023e69f39f753f72fe1 (patch)
tree860672e7da1a3516e36dd40f962552451ef0bcf2
parent4614a3a3b638dfd7a67d0237944f6a76331af61d (diff)
Introduce "hcall" pointer to indicate pending hypercall.
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>
-rw-r--r--drivers/lguest/core.c8
-rw-r--r--drivers/lguest/hypercalls.c48
-rw-r--r--drivers/lguest/lg.h3
-rw-r--r--drivers/lguest/x86/core.c13
4 files changed, 34 insertions, 38 deletions
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index 06869a2d3b40..02556bae9e9f 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -198,10 +198,10 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
198{ 198{
199 /* We stop running once the Guest is dead. */ 199 /* We stop running once the Guest is dead. */
200 while (!lg->dead) { 200 while (!lg->dead) {
201 /* First we run any hypercalls the Guest wants done: either in 201 /* First we run any hypercalls the Guest wants done. */
202 * the hypercall ring in "struct lguest_data", or directly by 202 if (lg->hcall)
203 * using int 31 (LGUEST_TRAP_ENTRY). */ 203 do_hypercalls(lg);
204 do_hypercalls(lg); 204
205 /* It's possible the Guest did a SEND_DMA hypercall to the 205 /* It's possible the Guest did a SEND_DMA hypercall to the
206 * Launcher, in which case we return from the read() now. */ 206 * Launcher, in which case we return from the read() now. */
207 if (lg->dma_is_pending) { 207 if (lg->dma_is_pending) {
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index 8bde20934f91..0175a9f03347 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -241,19 +241,6 @@ static void initialize(struct lguest *lg)
241 * is one other way we can do things for the Guest, as we see in 241 * is one other way we can do things for the Guest, as we see in
242 * emulate_insn(). */ 242 * emulate_insn(). */
243 243
244/*H:110 Tricky point: we mark the hypercall as "done" once we've done it.
245 * Normally we don't need to do this: the Guest will run again and update the
246 * trap number before we come back around the run_guest() loop to
247 * do_hypercalls().
248 *
249 * However, if we are signalled or the Guest sends DMA to the Launcher, that
250 * loop will exit without running the Guest. When it comes back it would try
251 * to re-run the hypercall. */
252static void clear_hcall(struct lguest *lg)
253{
254 lg->regs->trapnum = 255;
255}
256
257/*H:100 244/*H:100
258 * Hypercalls 245 * Hypercalls
259 * 246 *
@@ -262,16 +249,12 @@ static void clear_hcall(struct lguest *lg)
262 */ 249 */
263void do_hypercalls(struct lguest *lg) 250void do_hypercalls(struct lguest *lg)
264{ 251{
265 /* Not initialized yet? */ 252 /* Not initialized yet? This hypercall must do it. */
266 if (unlikely(!lg->lguest_data)) { 253 if (unlikely(!lg->lguest_data)) {
267 /* Did the Guest make a hypercall? We might have come back for 254 /* Set up the "struct lguest_data" */
268 * some other reason (an interrupt, a different trap). */ 255 initialize(lg);
269 if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) { 256 /* Hcall is done. */
270 /* Set up the "struct lguest_data" */ 257 lg->hcall = NULL;
271 initialize(lg);
272 /* The hypercall is done. */
273 clear_hcall(lg);
274 }
275 return; 258 return;
276 } 259 }
277 260
@@ -281,12 +264,21 @@ void do_hypercalls(struct lguest *lg)
281 do_async_hcalls(lg); 264 do_async_hcalls(lg);
282 265
283 /* If we stopped reading the hypercall ring because the Guest did a 266 /* If we stopped reading the hypercall ring because the Guest did a
284 * SEND_DMA to the Launcher, we want to return now. Otherwise if the 267 * SEND_DMA to the Launcher, we want to return now. Otherwise we do
285 * Guest asked us to do a hypercall, we do it. */ 268 * the hypercall. */
286 if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) { 269 if (!lg->dma_is_pending) {
287 do_hcall(lg, lg->regs); 270 do_hcall(lg, lg->hcall);
288 /* The hypercall is done. */ 271 /* Tricky point: we reset the hcall pointer to mark the
289 clear_hcall(lg); 272 * hypercall as "done". We use the hcall pointer rather than
273 * the trap number to indicate a hypercall is pending.
274 * Normally it doesn't matter: the Guest will run again and
275 * update the trap number before we come back here.
276 *
277 * However, if we are signalled or the Guest sends DMA to the
278 * Launcher, the run_guest() loop will exit without running the
279 * Guest. When it comes back it would try to re-run the
280 * hypercall. */
281 lg->hcall = NULL;
290 } 282 }
291} 283}
292 284
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index 203d3100c3b4..662994b776cc 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -106,6 +106,9 @@ struct lguest
106 u32 esp1; 106 u32 esp1;
107 u8 ss1; 107 u8 ss1;
108 108
109 /* If a hypercall was asked for, this points to the arguments. */
110 struct lguest_regs *hcall;
111
109 /* Do we need to stop what we're doing and return to userspace? */ 112 /* Do we need to stop what we're doing and return to userspace? */
110 int break_out; 113 int break_out;
111 wait_queue_head_t break_wq; 114 wait_queue_head_t break_wq;
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index e2f46b16ce31..0cc251cbc72a 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -316,13 +316,14 @@ void lguest_arch_handle_trap(struct lguest *lg)
316 return; 316 return;
317 break; 317 break;
318 case 32 ... 255: 318 case 32 ... 255:
319 /* These values mean a real interrupt occurred, in 319 /* These values mean a real interrupt occurred, in which case
320 * which case the Host handler has already been run. 320 * the Host handler has already been run. We just do a
321 * We just do a friendly check if another process 321 * friendly check if another process should now be run, then
322 * should now be run, then fall through to loop 322 * return to run the Guest again */
323 * around: */
324 cond_resched(); 323 cond_resched();
325 case LGUEST_TRAP_ENTRY: /* Handled before re-entering Guest */ 324 return;
325 case LGUEST_TRAP_ENTRY:
326 lg->hcall = lg->regs;
326 return; 327 return;
327 } 328 }
328 329