Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp317291pxb; Thu, 5 Nov 2020 00:18:15 -0800 (PST) X-Google-Smtp-Source: ABdhPJyw/VVt/WnJlf8uMTgUY6dFLr+56WBoaIBn1GC4YjvKN2RmrChmq2WMTh26SgnLUl7PLBcF X-Received: by 2002:a50:d78f:: with SMTP id w15mr1381228edi.227.1604564295371; Thu, 05 Nov 2020 00:18:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1604564295; cv=none; d=google.com; s=arc-20160816; b=NZ5ejthonNqxet9bwMB92EOZyrY4rrT7JttM5CHawxzx1bYMeQRJrIFQWEllsXa5bb DzvxbcOKIbHCS+hTb92HB/DHNWnGZiyLJCpcuSoTK8OmQlAp44vGTJqDEXwNfVoWio1J YnCVWO8PsRnhSlBqltgKbkw5ngRRwd0zDVtwJtKcEfe6sUd7HjYDRzq39QCY9kqoVrQW Mu2DpBAxYiFAdFn7N9K2KIffId2P/gUPw067a9jFNCT319XvgnoLxswoSgCXrhqil4mh tDH/XnizVkR7z1MRXFdJD59V4PP4Qvb1j9vGrqt3aFwDNA1FLK3lL3edvQkMjjhD8CUX OQKQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from:ironport-sdr:ironport-sdr; bh=0DJG8EpUVu5gRk9JPMJJ6UXHYfmpK2cs0KgT8l8EyN8=; b=G9jh+cJ/S/1HOOOMhQZPvbzPmyX0deAYLlU8/86XtvKrQsvBfajNdr0qfCdXx6EnCe JUX0WwzwxaITvA6f7SOiIhXxglMPDW7K7dp62ypEG7/fGGX7L2GpZ3Kk01r4yf8vvYSk vKnJLJp3fJ37bz2VjkdblvqoH+s2G0yRhn0wQa9nMx3MjIgbRL1sjq1mcyBq3XkckAn6 1m0wU/yF0bEFOcB3uADjhqRDVBeASxdZUcbgNIMMvZKRpNHGdzkHfsv78BOaUDAyi7b6 rByx1BicsNykvEms8sRWu3+gSnaZ+E20zDiPhl9sC1t5cXznTkCjc0Qa7IMgY7GRIasY rmRw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id bw14si538180ejb.319.2020.11.05.00.17.52; Thu, 05 Nov 2020 00:18:15 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730681AbgKEIQI (ORCPT + 99 others); Thu, 5 Nov 2020 03:16:08 -0500 Received: from mga04.intel.com ([192.55.52.120]:39805 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730543AbgKEIQE (ORCPT ); Thu, 5 Nov 2020 03:16:04 -0500 IronPort-SDR: mCkOL5x7k9jhsJRPvZBcBepVBT9xJXq0xCQt2y+IISg2IcPgOmtmOpBt+jSdC6W6HKRDfLbkkM Q4+e0/8FnnOw== X-IronPort-AV: E=McAfee;i="6000,8403,9795"; a="166755749" X-IronPort-AV: E=Sophos;i="5.77,453,1596524400"; d="scan'208";a="166755749" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Nov 2020 00:16:03 -0800 IronPort-SDR: 05IwEy/VozTgYE7NroiL4avmOZ0AmLLlBB1AfnxpHEKV7Rbl5N5VPmInirU4uezqeSZc9PQEtf 6RkImQi8SCog== X-IronPort-AV: E=Sophos;i="5.77,453,1596524400"; d="scan'208";a="539281547" Received: from chenyi-pc.sh.intel.com ([10.239.159.72]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Nov 2020 00:16:01 -0800 From: Chenyi Qiang To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , Xiaoyao Li Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [kvm-unit-tests PATCH] x86: Add tests for PKS Date: Thu, 5 Nov 2020 16:18:05 +0800 Message-Id: <20201105081805.5674-9-chenyi.qiang@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201105081805.5674-1-chenyi.qiang@intel.com> References: <20201105081805.5674-1-chenyi.qiang@intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This unit-test is intended to test the KVM support for Protection Keys for Supervisor Pages (PKS). If CR4.PKS is set in long mode, supervisor pkeys are checked in addition to normal paging protections and Access or Write can be disabled via a MSR update without TLB flushes when permissions change. Signed-off-by: Chenyi Qiang --- lib/x86/msr.h | 1 + lib/x86/processor.h | 2 + x86/Makefile.x86_64 | 1 + x86/pks.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 5 ++ 5 files changed, 155 insertions(+) create mode 100644 x86/pks.c diff --git a/lib/x86/msr.h b/lib/x86/msr.h index 6ef5502..e36934b 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -209,6 +209,7 @@ #define MSR_IA32_EBL_CR_POWERON 0x0000002a #define MSR_IA32_FEATURE_CONTROL 0x0000003a #define MSR_IA32_TSC_ADJUST 0x0000003b +#define MSR_IA32_PKRS 0x000006e1 #define FEATURE_CONTROL_LOCKED (1<<0) #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) diff --git a/lib/x86/processor.h b/lib/x86/processor.h index 74a2498..985fdd0 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -50,6 +50,7 @@ #define X86_CR4_SMEP 0x00100000 #define X86_CR4_SMAP 0x00200000 #define X86_CR4_PKE 0x00400000 +#define X86_CR4_PKS 0x01000000 #define X86_EFLAGS_CF 0x00000001 #define X86_EFLAGS_FIXED 0x00000002 @@ -157,6 +158,7 @@ static inline u8 cpuid_maxphyaddr(void) #define X86_FEATURE_RDPID (CPUID(0x7, 0, ECX, 22)) #define X86_FEATURE_SPEC_CTRL (CPUID(0x7, 0, EDX, 26)) #define X86_FEATURE_ARCH_CAPABILITIES (CPUID(0x7, 0, EDX, 29)) +#define X86_FEATURE_PKS (CPUID(0x7, 0, ECX, 31)) #define X86_FEATURE_NX (CPUID(0x80000001, 0, EDX, 20)) #define X86_FEATURE_RDPRU (CPUID(0x80000008, 0, EBX, 4)) diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64 index af61d85..3a353df 100644 --- a/x86/Makefile.x86_64 +++ b/x86/Makefile.x86_64 @@ -20,6 +20,7 @@ tests += $(TEST_DIR)/tscdeadline_latency.flat tests += $(TEST_DIR)/intel-iommu.flat tests += $(TEST_DIR)/vmware_backdoors.flat tests += $(TEST_DIR)/rdpru.flat +tests += $(TEST_DIR)/pks.flat include $(SRCDIR)/$(TEST_DIR)/Makefile.common diff --git a/x86/pks.c b/x86/pks.c new file mode 100644 index 0000000..a3044cf --- /dev/null +++ b/x86/pks.c @@ -0,0 +1,146 @@ +#include "libcflat.h" +#include "x86/desc.h" +#include "x86/processor.h" +#include "x86/vm.h" +#include "x86/msr.h" + +#define CR0_WP_MASK (1UL << 16) +#define PTE_PKEY_BIT 59 +#define SUPER_BASE (1 << 24) +#define SUPER_VAR(v) (*((__typeof__(&(v))) (((unsigned long)&v) + SUPER_BASE))) + +volatile int pf_count = 0; +volatile unsigned save; +volatile unsigned test; + +static void set_cr0_wp(int wp) +{ + unsigned long cr0 = read_cr0(); + + cr0 &= ~CR0_WP_MASK; + if (wp) + cr0 |= CR0_WP_MASK; + write_cr0(cr0); +} + +void do_pf_tss(unsigned long error_code); +void do_pf_tss(unsigned long error_code) +{ + printf("#PF handler, error code: 0x%lx\n", error_code); + pf_count++; + save = test; + wrmsr(MSR_IA32_PKRS, 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" + "mov 9*8(%rsp), %rdi\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(void) +{ + pf_count = 0; + + invlpg(&test); + invlpg(&SUPER_VAR(test)); + wrmsr(MSR_IA32_PKRS, 0); + set_cr0_wp(0); +} + +int main(int ac, char **av) +{ + unsigned long i; + unsigned int pkey = 0x2; + unsigned int pkrs_ad = 0x10; + unsigned int pkrs_wd = 0x20; + + if (!this_cpu_has(X86_FEATURE_PKS)) { + printf("PKS not enabled\n"); + return report_summary(); + } + + setup_vm(); + setup_alt_stack(); + set_intr_alt_stack(14, pf_tss); + wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_LMA); + + // First 16MB are user pages + for (i = 0; i < SUPER_BASE; i += PAGE_SIZE) { + *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT); + invlpg((void *)i); + } + + // Present the same 16MB as supervisor pages in the 16MB-32MB range + for (i = SUPER_BASE; i < 2 * SUPER_BASE; i += PAGE_SIZE) { + *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~SUPER_BASE; + *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~PT_USER_MASK; + *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_PKS); + write_cr3(read_cr3()); + + init_test(); + set_cr0_wp(1); + wrmsr(MSR_IA32_PKRS, pkrs_ad); + SUPER_VAR(test) = 21; + report(pf_count == 1 && test == 21 && save == 0, + "write to supervisor page when pkrs is ad and wp == 1"); + + init_test(); + set_cr0_wp(0); + wrmsr(MSR_IA32_PKRS, pkrs_ad); + SUPER_VAR(test) = 22; + report(pf_count == 1 && test == 22 && save == 21, + "write to supervisor page when pkrs is ad and wp == 0"); + + init_test(); + set_cr0_wp(1); + wrmsr(MSR_IA32_PKRS, pkrs_wd); + SUPER_VAR(test) = 23; + report(pf_count == 1 && test == 23 && save == 22, + "write to supervisor page when pkrs is wd and wp == 1"); + + init_test(); + set_cr0_wp(0); + wrmsr(MSR_IA32_PKRS, pkrs_wd); + SUPER_VAR(test) = 24; + report(pf_count == 0 && test == 24, + "write to supervisor page when pkrs is wd and wp == 0"); + + init_test(); + set_cr0_wp(0); + wrmsr(MSR_IA32_PKRS, pkrs_wd); + test = 25; + report(pf_count == 0 && test == 25, + "write to user page when pkrs is wd and wp == 0"); + + init_test(); + set_cr0_wp(1); + wrmsr(MSR_IA32_PKRS, pkrs_wd); + test = 26; + report(pf_count == 0 && test == 26, + "write to user page when pkrs is wd and wp == 1"); + + init_test(); + wrmsr(MSR_IA32_PKRS, pkrs_ad); + (void)((__typeof__(&(test))) (((unsigned long)&test))); + report(pf_count == 0, "read from user page when pkrs is ad"); + + return report_summary(); +} diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 3a79151..b75419e 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -127,6 +127,11 @@ file = pku.flat arch = x86_64 extra_params = -cpu host +[pks] +file = pks.flat +arch = x86_64 +extra_params = -cpu host + [asyncpf] file = asyncpf.flat extra_params = -m 2048 -- 2.17.1