···1717struct pgdir {1818 unsigned long gpgdir;1919 bool switcher_mapped;2020+ int last_host_cpu;2021 pgd_t *pgdir;2122};2223
+54-26
drivers/lguest/page_tables.c
···77 * converted Guest pages when running the Guest.88:*/991010-/* Copyright (C) Rusty Russell IBM Corporation 2006.1010+/* Copyright (C) Rusty Russell IBM Corporation 2013.1111 * GPL v2 and any later version */1212#include <linux/mm.h>1313#include <linux/gfp.h>···731731 /* Release all the non-kernel mappings. */732732 flush_user_mappings(cpu->lg, next);733733734734+ /* This hasn't run on any CPU at all. */735735+ cpu->lg->pgdirs[next].last_host_cpu = -1;736736+734737 return next;735738}736739···793790 for (j = 0; j < PTRS_PER_PGD; j++)794791 release_pgd(lg->pgdirs[i].pgdir + j);795792 lg->pgdirs[i].switcher_mapped = false;793793+ lg->pgdirs[i].last_host_cpu = -1;796794 }797795}798796···10901086 free_page((long)lg->pgdirs[i].pgdir);10911087}1092108810891089+/*H:48110901090+ * This clears the Switcher mappings for cpu #i.10911091+ */10921092+static void remove_switcher_percpu_map(struct lg_cpu *cpu, unsigned int i)10931093+{10941094+ unsigned long base = switcher_addr + PAGE_SIZE + i * PAGE_SIZE*2;10951095+ pte_t *pte;10961096+10971097+ /* Clear the mappings for both pages. */10981098+ pte = find_spte(cpu, base, false, 0, 0);10991099+ release_pte(*pte);11001100+ set_pte(pte, __pte(0));11011101+11021102+ pte = find_spte(cpu, base + PAGE_SIZE, false, 0, 0);11031103+ release_pte(*pte);11041104+ set_pte(pte, __pte(0));11051105+}11061106+10931107/*H:48010941108 * (vi) Mapping the Switcher when the Guest is about to run.10951109 *10961096- * The Switcher and the two pages for this CPU need to be visible in the10971097- * Guest (and not the pages for other CPUs).11101110+ * The Switcher and the two pages for this CPU need to be visible in the Guest11111111+ * (and not the pages for other CPUs).10981112 *10991099- * The pages have all been allocate11131113+ * The pages for the pagetables have all been allocated before: we just need11141114+ * to make sure the actual PTEs are up-to-date for the CPU we're about to run11151115+ * on.11001116 */11011117void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)11021118{11031103- unsigned long base, i;11191119+ unsigned long base;11041120 struct page *percpu_switcher_page, *regs_page;11051121 pte_t *pte;11221122+ struct pgdir *pgdir = &cpu->lg->pgdirs[cpu->cpu_pgd];1106112311071107- /* Switcher page should always be mapped! */11081108- BUG_ON(!cpu->lg->pgdirs[cpu->cpu_pgd].switcher_mapped);11241124+ /* Switcher page should always be mapped by now! */11251125+ BUG_ON(!pgdir->switcher_mapped);1109112611101110- /* Clear all the Switcher mappings for any other CPUs. */11111111- /* FIXME: This is dumb: update only when Host CPU changes. */11121112- for_each_possible_cpu(i) {11131113- /* Get location of lguest_pages (indexed by Host CPU) */11141114- base = switcher_addr + PAGE_SIZE11151115- + i * sizeof(struct lguest_pages);11271127+ /* 11281128+ * Remember that we have two pages for each Host CPU, so we can run a11291129+ * Guest on each CPU without them interfering. We need to make sure11301130+ * those pages are mapped correctly in the Guest, but since we usually11311131+ * run on the same CPU, we cache that, and only update the mappings11321132+ * when we move.11331133+ */11341134+ if (pgdir->last_host_cpu == raw_smp_processor_id())11351135+ return;1116113611171117- /* Get shadow PTE for first page (where we put guest regs). */11181118- pte = find_spte(cpu, base, false, 0, 0);11191119- set_pte(pte, __pte(0));11201120-11211121- /* This is where we put R/O state. */11221122- pte = find_spte(cpu, base + PAGE_SIZE, false, 0, 0);11231123- set_pte(pte, __pte(0));11371137+ /* -1 means unknown so we remove everything. */11381138+ if (pgdir->last_host_cpu == -1) {11391139+ unsigned int i;11401140+ for_each_possible_cpu(i)11411141+ remove_switcher_percpu_map(cpu, i);11421142+ } else {11431143+ /* We know exactly what CPU mapping to remove. */11441144+ remove_switcher_percpu_map(cpu, pgdir->last_host_cpu);11241145 }1125114611261147 /*···11691140 * the Guest: the IDT, GDT and other things it's not supposed to11701141 * change.11711142 */11721172- base += PAGE_SIZE;11731173- pte = find_spte(cpu, base, false, 0, 0);11741174-11431143+ pte = find_spte(cpu, base + PAGE_SIZE, false, 0, 0);11751144 percpu_switcher_page11761145 = lg_switcher_pages[1 + raw_smp_processor_id()*2 + 1];11771146 get_page(percpu_switcher_page);11781147 set_pte(pte, mk_pte(percpu_switcher_page,11791148 __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL)));11801180-}11811181-/*:*/1182114911831183-/*11501150+ pgdir->last_host_cpu = raw_smp_processor_id();11511151+}11521152+11531153+/*H:49011841154 * We've made it through the page table code. Perhaps our tired brains are11851155 * still processing the details, or perhaps we're simply glad it's over.11861156 *