[kvm-unit-tests PATCH 1/3] x86: Add routines to set/clear PT_USER_MASK for all pages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add following 2 routines :
1) set_user_mask_all() - set PT_USER_MASK for all the levels of page tables
2) clear_user_mask_all - clear PT_USER_MASK for all the levels of page tables

commit 916635a813e975600335c6c47250881b7a328971
(nSVM: Add test for NPT reserved bit and #NPF error code behavior)
clears PT_USER_MASK for all svm testcases. Any tests that requires
usermode access will fail after this commit.

Usermode function needs to be called from L2 guest to generate
AC exception and calling usermode function with supervisor pages
generates #PF exception with error code 0004

Add solution to above mentioned problem which is to set
PT_USER_MASK for all pages in the initialization of #AC exception
test and clear them in uninitialization of #AC exception at last.
AC exception test works fine without hampering other test cases with
this solution.

Signed-off-by: Manali Shukla <manali.shukla@xxxxxxx>
---
 lib/x86/vm.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/x86/vm.h |  3 +++
 2 files changed, 57 insertions(+)

diff --git a/lib/x86/vm.c b/lib/x86/vm.c
index 56be57b..f3a7ae8 100644
--- a/lib/x86/vm.c
+++ b/lib/x86/vm.c
@@ -37,6 +37,60 @@ pteval_t *install_pte(pgd_t *cr3,
     return &pt[offset];
 }
 
+/*
+ * set PT_USER_MASK bit for all levels of page tables
+ */
+
+void set_user_mask_all(pteval_t *pt, int level)
+{
+    pteval_t pte, *ptep;
+    int i;
+
+    if (level == PAGE_LEVEL)
+        pte_opt_mask |= PT_USER_MASK;
+
+    for (i = 0; i < 512; i++) {
+        ptep = &pt[i];
+        pte = *ptep;
+
+        if ((pte & PT_PRESENT_MASK) && !(pte & PT_USER_MASK)) {
+            *ptep |= PT_USER_MASK;
+
+            if (level == 1 || pte & PT_PAGE_SIZE_MASK)
+                continue;
+
+            set_user_mask_all(phys_to_virt(pte & 0xffffffffff000ull), level - 1);
+        }
+    }
+}
+
+
+/*
+ * clear PT_USER_MASK bit for all levels of page tables
+ */
+
+void clear_user_mask_all(pteval_t *pt, int level)
+{
+    pteval_t pte, *ptep;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        ptep = &pt[i];
+        pte = *ptep;
+
+        if ((pte & PT_PRESENT_MASK) && (pte & PT_USER_MASK)) {
+            *ptep &= ~PT_USER_MASK;
+
+            if (level == 1 || pte & PT_PAGE_SIZE_MASK)
+                continue;
+
+            clear_user_mask_all(phys_to_virt(pte & 0xffffffffff000ull), level - 1);
+        }
+    }
+    if (level == PAGE_LEVEL)
+        pte_opt_mask &= ~PT_USER_MASK;
+}
+
 /*
  * Finds last PTE in the mapping of @virt that's at or above @lowest_level. The
  * returned PTE isn't necessarily present, but its parent is.
diff --git a/lib/x86/vm.h b/lib/x86/vm.h
index 4c6dff9..75715e5 100644
--- a/lib/x86/vm.h
+++ b/lib/x86/vm.h
@@ -38,6 +38,9 @@ pteval_t *install_large_page(pgd_t *cr3, phys_addr_t phys, void *virt);
 void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt);
 bool any_present_pages(pgd_t *cr3, void *virt, size_t len);
 
+void set_user_mask_all(pteval_t *pt, int level);
+void clear_user_mask_all(pteval_t *pt, int level);
+
 static inline void *current_page_table(void)
 {
 	return phys_to_virt(read_cr3());
-- 
2.30.2




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux