All of lore.kernel.org
 help / color / mirror / Atom feed
* [kvm-unit-tests] x86: pkeys: add test for PKEYS
@ 2015-11-16  7:53 Huaitong Han
  2015-11-16  7:53 ` [kvm-unit-tests] x86: smap: add smap check to unittests.cfg Huaitong Han
  2015-11-17 16:05 ` [kvm-unit-tests] x86: pkeys: add test for PKEYS Paolo Bonzini
  0 siblings, 2 replies; 4+ messages in thread
From: Huaitong Han @ 2015-11-16  7:53 UTC (permalink / raw)
  To: pbonzini, mtosatti; +Cc: kvm, Huaitong Han

Signed-off-by: Huaitong Han <huaitong.han@intel.com>

diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak
index c2f9908..2ef98cc 100644
--- a/config/config-x86-common.mak
+++ b/config/config-x86-common.mak
@@ -36,7 +36,8 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/kvmclock_test.flat  $(TEST_DIR)/eventinj.flat \
                $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \
                $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \
-               $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat
+               $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \
+               $(TEST_DIR)/pku.flat
 
 ifdef API
 tests-common += api/api-sample
@@ -104,6 +105,8 @@ $(TEST_DIR)/pcid.elf: $(cstart.o) $(TEST_DIR)/pcid.o
 
 $(TEST_DIR)/smap.elf: $(cstart.o) $(TEST_DIR)/smap.o
 
+$(TEST_DIR)/pku.elf: $(cstart.o) $(TEST_DIR)/pku.o
+
 $(TEST_DIR)/vmx.elf: $(cstart.o) $(TEST_DIR)/vmx.o $(TEST_DIR)/vmx_tests.o
 
 $(TEST_DIR)/debug.elf: $(cstart.o) $(TEST_DIR)/debug.o
diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index 7973879..f7aa5ec 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -26,6 +26,7 @@
 #define X86_CR4_PAE    0x00000020
 #define X86_CR4_PCIDE  0x00020000
 #define X86_CR4_SMAP   0x00200000
+#define X86_CR4_PKE    0x00400000
 
 #define X86_IA32_EFER          0xc0000080
 #define X86_EFER_LMA           (1UL << 8)
