All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: Huaitong Han <huaitong.han@intel.com>, mtosatti@redhat.com
Cc: kvm@vger.kernel.org
Subject: Re: [kvm-unit-tests] x86: pkeys: add test for PKEYS
Date: Tue, 17 Nov 2015 17:05:46 +0100	[thread overview]
Message-ID: <564B505A.2080404@redhat.com> (raw)
In-Reply-To: <1447660403-12167-1-git-send-email-huaitong.han@intel.com>



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
>  
> 

      parent reply	other threads:[~2015-11-17 16:05 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Paolo Bonzini [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=564B505A.2080404@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=huaitong.han@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=mtosatti@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.