* [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
* [kvm-unit-tests] x86: smap: add smap check to unittests.cfg
2015-11-16 7:53 [kvm-unit-tests] x86: pkeys: add test for PKEYS Huaitong Han
@ 2015-11-16 7:53 ` 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
1 sibling, 1 reply; 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/x86/unittests.cfg b/x86/unittests.cfg
index 14e36a4..6d3dc89 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -72,6 +72,10 @@ groups = vmexit
file = access.flat
arch = x86_64
+[smap]
+file = smap.flat
+extra_params = -cpu host
+
[pku]
file = pku.flat
arch = x86_64
--
2.4.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [kvm-unit-tests] x86: pkeys: add test for PKEYS
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:05 ` Paolo Bonzini
1 sibling, 0 replies; 4+ messages in thread
From: Paolo Bonzini @ 2015-11-17 16:05 UTC (permalink / raw)
To: Huaitong Han, mtosatti; +Cc: kvm
On 16/11/2015 08:53, Huaitong Han wrote:
> 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
This needs to be in config-x86_64.mak, because the 32-bit version will
have EFER.LMA=0. Otherwise looks good (and I've tested it with a
quick-and-dirty implementation of pkeys in QEMU).
Paolo
> 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
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [kvm-unit-tests] x86: smap: add smap check to unittests.cfg
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
0 siblings, 0 replies; 4+ messages in thread
From: Paolo Bonzini @ 2015-11-17 16:07 UTC (permalink / raw)
To: Huaitong Han, mtosatti; +Cc: kvm
On 16/11/2015 08:53, Huaitong Han wrote:
> Signed-off-by: Huaitong Han <huaitong.han@intel.com>
>
> diff --git a/x86/unittests.cfg b/x86/unittests.cfg
> index 14e36a4..6d3dc89 100644
> --- a/x86/unittests.cfg
> +++ b/x86/unittests.cfg
> @@ -72,6 +72,10 @@ groups = vmexit
> file = access.flat
> arch = x86_64
>
> +[smap]
> +file = smap.flat
> +extra_params = -cpu host
> +
> [pku]
> file = pku.flat
> arch = x86_64
>
Applied, thanks.
Paolo
^ permalink raw reply [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.