Commit 86935fc4 authored by Rusty Russell's avatar Rusty Russell

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: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 3412b6ae
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
struct pgdir { struct pgdir {
unsigned long gpgdir; unsigned long gpgdir;
bool switcher_mapped;
pgd_t *pgdir; pgd_t *pgdir;
}; };
......
...@@ -736,18 +736,39 @@ static unsigned int new_pgdir(struct lg_cpu *cpu, ...@@ -736,18 +736,39 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
/*H:501 /*H:501
* We do need the Switcher code mapped at all times, so we allocate that * We do need the Switcher code mapped at all times, so we allocate that
* part of the Guest page table here, and populate it when we're about to run * part of the Guest page table here. We map the Switcher code immediately,
* the guest. * but defer mapping of the guest register page and IDT/LDT etc page until
* just before we run the guest in map_switcher_in_guest().
*
* We *could* do this setup in map_switcher_in_guest(), but at that point
* we've interrupts disabled, and allocating pages like that is fraught: we
* can't sleep if we need to free up some memory.
*/ */
static bool allocate_switcher_mapping(struct lg_cpu *cpu) static bool allocate_switcher_mapping(struct lg_cpu *cpu)
{ {
int i; int i;
for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) { for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) {
if (!find_spte(cpu, switcher_addr + i * PAGE_SIZE, true, pte_t *pte = find_spte(cpu, switcher_addr + i * PAGE_SIZE, true,
CHECK_GPGD_MASK, _PAGE_TABLE)) CHECK_GPGD_MASK, _PAGE_TABLE);
if (!pte)
return false; return false;
/*
* Map the switcher page if not already there. It might
* already be there because we call allocate_switcher_mapping()
* in guest_set_pgd() just in case it did discard our Switcher
* mapping, but it probably didn't.
*/
if (i == 0 && !(pte_flags(*pte) & _PAGE_PRESENT)) {
/* Get a reference to the Switcher page. */
get_page(lg_switcher_pages[0]);
/* Create a read-only, exectuable, kernel-style PTE */
set_pte(pte,
mk_pte(lg_switcher_pages[0], PAGE_KERNEL_RX));
}
} }
cpu->lg->pgdirs[cpu->cpu_pgd].switcher_mapped = true;
return true; return true;
} }
...@@ -768,6 +789,7 @@ static void release_all_pagetables(struct lguest *lg) ...@@ -768,6 +789,7 @@ static void release_all_pagetables(struct lguest *lg)
/* Every PGD entry. */ /* Every PGD entry. */
for (j = 0; j < PTRS_PER_PGD; j++) for (j = 0; j < PTRS_PER_PGD; j++)
release_pgd(lg->pgdirs[i].pgdir + j); release_pgd(lg->pgdirs[i].pgdir + j);
lg->pgdirs[i].switcher_mapped = false;
} }
} }
...@@ -827,8 +849,10 @@ void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable) ...@@ -827,8 +849,10 @@ void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable)
if (repin) if (repin)
pin_stack_pages(cpu); pin_stack_pages(cpu);
if (!allocate_switcher_mapping(cpu)) if (!cpu->lg->pgdirs[cpu->cpu_pgd].switcher_mapped) {
kill_guest(cpu, "Cannot populate switcher mapping"); if (!allocate_switcher_mapping(cpu))
kill_guest(cpu, "Cannot populate switcher mapping");
}
} }
/*:*/ /*:*/
...@@ -1076,10 +1100,8 @@ void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages) ...@@ -1076,10 +1100,8 @@ void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)
struct page *percpu_switcher_page, *regs_page; struct page *percpu_switcher_page, *regs_page;
pte_t *pte; pte_t *pte;
/* Code page should always be mapped, and executable. */ /* Switcher page should always be mapped! */
pte = find_spte(cpu, switcher_addr, false, 0, 0); BUG_ON(!cpu->lg->pgdirs[cpu->cpu_pgd].switcher_mapped);
get_page(lg_switcher_pages[0]);
set_pte(pte, mk_pte(lg_switcher_pages[0], PAGE_KERNEL_RX));
/* Clear all the Switcher mappings for any other CPUs. */ /* Clear all the Switcher mappings for any other CPUs. */
/* FIXME: This is dumb: update only when Host CPU changes. */ /* FIXME: This is dumb: update only when Host CPU changes. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment