/*H:470 * Finally, a routine which throws away everything: all PGD entries in all * the shadow page tables, including the Guest's kernel mappings. This is used * when we destroy the Guest. */ static void release_all_pagetables(struct lguest *lg) { unsigned int i, j; /* Every shadow pagetable this Guest has */ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) if (lg->pgdirs[i].pgdir) { #ifdef CONFIG_X86_PAE pgd_t *spgd; pmd_t *pmdpage; unsigned int k; /* Get the last pmd page. */ spgd = lg->pgdirs[i].pgdir + SWITCHER_PGD_INDEX; pmdpage = __va(pgd_pfn(*spgd) << PAGE_SHIFT); /* * And release the pmd entries of that pmd page, * except for the switcher pmd. */ for (k = 0; k < SWITCHER_PMD_INDEX; k++) release_pmd(&pmdpage[k]); #endif /* Every PGD entry except the Switcher at the top */ for (j = 0; j < SWITCHER_PGD_INDEX; j++) release_pgd(lg->pgdirs[i].pgdir + j); } }
/*H:445 * We saw flush_user_mappings() twice: once from the flush_user_mappings() * hypercall and once in new_pgdir() when we re-used a top-level pgdir page. * It simply releases every PTE page from 0 up to the Guest's kernel address. */ static void flush_user_mappings(struct lguest *lg, int idx) { unsigned int i; /* Release every pgd entry up to the kernel's address. */ for (i = 0; i < pgd_index(lg->kernel_address); i++) release_pgd(lg->pgdirs[idx].pgdir + i); }
/*H:400 * (iii) Setting up a page table entry when the Guest tells us one has changed. * * Just like we did in interrupts_and_traps.c, it makes sense for us to deal * with the other side of page tables while we're here: what happens when the * Guest asks for a page table to be updated? * * We already saw that demand_page() will fill in the shadow page tables when * needed, so we can simply remove shadow page table entries whenever the Guest * tells us they've changed. When the Guest tries to use the new entry it will * fault and demand_page() will fix it up. * * So with that in mind here's our code to update a (top-level) PGD entry: */ void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 idx) { int pgdir; if (idx >= SWITCHER_PGD_INDEX) return; /* If they're talking about a page table we have a shadow for... */ pgdir = find_pgdir(lg, gpgdir); if (pgdir < ARRAY_SIZE(lg->pgdirs)) /* ... throw it away. */ release_pgd(lg->pgdirs[pgdir].pgdir + idx); }
/*H:470 * Finally, a routine which throws away everything: all PGD entries in all * the shadow page tables, including the Guest's kernel mappings. This is used * when we destroy the Guest. */ static void release_all_pagetables(struct lguest *lg) { unsigned int i, j; /* Every shadow pagetable this Guest has */ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) { if (!lg->pgdirs[i].pgdir) continue; /* Every PGD entry. */ for (j = 0; j < PTRS_PER_PGD; j++) release_pgd(lg->pgdirs[i].pgdir + j); lg->pgdirs[i].switcher_mapped = false; lg->pgdirs[i].last_host_cpu = -1; } }
/*H:400 * (iii) Setting up a page table entry when the Guest tells us one has changed. * * Just like we did in interrupts_and_traps.c, it makes sense for us to deal * with the other side of page tables while we're here: what happens when the * Guest asks for a page table to be updated? * * We already saw that demand_page() will fill in the shadow page tables when * needed, so we can simply remove shadow page table entries whenever the Guest * tells us they've changed. When the Guest tries to use the new entry it will * fault and demand_page() will fix it up. * * So with that in mind here's our code to update a (top-level) PGD entry: */ void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 idx) { int pgdir; if (idx > PTRS_PER_PGD) { kill_guest(&lg->cpus[0], "Attempt to set pgd %u/%u", idx, PTRS_PER_PGD); return; } /* If they're talking about a page table we have a shadow for... */ pgdir = find_pgdir(lg, gpgdir); if (pgdir < ARRAY_SIZE(lg->pgdirs)) { /* ... throw it away. */ release_pgd(lg->pgdirs[pgdir].pgdir + idx); /* That might have been the Switcher mapping, remap it. */ if (!allocate_switcher_mapping(&lg->cpus[0])) { kill_guest(&lg->cpus[0], "Cannot populate switcher mapping"); } lg->pgdirs[pgdir].last_host_cpu = -1; } }