diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2007-10-21 21:03:30 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2007-10-23 01:49:52 -0400 |
commit | cc6d4fbcef328acdc9fa7023e69f39f753f72fe1 (patch) | |
tree | 860672e7da1a3516e36dd40f962552451ef0bcf2 /drivers/lguest/hypercalls.c | |
parent | 4614a3a3b638dfd7a67d0237944f6a76331af61d (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>
Diffstat (limited to 'drivers/lguest/hypercalls.c')
-rw-r--r-- | drivers/lguest/hypercalls.c | 48 |
1 files changed, 20 insertions, 28 deletions
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. */ | ||
252 | static 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 | */ |
263 | void do_hypercalls(struct lguest *lg) | 250 | void 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 | ||