diff --git a/x86/pku.c b/x86/pku.c
new file mode 100644
index 0000000..0e00b99
--- /dev/null
+++ b/x86/pku.c
@@ -0,0 +1,161 @@
+#include "libcflat.h"
+#include "x86/desc.h"
+#include "x86/processor.h"
+#include "x86/vm.h"
+#include "x86/msr.h"
+
+#define X86_FEATURE_PKU  3
+#define CR0_WP_MASK      (1UL << 16)
+#define PTE_PKEY_BIT     59
+#define USER_BASE        (1 << 24)
+#define USER_VAR(v)      (*((__typeof__(&(v))) (((unsigned long)&v) + USER_BASE)))
+
+volatile int pf_count = 0;
+volatile unsigned save;
+volatile unsigned test;
+
+void set_cr0_wp(int wp)
+{
+    unsigned long cr0 = read_cr0();
+
+    cr0 &= ~CR0_WP_MASK;
+    if (wp)
+        cr0 |= CR0_WP_MASK;
+    write_cr0(cr0);
+}
+
+static inline u32 read_pkru(void)
+{
+    unsigned int eax, edx;
+    unsigned int ecx = 0;
+    unsigned int pkru;
+
+    asm volatile(".byte 0x0f,0x01,0xee\n\t"
+                 : "=a" (eax), "=d" (edx)
+                 : "c" (ecx));
+    pkru = eax;
+    return pkru;
+}
+
+static void write_pkru(u32 pkru)
+{
+    unsigned int eax = pkru;
+    unsigned int ecx = 0;
+    unsigned int edx = 0;
+
+    asm volatile(".byte 0x0f,0x01,0xef\n\t"
+        : : "a" (eax), "c" (ecx), "d" (edx));
+}
+
+void do_pf_tss(unsigned long error_code)
+{
+    pf_count++;
+    save = test;
+    write_pkru(0);
+}
+
+extern void pf_tss(void);
+
+asm ("pf_tss: \n\t"
+#ifdef __x86_64__
+    // no task on x86_64, save/restore caller-save regs
+    "push %rax; push %rcx; push %rdx; push %rsi; push %rdi\n"
+    "push %r8; push %r9; push %r10; push %r11\n"
+#endif
+    "call do_pf_tss \n\t"
+#ifdef __x86_64__
+    "pop %r11; pop %r10; pop %r9; pop %r8\n"
+    "pop %rdi; pop %rsi; pop %rdx; pop %rcx; pop %rax\n"
+#endif
+    "add $"S", %"R "sp\n\t" // discard error code
+    "iret"W" \n\t"
+    "jmp pf_tss\n\t"
+    );
+
+static void init_test()
+{
+    pf_count = 0;
+
+    invlpg(&test);
+    invlpg(&USER_VAR(test));
+    write_pkru(0);
+    set_cr0_wp(0);
+}
+
+int main(int ac, char **av)
+{
+    unsigned long i;
+    unsigned int pkey = 0x2;
+    unsigned int pkru_ad = 0x10;
+    unsigned int pkru_wd = 0x20;
+
+    if (!(cpuid_indexed(7, 0).c & (1 << X86_FEATURE_PKU))) {
+        printf("PKU not enabled, exiting\n");
+        exit(1);
+    }
+
+    setup_vm();
+    setup_alt_stack();
+    set_intr_alt_stack(14, pf_tss);
+    wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_LMA);
+
+    for (i = 0; i < USER_BASE; i += PAGE_SIZE) {
+        *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~PTE_USER;
+        *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT);
+        invlpg((void *)i);
+    }
+
+    for (i = USER_BASE; i < 2 * USER_BASE; i += PAGE_SIZE) {
+        *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~USER_BASE;
+        *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT);
+        invlpg((void *)i);
+    }
+
+    write_cr4(read_cr4() | X86_CR4_PKE);
+    write_cr3(read_cr3());
+
+    init_test();
+    set_cr0_wp(1);
+    write_pkru(pkru_ad);
+    test = 21;
+    report("write to supervisor page when pkru is ad and wp == 1", pf_count == 0 && test == 21);
+
+    init_test();
+    set_cr0_wp(0);
+    write_pkru(pkru_ad);
+    test = 22;
+    report("write to supervisor page when pkru is ad and wp == 0", pf_count == 0 && test == 22);
+
+    init_test();
+    set_cr0_wp(1);
+    write_pkru(pkru_wd);
+    test = 23;
+    report("write to supervisor page when pkru is wd and wp == 1", pf_count == 0 && test == 23);
+
+    init_test();
+    set_cr0_wp(0);
+    write_pkru(pkru_wd);
+    test = 24;
+    report("write to supervisor page when pkru is wd and wp == 0", pf_count == 0 && test == 24);
+
+    init_test();
+    write_pkru(pkru_wd);
+    set_cr0_wp(0);
+    USER_VAR(test) = 25;
+    report("write to user page when pkru is wd and wp == 0", pf_count == 0 && test == 25);
+
+    init_test();
+    write_pkru(pkru_wd);
+    set_cr0_wp(1);
+    USER_VAR(test) = 26;
+    report("write to user page when pkru is wd and wp == 1", pf_count == 1 && test == 26 && save == 25);
+
+    init_test();
+    write_pkru(pkru_ad);
+    (void)USER_VAR(test);
+    report("read from user page when pkru is ad", pf_count == 1 && save == 26);
+
+    // TODO: implicit kernel access from ring 3 (e.g. int)
+
+    return report_summary();
+}
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 337cc19..14e36a4 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -72,6 +72,11 @@ groups = vmexit
 file = access.flat
 arch = x86_64
 
+[pku]
+file = pku.flat
+arch = x86_64
+extra_params = -cpu host
+
 #[asyncpf]
 #file = asyncpf.flat
 
-- 
2.4.3


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-11-17 16:08 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-16  7:53 [kvm-unit-tests] x86: pkeys: add test for PKEYS Huaitong Han
2015-11-16  7:53 ` [kvm-unit-tests] x86: smap: add smap check to unittests.cfg Huaitong Han
2015-11-17 16:07   ` Paolo Bonzini
2015-11-17 16:05 ` [kvm-unit-tests] x86: pkeys: add test for PKEYS Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.