Skip to contentSkip to conversation

KVM test: separate expect status updates from ac_test_setup_pte() function

PATCH Applied Xiao Guangrong 2 participants 4 messages Jul 23, 2010 – Jul 27, 2010 KVM

lore
Share & tools
lore
#0 lore raw

PATCH 1/3 KVM test: separate expect status updates from ac_test_setup_pte() function

Separate expect status updates operation, later we can just modify the access way(i,e the AC_ACCESS_* flags)

---
 kvm/test/x86/access.c |  131 ++++++++++++++++++++++++++-----------------------
 1 files changed, 69 insertions(+), 62 deletions(-)
kvm/test/x86/access.c +69 -62
index 3338fbc..c7d7e29 100644
@@ -302,72 +302,12 @@ void ac_test_reset_pt_pool(ac_test_t *at)
     at->pt_pool_current = 0;
 }
 
-void ac_test_setup_pte(ac_test_t *at)
+void ac_set_expected_status(ac_test_t *at)
 {
-    unsigned long root = read_cr3();
     int pde_valid, pte_valid;
 
-    if (!ac_test_enough_room(at))
-	ac_test_reset_pt_pool(at);
-
-    at->ptep = 0;
-    for (int i = 4; i >= 1 && (i >= 2 || !at->flags[AC_PDE_PSE]); --i) {
-	pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK);
-	unsigned index = ((unsigned long)at->virt >> (12 + (i-1) * 9)) & 511;
-	pt_element_t pte = 0;
-	switch (i) {
-	case 4:
-	case 3:
-	    pte = vroot[index];
-	    pte = ac_test_alloc_pt(at) | PT_PRESENT_MASK;
-	    pte |= PT_WRITABLE_MASK | PT_USER_MASK;
-	    break;
-	case 2:
-	    if (!at->flags[AC_PDE_PSE])
-		pte = ac_test_alloc_pt(at);
-	    else {
-		pte = at->phys & PT_PSE_BASE_ADDR_MASK;
-		pte |= PT_PSE_MASK;
-	    }
-	    if (at->flags[AC_PDE_PRESENT])
-		pte |= PT_PRESENT_MASK;
-	    if (at->flags[AC_PDE_WRITABLE])
-		pte |= PT_WRITABLE_MASK;
-	    if (at->flags[AC_PDE_USER])
-		pte |= PT_USER_MASK;
-	    if (at->flags[AC_PDE_ACCESSED])
-		pte |= PT_ACCESSED_MASK;
-	    if (at->flags[AC_PDE_DIRTY])
-		pte |= PT_DIRTY_MASK;
-	    if (at->flags[AC_PDE_NX])
-		pte |= PT_NX_MASK;
-	    if (at->flags[AC_PDE_BIT51])
-		pte |= 1ull << 51;
-	    at->pdep = &vroot[index];
-	    break;
-	case 1:
-	    pte = at->phys & PT_BASE_ADDR_MASK;
-	    if (at->flags[AC_PTE_PRESENT])
-		pte |= PT_PRESENT_MASK;
-	    if (at->flags[AC_PTE_WRITABLE])
-		pte |= PT_WRITABLE_MASK;
-	    if (at->flags[AC_PTE_USER])
-		pte |= PT_USER_MASK;
-	    if (at->flags[AC_PTE_ACCESSED])
-		pte |= PT_ACCESSED_MASK;
-	    if (at->flags[AC_PTE_DIRTY])
-		pte |= PT_DIRTY_MASK;
-	    if (at->flags[AC_PTE_NX])
-		pte |= PT_NX_MASK;
-	    if (at->flags[AC_PTE_BIT51])
-		pte |= 1ull << 51;
-	    at->ptep = &vroot[index];
-	    break;
-	}
-	vroot[index] = pte;
-	root = vroot[index];
-    }
     invlpg(at->virt);
+
     if (at->ptep)
 	at->expected_pte = *at->ptep;
     at->expected_pde = *at->pdep;
@@ -467,6 +407,73 @@ fault:
         at->expected_error &= ~PFERR_FETCH_MASK;
 }
 
