VMM: debug helper for checking KPT == EPT invariant
Not called from anywhere, but you can kfunc it or drop it wherever you
want (like EPT HPF, proc_free, etc).
diff --git a/kern/arch/x86/pmap64.c b/kern/arch/x86/pmap64.c
index 66e7129..29387d8 100644
--- a/kern/arch/x86/pmap64.c
+++ b/kern/arch/x86/pmap64.c
@@ -43,11 +43,22 @@
kpte_t *pml_walk(kpte_t *pml, uintptr_t va, int flags);
void map_segment(pgdir_t pgdir, uintptr_t va, size_t size, physaddr_t pa,
int perm, int pml_shift);
+int unmap_segment(pgdir_t pgdir, uintptr_t va, size_t size);
+
typedef int (*kpte_cb_t)(kpte_t *kpte, uintptr_t kva, int pml_shift,
bool visited_subs, void *arg);
int pml_for_each(kpte_t *pml, uintptr_t start, size_t len, kpte_cb_t callback,
void *arg);
-int unmap_segment(pgdir_t pgdir, uintptr_t va, size_t size);
+/* Helpers for PML for-each walks */
+static inline bool pte_is_final(pte_t pte, int pml_shift)
+{
+ return (pml_shift == PML1_SHIFT) || pte_is_jumbo(pte);
+}
+
+static inline bool pte_is_intermediate(pte_t pte, int pml_shift)
+{
+ return !pte_is_final(pte, pml_shift);
+}
/* Helper: gets the kpte_t pointer which is the base of the PML4 from pgdir */
static kpte_t *pgdir_get_kpt(pgdir_t pgdir)
@@ -661,3 +672,46 @@
pml_for_each(pgdir, KERNBASE, VPT - KERNBASE, print_pte, 0);
pml_for_each(pgdir, VPT_TOP, MAX_VADDR - VPT_TOP, print_pte, 0);
}
+
+/* Debug helper - makes sure the KPT == EPT for [0, UVPT) */
+int debug_check_kpt_ept(void)
+{
+ int db_cb(kpte_t *kpte, uintptr_t kva, int shift, bool visited_subs,
+ void *data)
+ {
+ epte_t *epte = kpte_to_epte(kpte);
+ char *reason;
+ int pa_offset = 0;
+
+ if (kpte_is_present(kpte) != epte_is_present(epte)) {
+ reason = "present bit";
+ goto fail;
+ }
+ if (kpte_is_mapped(kpte) != epte_is_mapped(epte)) {
+ reason = "mapped or not";
+ goto fail;
+ }
+ if (kpte_is_jumbo(kpte) != epte_is_jumbo(epte)) {
+ reason = "jumbo";
+ goto fail;
+ }
+ /* Intermediate PTEs have the EPTE pointing to PADDR + PGSIZE */
+ if (pte_is_present(kpte) && pte_is_intermediate(kpte, shift))
+ pa_offset = PGSIZE;
+ if (kpte_get_paddr(kpte) + pa_offset != epte_get_paddr(epte)) {
+ reason = "paddr";
+ goto fail;
+ }
+ if (kpte_get_perm(kpte) != epte_get_perm(epte)) {
+ reason = "permissions";
+ goto fail;
+ }
+ return 0;
+
+fail:
+ panic("kpte %p (%p) epte %p (%p) kva %p shift %d: %s",
+ kpte, *kpte, epte, *epte, kva, shift, reason);
+ return -1;
+ }
+ return pml_for_each(current->env_pgdir.kpte, 0, UVPT - 0, db_cb, 0);
+}