aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest/core.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2007-07-26 13:41:04 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-26 14:35:17 -0400
commitf8f0fdcd40449d318f8dc30c1b361b0b7f54134a (patch)
tree09bdfa13377de602bcd0f363a417a93666115c7e /drivers/lguest/core.c
parentbff672e630a015d5b54c8bfb16160b7edc39a57c (diff)
lguest: documentation VI: Switcher
Documentation: The Switcher Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/lguest/core.c')
-rw-r--r--drivers/lguest/core.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index c0f50b4dd2f..0a46e8837d9 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -393,46 +393,89 @@ static void set_ts(void)
393 write_cr0(cr0|8); 393 write_cr0(cr0|8);
394} 394}
395 395
396/*S:010
397 * We are getting close to the Switcher.
398 *
399 * Remember that each CPU has two pages which are visible to the Guest when it
400 * runs on that CPU. This has to contain the state for that Guest: we copy the
401 * state in just before we run the Guest.
402 *
403 * Each Guest has "changed" flags which indicate what has changed in the Guest
404 * since it last ran. We saw this set in interrupts_and_traps.c and
405 * segments.c.
406 */
396static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages) 407static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
397{ 408{
409 /* Copying all this data can be quite expensive. We usually run the
410 * same Guest we ran last time (and that Guest hasn't run anywhere else
411 * meanwhile). If that's not the case, we pretend everything in the
412 * Guest has changed. */
398 if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) { 413 if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
399 __get_cpu_var(last_guest) = lg; 414 __get_cpu_var(last_guest) = lg;
400 lg->last_pages = pages; 415 lg->last_pages = pages;
401 lg->changed = CHANGED_ALL; 416 lg->changed = CHANGED_ALL;
402 } 417 }
403 418
404 /* These are pretty cheap, so we do them unconditionally. */ 419 /* These copies are pretty cheap, so we do them unconditionally: */
420 /* Save the current Host top-level page directory. */
405 pages->state.host_cr3 = __pa(current->mm->pgd); 421 pages->state.host_cr3 = __pa(current->mm->pgd);
422 /* Set up the Guest's page tables to see this CPU's pages (and no
423 * other CPU's pages). */
406 map_switcher_in_guest(lg, pages); 424 map_switcher_in_guest(lg, pages);
425 /* Set up the two "TSS" members which tell the CPU what stack to use
426 * for traps which do directly into the Guest (ie. traps at privilege
427 * level 1). */
407 pages->state.guest_tss.esp1 = lg->esp1; 428 pages->state.guest_tss.esp1 = lg->esp1;
408 pages->state.guest_tss.ss1 = lg->ss1; 429 pages->state.guest_tss.ss1 = lg->ss1;
409 430
410 /* Copy direct trap entries. */ 431 /* Copy direct-to-Guest trap entries. */
411 if (lg->changed & CHANGED_IDT) 432 if (lg->changed & CHANGED_IDT)
412 copy_traps(lg, pages->state.guest_idt, default_idt_entries); 433 copy_traps(lg, pages->state.guest_idt, default_idt_entries);
413 434
414 /* Copy all GDT entries but the TSS. */ 435 /* Copy all GDT entries which the Guest can change. */
415 if (lg->changed & CHANGED_GDT) 436 if (lg->changed & CHANGED_GDT)
416 copy_gdt(lg, pages->state.guest_gdt); 437 copy_gdt(lg, pages->state.guest_gdt);
417 /* If only the TLS entries have changed, copy them. */ 438 /* If only the TLS entries have changed, copy them. */
418 else if (lg->changed & CHANGED_GDT_TLS) 439 else if (lg->changed & CHANGED_GDT_TLS)
419 copy_gdt_tls(lg, pages->state.guest_gdt); 440 copy_gdt_tls(lg, pages->state.guest_gdt);
420 441
442 /* Mark the Guest as unchanged for next time. */
421 lg->changed = 0; 443 lg->changed = 0;
422} 444}
423 445
446/* Finally: the code to actually call into the Switcher to run the Guest. */
424static void run_guest_once(struct lguest *lg, struct lguest_pages *pages) 447static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
425{ 448{
449 /* This is a dummy value we need for GCC's sake. */
426 unsigned int clobber; 450 unsigned int clobber;
427 451
452 /* Copy the guest-specific information into this CPU's "struct
453 * lguest_pages". */
428 copy_in_guest_info(lg, pages); 454 copy_in_guest_info(lg, pages);
429 455
430 /* Put eflags on stack, lcall does rest: suitable for iret return. */ 456 /* Now: we push the "eflags" register on the stack, then do an "lcall".
457 * This is how we change from using the kernel code segment to using
458 * the dedicated lguest code segment, as well as jumping into the
459 * Switcher.
460 *
461 * The lcall also pushes the old code segment (KERNEL_CS) onto the
462 * stack, then the address of this call. This stack layout happens to
463 * exactly match the stack of an interrupt... */
431 asm volatile("pushf; lcall *lguest_entry" 464 asm volatile("pushf; lcall *lguest_entry"
465 /* This is how we tell GCC that %eax ("a") and %ebx ("b")
466 * are changed by this routine. The "=" means output. */
432 : "=a"(clobber), "=b"(clobber) 467 : "=a"(clobber), "=b"(clobber)
468 /* %eax contains the pages pointer. ("0" refers to the
469 * 0-th argument above, ie "a"). %ebx contains the
470 * physical address of the Guest's top-level page
471 * directory. */
433 : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir)) 472 : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
473 /* We tell gcc that all these registers could change,
474 * which means we don't have to save and restore them in
475 * the Switcher. */
434 : "memory", "%edx", "%ecx", "%edi", "%esi"); 476 : "memory", "%edx", "%ecx", "%edi", "%esi");
435} 477}
478/*:*/
436 479
437/*H:030 Let's jump straight to the the main loop which runs the Guest. 480/*H:030 Let's jump straight to the the main loop which runs the Guest.
438 * Remember, this is called by the Launcher reading /dev/lguest, and we keep 481 * Remember, this is called by the Launcher reading /dev/lguest, and we keep