+void ac_test_setup_pte(ac_test_t *at)
+{
+    unsigned long root = read_cr3();
+
+    if (!ac_test_enough_room(at))
+	ac_test_reset_pt_pool(at);
+
+    at->ptep = 0;
+    for (int i = 4; i >= 1 && (i >= 2 || !at->flags[AC_PDE_PSE]); --i) {
+	pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK);
+	unsigned index = ((unsigned long)at->virt >> (12 + (i-1) * 9)) & 511;
+	pt_element_t pte = 0;
+	switch (i) {
+	case 4:
+	case 3:
+	    pte = vroot[index];
+	    pte = ac_test_alloc_pt(at) | PT_PRESENT_MASK;
+	    pte |= PT_WRITABLE_MASK | PT_USER_MASK;
+	    break;
+	case 2:
+	    if (!at->flags[AC_PDE_PSE])
+		pte = ac_test_alloc_pt(at);
+	    else {
+		pte = at->phys & PT_PSE_BASE_ADDR_MASK;
+		pte |= PT_PSE_MASK;
+	    }
+	    if (at->flags[AC_PDE_PRESENT])
+		pte |= PT_PRESENT_MASK;
+	    if (at->flags[AC_PDE_WRITABLE])
+		pte |= PT_WRITABLE_MASK;
+	    if (at->flags[AC_PDE_USER])
+		pte |= PT_USER_MASK;
+	    if (at->flags[AC_PDE_ACCESSED])
+		pte |= PT_ACCESSED_MASK;
+	    if (at->flags[AC_PDE_DIRTY])
+		pte |= PT_DIRTY_MASK;
+	    if (at->flags[AC_PDE_NX])
+		pte |= PT_NX_MASK;
+	    if (at->flags[AC_PDE_BIT51])
+		pte |= 1ull << 51;
+	    at->pdep = &vroot[index];
+	    break;
+	case 1:
+	    pte = at->phys & PT_BASE_ADDR_MASK;
+	    if (at->flags[AC_PTE_PRESENT])
+		pte |= PT_PRESENT_MASK;
+	    if (at->flags[AC_PTE_WRITABLE])
+		pte |= PT_WRITABLE_MASK;
+	    if (at->flags[AC_PTE_USER])
+		pte |= PT_USER_MASK;
+	    if (at->flags[AC_PTE_ACCESSED])
+		pte |= PT_ACCESSED_MASK;
+	    if (at->flags[AC_PTE_DIRTY])
+		pte |= PT_DIRTY_MASK;
+	    if (at->flags[AC_PTE_NX])
+		pte |= PT_NX_MASK;
+	    if (at->flags[AC_PTE_BIT51])
+		pte |= 1ull << 51;
+	    at->ptep = &vroot[index];
+	    break;
+	}
+	vroot[index] = pte;
+	root = vroot[index];
+    }
+    ac_set_expected_status(at);
+}
+
 static void ac_test_check(ac_test_t *at, _Bool *success_ret, _Bool cond,
                           const char *fmt, ...)
 {
Signature · 1 line
1.6.1.2
#1 lore raw

PATCH 2/3 KVM test: separate pool from ac_test_t struct

Separate pool from the ac_test_t struct, later we will use multiple ac_test_t units, those units should allocate pte from the same pool to avoid mapping to the same pte

---
 kvm/test/x86/access.c |   71 ++++++++++++++++++++++++++++--------------------
 1 files changed, 41 insertions(+), 30 deletions(-)
kvm/test/x86/access.c +41 -30
index ebadae9..be51a55 100644
@@ -127,12 +127,15 @@ typedef struct {
 } idt_entry_t;
 
 typedef struct {
-    unsigned flags[NR_AC_FLAGS];
-    void *virt;
-    pt_element_t phys;
     pt_element_t pt_pool;
     unsigned pt_pool_size;
     unsigned pt_pool_current;
+} ac_pool_t;
+
+typedef struct {
+    unsigned flags[NR_AC_FLAGS];
+    void *virt;
+    pt_element_t phys;
     pt_element_t *ptep;
     pt_element_t expected_pte;
     pt_element_t *pdep;
@@ -225,23 +228,29 @@ void set_efer_nx(int nx)
     wrmsr(MSR_EFER, efer);
 }
 
+static void ac_env_int(ac_pool_t *pool)
+{
+    static idt_entry_t idt[256];
+
+    memset(idt, 0, sizeof(idt));
+    lidt(idt, 256);
+    extern char page_fault, kernel_entry;
+    set_idt_entry(&idt[14], &page_fault, 0);
+    set_idt_entry(&idt[0x20], &kernel_entry, 3);
 
-void ac_test_init(ac_test_t *at)
+    pool->pt_pool = 33 * 1024 * 1024;
+    pool->pt_pool_size = 120 * 1024 * 1024 - pool->pt_pool;
+    pool->pt_pool_current = 0;
+}
+
+void ac_test_init(ac_test_t *at, void *virt)
 {
     wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
     set_cr0_wp(1);
     for (int i = 0; i < NR_AC_FLAGS; ++i)
 	at->flags[i] = 0;
-    at->virt = (void *)(0x123400000000 + 16 * smp_id());
+    at->virt = virt;
     at->phys = 32 * 1024 * 1024;
-    at->pt_pool = 33 * 1024 * 1024;
-    at->pt_pool_size = 120 * 1024 * 1024 - at->pt_pool;
-    at->pt_pool_current = 0;
-    memset(at->idt, 0, sizeof at->idt);
-    lidt(at->idt, 256);
-    extern char page_fault, kernel_entry;
-    set_idt_entry(&at->idt[14], &page_fault, 0);
-    set_idt_entry(&at->idt[0x20], &kernel_entry, 3);
 }
 
 int ac_test_bump_one(ac_test_t *at)
@@ -285,21 +294,21 @@ void invlpg(void *addr)
     asm volatile ("invlpg (%0)" : : "r"(addr));
 }
 
