diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2007-07-26 13:41:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-26 14:35:17 -0400 |
commit | f8f0fdcd40449d318f8dc30c1b361b0b7f54134a (patch) | |
tree | 09bdfa13377de602bcd0f363a417a93666115c7e /drivers/lguest/core.c | |
parent | bff672e630a015d5b54c8bfb16160b7edc39a57c (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.c | 51 |
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 | */ | ||
396 | static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages) | 407 | static 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. */ | ||
424 | static void run_guest_once(struct lguest *lg, struct lguest_pages *pages) | 447 | static 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 |