diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2013-04-22 00:40:41 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2013-04-22 02:15:02 -0400 |
commit | 86935fc4ee4d95efe01b6c91cd5143fa4c38c02b (patch) | |
tree | bac296987d1d5fbb756912e643e7faa23c663e1b /drivers/lguest | |
parent | 3412b6ae2924e068f9932f841bdea0f2d8424502 (diff) |
lguest: map Switcher text whenever we allocate a new pagetable.
It's always to same, so no need to put in the PTE every time we're
about to run. Keep a flag to track whether the pagetable has the
Switcher entries allocated, and when allocating always initialize the
Switcher text PTE.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/lguest')
-rw-r--r-- | drivers/lguest/lg.h | 1 | ||||
-rw-r--r-- | drivers/lguest/page_tables.c | 42 |
2 files changed, 33 insertions, 10 deletions
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index faac9fc6db22..005929a3fd52 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | struct pgdir { | 17 | struct pgdir { |
18 | unsigned long gpgdir; | 18 | unsigned long gpgdir; |
19 | bool switcher_mapped; | ||
19 | pgd_t *pgdir; | 20 | pgd_t *pgdir; |
20 | }; | 21 | }; |
21 | 22 | ||
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index 1f48f2712f3a..d1a5de45be02 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c | |||
@@ -736,18 +736,39 @@ static unsigned int new_pgdir(struct lg_cpu *cpu, | |||
736 | 736 | ||
737 | /*H:501 | 737 | /*H:501 |
738 | * We do need the Switcher code mapped at all times, so we allocate that | 738 | * We do need the Switcher code mapped at all times, so we allocate that |
739 | * part of the Guest page table here, and populate it when we're about to run | 739 | * part of the Guest page table here. We map the Switcher code immediately, |
740 | * the guest. | 740 | * but defer mapping of the guest register page and IDT/LDT etc page until |
741 | * just before we run the guest in map_switcher_in_guest(). | ||
742 | * | ||
743 | * We *could* do this setup in map_switcher_in_guest(), but at that point | ||
744 | * we've interrupts disabled, and allocating pages like that is fraught: we | ||
745 | * can't sleep if we need to free up some memory. | ||
741 | */ | 746 | */ |
742 | static bool allocate_switcher_mapping(struct lg_cpu *cpu) | 747 | static bool allocate_switcher_mapping(struct lg_cpu *cpu) |
743 | { | 748 | { |
744 | int i; | 749 | int i; |
745 | 750 | ||
746 | for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) { | 751 | for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) { |
747 | if (!find_spte(cpu, switcher_addr + i * PAGE_SIZE, true, | 752 | pte_t *pte = find_spte(cpu, switcher_addr + i * PAGE_SIZE, true, |
748 | CHECK_GPGD_MASK, _PAGE_TABLE)) | 753 | CHECK_GPGD_MASK, _PAGE_TABLE); |
754 | if (!pte) | ||
749 | return false; | 755 | return false; |
756 | |||
757 | /* | ||
758 | * Map the switcher page if not already there. It might | ||
759 | * already be there because we call allocate_switcher_mapping() | ||
760 | * in guest_set_pgd() just in case it did discard our Switcher | ||
761 | * mapping, but it probably didn't. | ||
762 | */ | ||
763 | if (i == 0 && !(pte_flags(*pte) & _PAGE_PRESENT)) { | ||
764 | /* Get a reference to the Switcher page. */ | ||
765 | get_page(lg_switcher_pages[0]); | ||
766 | /* Create a read-only, exectuable, kernel-style PTE */ | ||
767 | set_pte(pte, | ||
768 | mk_pte(lg_switcher_pages[0], PAGE_KERNEL_RX)); | ||
769 | } | ||
750 | } | 770 | } |
771 | cpu->lg->pgdirs[cpu->cpu_pgd].switcher_mapped = true; | ||
751 | return true; | 772 | return true; |
752 | } | 773 | } |
753 | 774 | ||
@@ -768,6 +789,7 @@ static void release_all_pagetables(struct lguest *lg) | |||
768 | /* Every PGD entry. */ | 789 | /* Every PGD entry. */ |
769 | for (j = 0; j < PTRS_PER_PGD; j++) | 790 | for (j = 0; j < PTRS_PER_PGD; j++) |
770 | release_pgd(lg->pgdirs[i].pgdir + j); | 791 | release_pgd(lg->pgdirs[i].pgdir + j); |
792 | lg->pgdirs[i].switcher_mapped = false; | ||
771 | } | 793 | } |
772 | } | 794 | } |
773 | 795 | ||
@@ -827,8 +849,10 @@ void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable) | |||
827 | if (repin) | 849 | if (repin) |
828 | pin_stack_pages(cpu); | 850 | pin_stack_pages(cpu); |
829 | 851 | ||
830 | if (!allocate_switcher_mapping(cpu)) | 852 | if (!cpu->lg->pgdirs[cpu->cpu_pgd].switcher_mapped) { |
831 | kill_guest(cpu, "Cannot populate switcher mapping"); | 853 | if (!allocate_switcher_mapping(cpu)) |
854 | kill_guest(cpu, "Cannot populate switcher mapping"); | ||
855 | } | ||
832 | } | 856 | } |
833 | /*:*/ | 857 | /*:*/ |
834 | 858 | ||
@@ -1076,10 +1100,8 @@ void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages) | |||
1076 | struct page *percpu_switcher_page, *regs_page; | 1100 | struct page *percpu_switcher_page, *regs_page; |
1077 | pte_t *pte; | 1101 | pte_t *pte; |
1078 | 1102 | ||
1079 | /* Code page should always be mapped, and executable. */ | 1103 | /* Switcher page should always be mapped! */ |
1080 | pte = find_spte(cpu, switcher_addr, false, 0, 0); | 1104 | BUG_ON(!cpu->lg->pgdirs[cpu->cpu_pgd].switcher_mapped); |
1081 | get_page(lg_switcher_pages[0]); | ||
1082 | set_pte(pte, mk_pte(lg_switcher_pages[0], PAGE_KERNEL_RX)); | ||
1083 | 1105 | ||
1084 | /* Clear all the Switcher mappings for any other CPUs. */ | 1106 | /* Clear all the Switcher mappings for any other CPUs. */ |
1085 | /* FIXME: This is dumb: update only when Host CPU changes. */ | 1107 | /* FIXME: This is dumb: update only when Host CPU changes. */ |