aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2013-04-22 00:40:41 -0400
committerRusty Russell <rusty@rustcorp.com.au>2013-04-22 02:15:02 -0400
commit86935fc4ee4d95efe01b6c91cd5143fa4c38c02b (patch)
treebac296987d1d5fbb756912e643e7faa23c663e1b /drivers/lguest
parent3412b6ae2924e068f9932f841bdea0f2d8424502 (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.h1
-rw-r--r--drivers/lguest/page_tables.c42
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
17struct pgdir { 17struct 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 */
742static bool allocate_switcher_mapping(struct lg_cpu *cpu) 747static 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. */