diff options
Diffstat (limited to 'arch/x86/lguest/boot.c')
-rw-r--r-- | arch/x86/lguest/boot.c | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 48ee4f9435f4..a5d8e1ace1cf 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c | |||
@@ -367,10 +367,9 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx, | |||
367 | * lazily after a task switch, and Linux uses that gratefully, but wouldn't a | 367 | * lazily after a task switch, and Linux uses that gratefully, but wouldn't a |
368 | * name like "FPUTRAP bit" be a little less cryptic? | 368 | * name like "FPUTRAP bit" be a little less cryptic? |
369 | * | 369 | * |
370 | * We store cr0 (and cr3) locally, because the Host never changes it. The | 370 | * We store cr0 locally because the Host never changes it. The Guest sometimes |
371 | * Guest sometimes wants to read it and we'd prefer not to bother the Host | 371 | * wants to read it and we'd prefer not to bother the Host unnecessarily. */ |
372 | * unnecessarily. */ | 372 | static unsigned long current_cr0; |
373 | static unsigned long current_cr0, current_cr3; | ||
374 | static void lguest_write_cr0(unsigned long val) | 373 | static void lguest_write_cr0(unsigned long val) |
375 | { | 374 | { |
376 | lazy_hcall(LHCALL_TS, val & X86_CR0_TS, 0, 0); | 375 | lazy_hcall(LHCALL_TS, val & X86_CR0_TS, 0, 0); |
@@ -399,17 +398,23 @@ static unsigned long lguest_read_cr2(void) | |||
399 | return lguest_data.cr2; | 398 | return lguest_data.cr2; |
400 | } | 399 | } |
401 | 400 | ||
401 | /* See lguest_set_pte() below. */ | ||
402 | static bool cr3_changed = false; | ||
403 | |||
402 | /* cr3 is the current toplevel pagetable page: the principle is the same as | 404 | /* cr3 is the current toplevel pagetable page: the principle is the same as |
403 | * cr0. Keep a local copy, and tell the Host when it changes. */ | 405 | * cr0. Keep a local copy, and tell the Host when it changes. The only |
406 | * difference is that our local copy is in lguest_data because the Host needs | ||
407 | * to set it upon our initial hypercall. */ | ||
404 | static void lguest_write_cr3(unsigned long cr3) | 408 | static void lguest_write_cr3(unsigned long cr3) |
405 | { | 409 | { |
410 | lguest_data.pgdir = cr3; | ||
406 | lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0); | 411 | lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0); |
407 | current_cr3 = cr3; | 412 | cr3_changed = true; |
408 | } | 413 | } |
409 | 414 | ||
410 | static unsigned long lguest_read_cr3(void) | 415 | static unsigned long lguest_read_cr3(void) |
411 | { | 416 | { |
412 | return current_cr3; | 417 | return lguest_data.pgdir; |
413 | } | 418 | } |
414 | 419 | ||
415 | /* cr4 is used to enable and disable PGE, but we don't care. */ | 420 | /* cr4 is used to enable and disable PGE, but we don't care. */ |
@@ -498,13 +503,13 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) | |||
498 | * to forget all of them. Fortunately, this is very rare. | 503 | * to forget all of them. Fortunately, this is very rare. |
499 | * | 504 | * |
500 | * ... except in early boot when the kernel sets up the initial pagetables, | 505 | * ... except in early boot when the kernel sets up the initial pagetables, |
501 | * which makes booting astonishingly slow. So we don't even tell the Host | 506 | * which makes booting astonishingly slow: 1.83 seconds! So we don't even tell |
502 | * anything changed until we've done the first page table switch. */ | 507 | * the Host anything changed until we've done the first page table switch, |
508 | * which brings boot back to 0.25 seconds. */ | ||
503 | static void lguest_set_pte(pte_t *ptep, pte_t pteval) | 509 | static void lguest_set_pte(pte_t *ptep, pte_t pteval) |
504 | { | 510 | { |
505 | *ptep = pteval; | 511 | *ptep = pteval; |
506 | /* Don't bother with hypercall before initial setup. */ | 512 | if (cr3_changed) |
507 | if (current_cr3) | ||
508 | lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0); | 513 | lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0); |
509 | } | 514 | } |
510 | 515 | ||
@@ -521,7 +526,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval) | |||
521 | static void lguest_flush_tlb_single(unsigned long addr) | 526 | static void lguest_flush_tlb_single(unsigned long addr) |
522 | { | 527 | { |
523 | /* Simply set it to zero: if it was not, it will fault back in. */ | 528 | /* Simply set it to zero: if it was not, it will fault back in. */ |
524 | lazy_hcall(LHCALL_SET_PTE, current_cr3, addr, 0); | 529 | lazy_hcall(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0); |
525 | } | 530 | } |
526 | 531 | ||
527 | /* This is what happens after the Guest has removed a large number of entries. | 532 | /* This is what happens after the Guest has removed a large number of entries. |
@@ -581,6 +586,9 @@ static void __init lguest_init_IRQ(void) | |||
581 | 586 | ||
582 | for (i = 0; i < LGUEST_IRQS; i++) { | 587 | for (i = 0; i < LGUEST_IRQS; i++) { |
583 | int vector = FIRST_EXTERNAL_VECTOR + i; | 588 | int vector = FIRST_EXTERNAL_VECTOR + i; |
589 | /* Some systems map "vectors" to interrupts weirdly. Lguest has | ||
590 | * a straightforward 1 to 1 mapping, so force that here. */ | ||
591 | __get_cpu_var(vector_irq)[vector] = i; | ||
584 | if (vector != SYSCALL_VECTOR) { | 592 | if (vector != SYSCALL_VECTOR) { |
585 | set_intr_gate(vector, interrupt[vector]); | 593 | set_intr_gate(vector, interrupt[vector]); |
586 | set_irq_chip_and_handler_name(i, &lguest_irq_controller, | 594 | set_irq_chip_and_handler_name(i, &lguest_irq_controller, |