-pt_element_t ac_test_alloc_pt(ac_test_t *at)
+pt_element_t ac_test_alloc_pt(ac_pool_t *pool)
 {
-    pt_element_t ret = at->pt_pool + at->pt_pool_current;
-    at->pt_pool_current += PAGE_SIZE;
+    pt_element_t ret = pool->pt_pool + pool->pt_pool_current;
+    pool->pt_pool_current += PAGE_SIZE;
     return ret;
 }
 
-_Bool ac_test_enough_room(ac_test_t *at)
+_Bool ac_test_enough_room(ac_pool_t *pool)
 {
-    return at->pt_pool_current + 4 * PAGE_SIZE <= at->pt_pool_size;
+    return pool->pt_pool_current + 4 * PAGE_SIZE <= pool->pt_pool_size;
 }
 
-void ac_test_reset_pt_pool(ac_test_t *at)
+void ac_test_reset_pt_pool(ac_pool_t *pool)
 {
-    at->pt_pool_current = 0;
+    pool->pt_pool_current = 0;
 }
 
 void ac_set_expected_status(ac_test_t *at)
@@ -407,12 +416,12 @@ fault:
         at->expected_error &= ~PFERR_FETCH_MASK;
 }
 
-void ac_test_setup_pte(ac_test_t *at)
+void ac_test_setup_pte(ac_test_t *at, ac_pool_t *pool)
 {
     unsigned long root = read_cr3();
 
-    if (!ac_test_enough_room(at))
-	ac_test_reset_pt_pool(at);
+    if (!ac_test_enough_room(pool))
+	ac_test_reset_pt_pool(pool);
 
     at->ptep = 0;
     for (int i = 4; i >= 1 && (i >= 2 || !at->flags[AC_PDE_PSE]); --i) {
@@ -423,12 +432,12 @@ void ac_test_setup_pte(ac_test_t *at)
 	case 4:
 	case 3:
 	    pte = vroot[index];
-	    pte = ac_test_alloc_pt(at) | PT_PRESENT_MASK;
+	    pte = ac_test_alloc_pt(pool) | PT_PRESENT_MASK;
 	    pte |= PT_WRITABLE_MASK | PT_USER_MASK;
 	    break;
 	case 2:
 	    if (!at->flags[AC_PDE_PSE])
-		pte = ac_test_alloc_pt(at);
+		pte = ac_test_alloc_pt(pool);
 	    else {
 		pte = at->phys & PT_PSE_BASE_ADDR_MASK;
 		pte |= PT_PSE_MASK;
@@ -620,29 +629,31 @@ static void ac_test_show(ac_test_t *at)
     printf("%s", line);
 }
 
-int ac_test_exec(ac_test_t *at)
+int ac_test_exec(ac_test_t *at, ac_pool_t *pool)
 {
     int r;
 
     if (verbose) {
         ac_test_show(at);
     }
-    ac_test_setup_pte(at);
+    ac_test_setup_pte(at, pool);
     r = ac_test_do_access(at);
     return r;
 }
 
 int ac_test_run(void)
 {
-    static ac_test_t at;
+    ac_test_t at;
+    ac_pool_t pool;
     int tests, successes;
 
     printf("run\n");
     tests = successes = 0;
-    ac_test_init(&at);
+    ac_env_int(&pool);
+    ac_test_init(&at, (void *)(0x123400000000 + 16 * smp_id()));
     do {
 	++tests;
-	successes += ac_test_exec(&at);
+	successes += ac_test_exec(&at, &pool);
     } while (ac_test_bump(&at));
 
     printf("\n%d tests, %d failures\n", tests, tests - successes);
Signature · 1 line
1.6.1.2
#2 lore raw

PATCH 3/3 KVM test: add test case to trigger the bug which cause hugepage mapping corrupt

The test case can trigger the bug that fixed by commit e09e90a5 in the kvm tree to avoid regression

---
 kvm/test/x86/access.c |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 46 insertions(+), 0 deletions(-)
kvm/test/x86/access.c +46 -0
index be51a55..a833df5 100644
@@ -629,6 +629,49 @@ static void ac_test_show(ac_test_t *at)
     printf("%s", line);
 }
 
+/*
+ * This test case is used to triger the bug which is fixed by
+ * commit e09e90a5 in the kvm tree
+ */
+static int corrupt_hugepage_triger(ac_pool_t *pool)
+{
+    ac_test_t at1, at2;
+
+    ac_test_init(&at1, (void *)(0x123400000000));
+    ac_test_init(&at2, (void *)(0x666600000000));
+
+    at2.flags[AC_CPU_CR0_WP] = 1;
+    at2.flags[AC_PDE_PSE] = 1;
+    at2.flags[AC_PDE_PRESENT] = 1;
+    ac_test_setup_pte(&at2, pool);
+    if (!ac_test_do_access(&at2))
+        goto err;
+
+    at1.flags[AC_CPU_CR0_WP] = 1;
+    at1.flags[AC_PDE_PSE] = 1;
+    at1.flags[AC_PDE_WRITABLE] = 1;
+    at1.flags[AC_PDE_PRESENT] = 1;
+    ac_test_setup_pte(&at1, pool);
+    if (!ac_test_do_access(&at1))
+        goto err;
+
+    at1.flags[AC_ACCESS_WRITE] = 1;
+    ac_set_expected_status(&at1);
+    if (!ac_test_do_access(&at1))
+        goto err;
+
+    at2.flags[AC_ACCESS_WRITE] = 1;
+    ac_set_expected_status(&at2);
+    if (!ac_test_do_access(&at2))
+        goto err;
+
+    return 1;
+
+err:
+    printf("corrupt_hugepage_triger test fail\n");
+    return 0;
+}
+
 int ac_test_exec(ac_test_t *at, ac_pool_t *pool)
 {
     int r;
@@ -656,6 +699,9 @@ int ac_test_run(void)
 	successes += ac_test_exec(&at, &pool);
     } while (ac_test_bump(&at));
 
+    ++tests;
+    successes += corrupt_hugepage_triger(&pool);
+
     printf("\n%d tests, %d failures\n", tests, tests - successes);
 
     return successes == tests;
Signature · 1 line
1.6.1.2
#3 lore raw
In reply to Xiao Guangrong
Quoted 8 lines · Xiao Guangrong

Separate expect status updates operation, later we can just modify the access way(i,e the AC_ACCESS_* flags)

---
 kvm/test/x86/access.c |  131 ++++++++++++++++++++++++++-----------------------
 1 files changed, 69 insertions(+), 62 deletions(-)

Applied all 3, thanks.