* [PATCH v3 0/7] KVM, pkeys: add memory protection-key support
@ 2015-11-18 5:43 Huaitong Han
2015-11-18 5:43 ` [PATCH v3 1/7] KVM, pkeys: expose CPUID/CR4 to guest Huaitong Han
` (7 more replies)
0 siblings, 8 replies; 11+ messages in thread
From: Huaitong Han @ 2015-11-18 5:43 UTC (permalink / raw)
To: pbonzini, gleb; +Cc: kvm, Huaitong Han
Changes in v3:
*Add comments for patch that disable PKU feature without ept.
Changes in v2:
*Add pku.c for kvm-unit-tests.
*Optimize permission_fault codes for patch4.
*Delete is_long_mode and PK for patch5.
*Squash cpuid and cr4 patches.
The protection-key feature provides an additional mechanism by which IA-32e
paging controls access to usermode addresses.
Hardware support for protection keys for user pages is enumerated with CPUID
feature flag CPUID.7.0.ECX[3]:PKU. Software support is CPUID.7.0.ECX[4]:OSPKE
with the setting of CR4.PKE(bit 22).
When CR4.PKE = 1, every linear address is associated with the 4-bit protection
key located in bits 62:59 of the paging-structure entry that mapped the page
containing the linear address. The PKRU register determines, for each
protection key, whether user-mode addresses with that protection key may be
read or written.
The PKRU register (protection key rights for user pages) is a 32-bit register
with the following format: for each i (0 ≤ i ≤ 15), PKRU[2i] is the
access-disable bit for protection key i (ADi); PKRU[2i+1] is the write-disable
bit for protection key i (WDi).
Software can use the RDPKRU and WRPKRU instructions with ECX = 0 to read and
write PKRU. In addition, the PKRU register is XSAVE-managed state and can thus
be read and written by instructions in the XSAVE feature set.
PFEC.PK (bit 5) is defined as protection key violations.
The specification of Protection Keys can be found at SDM (4.6.2, volume 3)
http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf.
The kernel native patchset have not yet been merged to upstream, you can found
at git://git.kernel.org/pub/scm/linux/kernel/git/daveh/x86-pkeys.git pkeys-v007.
Huaitong Han (7):
KVM, pkeys: expose CPUID/CR4 to guest
KVM, pkeys: disable pkeys for guests in non-paging mode
KVM, pkeys: update memeory permission bitmask for pkeys
KVM, pkeys: add pkeys support for permission_fault logic
KVM, pkeys: Add pkeys support for gva_to_gpa funcions
KVM, pkeys: add pkeys support for xsave state
KVM, pkeys: disable PKU feature without ept
arch/x86/include/asm/kvm_host.h | 11 +++++---
arch/x86/kvm/cpuid.c | 24 ++++++++++++++++--
arch/x86/kvm/cpuid.h | 8 ++++++
arch/x86/kvm/mmu.c | 32 +++++++++++++++++++++--
arch/x86/kvm/mmu.h | 56 +++++++++++++++++++++++++++++++++++++----
arch/x86/kvm/paging_tmpl.h | 18 ++++++++++---
arch/x86/kvm/vmx.c | 10 ++++----
arch/x86/kvm/x86.c | 27 ++++++++++++++------
arch/x86/kvm/x86.h | 3 ++-
9 files changed, 161 insertions(+), 28 deletions(-)
--
2.4.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/7] KVM, pkeys: expose CPUID/CR4 to guest
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
@ 2015-11-18 5:43 ` Huaitong Han
2015-11-18 5:43 ` [PATCH v3 2/7] KVM, pkeys: disable pkeys for guests in non-paging mode Huaitong Han
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Huaitong Han @ 2015-11-18 5:43 UTC (permalink / raw)
To: pbonzini, gleb; +Cc: kvm, Huaitong Han
This patch exposes CPUID/CR4 to guest.
X86_FEATURE_PKU is referred to as "PKU" in the hardware documentation:
CPUID.7.0.ECX[3]:PKU. X86_FEATURE_OSPKE is software support for pkeys,
enumerated with CPUID.7.0.ECX[4]:OSPKE, and it reflects the setting of
CR4.PKE(bit 22).
Signed-off-by: Huaitong Han <huaitong.han@intel.com>
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index c12e845..3bbc1cb 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -55,7 +55,8 @@
| X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \
| X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \
| X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \
- | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE | X86_CR4_SMAP))
+ | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE | X86_CR4_SMAP \
+ | X86_CR4_PKE))
#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 156441b..ece687b 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -81,6 +81,17 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
apic->lapic_timer.timer_mode_mask = 1 << 17;
}
+ best = kvm_find_cpuid_entry(vcpu, 7, 0);
+ if (!best)
+ return 0;
+
+ /*Update OSPKE bit */
+ if (boot_cpu_has(X86_FEATURE_PKU) && best->function == 0x7) {
+ best->ecx &= ~F(OSPKE);
+ if (kvm_read_cr4_bits(vcpu, X86_CR4_PKE))
+ best->ecx |= F(OSPKE);
+ }
+
best = kvm_find_cpuid_entry(vcpu, 0xD, 0);
if (!best) {
vcpu->arch.guest_supported_xcr0 = 0;
@@ -354,6 +365,9 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
const u32 kvm_supported_word10_x86_features =
F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | f_xsaves;
+ /* cpuid 7.0.ecx*/
+ const u32 kvm_supported_word11_x86_features = F(PKU) | 0 /*OSPKE*/;
+
/* all calls to cpuid_count() should be made on the same cpu */
get_cpu();
@@ -431,10 +445,13 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
cpuid_mask(&entry->ebx, 9);
// TSC_ADJUST is emulated
entry->ebx |= F(TSC_ADJUST);
- } else
+ entry->ecx &= kvm_supported_word11_x86_features;
+ cpuid_mask(&entry->ecx, 13);
+ } else {
entry->ebx = 0;
+ entry->ecx = 0;
+ }
entry->eax = 0;
- entry->ecx = 0;
entry->edx = 0;
break;
}
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index dd05b9c..7775158 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -70,6 +70,14 @@ static inline bool guest_cpuid_has_fsgsbase(struct kvm_vcpu *vcpu)
return best && (best->ebx & bit(X86_FEATURE_FSGSBASE));
}
+static inline bool guest_cpuid_has_pku(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 7, 0);
+ return best && (best->ecx & bit(X86_FEATURE_PKU));
+}
+
static inline bool guest_cpuid_has_longmode(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2d4e54d..5181834 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -709,7 +709,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
unsigned long old_cr4 = kvm_read_cr4(vcpu);
unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE |
- X86_CR4_SMEP | X86_CR4_SMAP;
+ X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE;
if (cr4 & CR4_RESERVED_BITS)
return 1;
@@ -726,6 +726,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_FSGSBASE))
return 1;
+ if (!guest_cpuid_has_pku(vcpu) && (cr4 & X86_CR4_PKE))
+ return 1;
+
if (is_long_mode(vcpu)) {
if (!(cr4 & X86_CR4_PAE))
return 1;
@@ -751,7 +754,7 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
(!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
kvm_mmu_reset_context(vcpu);
- if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)
+ if ((cr4 ^ old_cr4) & (X86_CR4_OSXSAVE | X86_CR4_PKE))
kvm_update_cpuid(vcpu);
return 0;
@@ -6838,7 +6841,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
- if (sregs->cr4 & X86_CR4_OSXSAVE)
+ if (sregs->cr4 & (X86_CR4_OSXSAVE | X86_CR4_PKE))
kvm_update_cpuid(vcpu);
idx = srcu_read_lock(&vcpu->kvm->srcu);
--
2.4.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/7] KVM, pkeys: disable pkeys for guests in non-paging mode
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
2015-11-18 5:43 ` [PATCH v3 1/7] KVM, pkeys: expose CPUID/CR4 to guest Huaitong Han
@ 2015-11-18 5:43 ` Huaitong Han
2015-11-18 5:44 ` [PATCH v3 3/7] KVM, pkeys: update memeory permission bitmask for pkeys Huaitong Han
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Huaitong Han @ 2015-11-18 5:43 UTC (permalink / raw)
To: pbonzini, gleb; +Cc: kvm, Huaitong Han
Pkeys is disabled if CPU is in non-paging mode in hardware. However KVM
always uses paging mode to emulate guest non-paging, mode with TDP. To
emulate this behavior, pkeys needs to be manually disabled when guest
switches to non-paging mode.
Signed-off-by: Huaitong Han <huaitong.han@intel.com>
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index d019868..9b12c80 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3645,14 +3645,14 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
hw_cr4 &= ~X86_CR4_PAE;
hw_cr4 |= X86_CR4_PSE;
/*
- * SMEP/SMAP is disabled if CPU is in non-paging mode
- * in hardware. However KVM always uses paging mode to
- * emulate guest non-paging mode with TDP.
- * To emulate this behavior, SMEP/SMAP needs to be
+ * SMEP/SMAP/PKU is disabled if CPU is in non-paging
+ * mode in hardware. However KVM always uses paging
+ * mode to emulate guest non-paging mode with TDP.
+ * To emulate this behavior, SMEP/SMAP/PKU needs to be
* manually disabled when guest switches to non-paging
* mode.
*/
- hw_cr4 &= ~(X86_CR4_SMEP | X86_CR4_SMAP);
+ hw_cr4 &= ~(X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_PKE);
} else if (!(cr4 & X86_CR4_PAE)) {
hw_cr4 &= ~X86_CR4_PAE;
}
--
2.4.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 3/7] KVM, pkeys: update memeory permission bitmask for pkeys
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
2015-11-18 5:43 ` [PATCH v3 1/7] KVM, pkeys: expose CPUID/CR4 to guest Huaitong Han
2015-11-18 5:43 ` [PATCH v3 2/7] KVM, pkeys: disable pkeys for guests in non-paging mode Huaitong Han
@ 2015-11-18 5:44 ` Huaitong Han
2015-11-18 5:44 ` [PATCH v3 4/7] KVM, pkeys: add pkeys support for permission_fault logic Huaitong Han
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Huaitong Han @ 2015-11-18 5:44 UTC (permalink / raw)
To: pbonzini, gleb; +Cc: kvm, Huaitong Han
Pkeys define a new status bit in the PFEC. PFEC.PK (bit 5), if some
conditions is true, the fault is considered as a PKU violation.
This patch updates memeory permission bitmask for pkeys.
Signed-off-by: Huaitong Han <huaitong.han@intel.com>
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 3bbc1cb..8852b9f 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -159,12 +159,14 @@ enum {
#define PFERR_USER_BIT 2
#define PFERR_RSVD_BIT 3
#define PFERR_FETCH_BIT 4
+#define PFERR_PK_BIT 5
#define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
#define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
#define PFERR_USER_MASK (1U << PFERR_USER_BIT)
#define PFERR_RSVD_MASK (1U << PFERR_RSVD_BIT)
#define PFERR_FETCH_MASK (1U << PFERR_FETCH_BIT)
+#define PFERR_PK_MASK (1U << PFERR_PK_BIT)
/* apic attention bits */
#define KVM_APIC_CHECK_VAPIC 0
@@ -288,10 +290,12 @@ struct kvm_mmu {
/*
* Bitmap; bit set = permission fault
- * Byte index: page fault error code [4:1]
+ * Byte index: page fault error code [5:1]
* Bit index: pte permissions in ACC_* format
+ *
+ * Add PFEC.PK (bit 5) for protection-key violations
*/
- u8 permissions[16];
+ u8 permissions[32];
u64 *pae_root;
u64 *lm_root;
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 69088a1..0568635 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3793,16 +3793,22 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
{
unsigned bit, byte, pfec;
u8 map;
- bool fault, x, w, u, wf, uf, ff, smapf, cr4_smap, cr4_smep, smap = 0;
+ bool fault, x, w, u, smap = 0, pku = 0;
+ bool wf, uf, ff, smapf, rsvdf, pkuf;
+ bool cr4_smap, cr4_smep, cr4_pku;
cr4_smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);
cr4_smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
+ cr4_pku = kvm_read_cr4_bits(vcpu, X86_CR4_PKE);
+
for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) {
pfec = byte << 1;
map = 0;
wf = pfec & PFERR_WRITE_MASK;
uf = pfec & PFERR_USER_MASK;
ff = pfec & PFERR_FETCH_MASK;
+ rsvdf = pfec & PFERR_RSVD_MASK;
+ pkuf = pfec & PFERR_PK_MASK;
/*
* PFERR_RSVD_MASK bit is set in PFEC if the access is not
* subject to SMAP restrictions, and cleared otherwise. The
@@ -3841,12 +3847,34 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
* clearer.
*/
smap = cr4_smap && u && !uf && !ff;
+
+ /*
+ * PKU:additional mechanism by which the paging
+ * controls access to user-mode addresses based
+ * on the value in the PKRU register. A fault is
+ * considered as a PKU violation if all of the
+ * following conditions are true:
+ * 1.CR4_PKE=1.
+ * 2.EFER_LMA=1.
+ * 3.page is present with no reserved bit
+ * violations.
+ * 4.the access is not an instruction fetch.
+ * 5.the access is to a user page.
+ * 6.PKRU.AD=1
+ * or The access is a data write and
+ * PKRU.WD=1 and either CR0.WP=1
+ * or it is a user access.
+ *
+ * The 2nd and 6th conditions are computed
+ * dynamically in permission_fault.
+ */
+ pku = cr4_pku && !rsvdf && !ff && u;
} else
/* Not really needed: no U/S accesses on ept */
u = 1;
fault = (ff && !x) || (uf && !u) || (wf && !w) ||
- (smapf && smap);
+ (smapf && smap) || (pkuf && pku);
map |= fault << bit;
}
mmu->permissions[byte] = map;
--
2.4.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 4/7] KVM, pkeys: add pkeys support for permission_fault logic
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
` (2 preceding siblings ...)
2015-11-18 5:44 ` [PATCH v3 3/7] KVM, pkeys: update memeory permission bitmask for pkeys Huaitong Han
@ 2015-11-18 5:44 ` Huaitong Han
2015-11-18 5:44 ` [PATCH v3 5/7] KVM, pkeys: Add pkeys support for gva_to_gpa funcions Huaitong Han
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Huaitong Han @ 2015-11-18 5:44 UTC (permalink / raw)
To: pbonzini, gleb; +Cc: kvm, Huaitong Han
Protection keys define a new 4-bit protection key field (PKEY) in bits
62:59 of leaf entries of the page tables, the PKEY is an index to PKRU
register(16 domains), every domain has 2 bits(write disable bit, access
disable bit).
Static logic has been produced in update_permission_bitmask, dynamic logic
need read pkey from page table entries, get pkru value, and deduce the
correct result.
Signed-off-by: Huaitong Han <huaitong.han@intel.com>
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index e4202e4..c76e744 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -3,6 +3,7 @@
#include <linux/kvm_host.h>
#include "kvm_cache_regs.h"
+#include "x86.h"
#define PT64_PT_BITS 9
#define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS)
@@ -24,6 +25,7 @@
#define PT_PAGE_SIZE_MASK (1ULL << PT_PAGE_SIZE_SHIFT)
#define PT_PAT_MASK (1ULL << 7)
#define PT_GLOBAL_MASK (1ULL << 8)
+
#define PT64_NX_SHIFT 63
#define PT64_NX_MASK (1ULL << PT64_NX_SHIFT)
@@ -45,6 +47,10 @@
#define PT_PAGE_TABLE_LEVEL 1
#define PT_MAX_HUGEPAGE_LEVEL (PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES - 1)
+#define PKRU_READ 0
+#define PKRU_WRITE 1
+#define PKRU_ATTRS 2
+
static inline u64 rsvd_bits(int s, int e)
{
return ((1ULL << (e - s + 1)) - 1) << s;
@@ -145,10 +151,50 @@ static inline bool is_write_protection(struct kvm_vcpu *vcpu)
* fault with the given access (in ACC_* format)?
*/
static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
- unsigned pte_access, unsigned pfec)
+ unsigned pte_access, unsigned pte_pkeys, unsigned pfec)
{
- int cpl = kvm_x86_ops->get_cpl(vcpu);
- unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
+ unsigned long smap, rflags;
+ u32 pkru, pkru_bits;
+ int cpl, index;
+ bool wf, uf;
+
+ cpl = kvm_x86_ops->get_cpl(vcpu);
+ rflags = kvm_x86_ops->get_rflags(vcpu);
+
+ /*
+ * PKU is computed dynamically in permission_fault.
+ * 2nd and 6th conditions:
+ * 2.EFER_LMA=1
+ * 6.PKRU.AD=1
+ * or The access is a data write and PKRU.WD=1 and
+ * either CR0.WP=1 or it is a user mode access
+ */
+ pkru = is_long_mode(vcpu) ? read_pkru() : 0;
+ if (unlikely(pkru) && (pfec & PFERR_PK_MASK))
+ {
+ /*
+ * PKRU defines 32 bits, there are 16 domains and 2 attribute bits per
+ * domain in pkru, pkey is the index to a defined domain, so the value
+ * of pkey * PKRU_ATTRS is offset of a defined domain.
+ */
+ pkru_bits = (pkru >> (pte_pkeys * PKRU_ATTRS)) & 3;
+
+ wf = pfec & PFERR_WRITE_MASK;
+ uf = pfec & PFERR_USER_MASK;
+
+ /*
+ * Ignore PKRU.WD if not relevant to this access (a read,
+ * or a supervisor mode access if CR0.WP=0).
+ * So 6th conditions is equivalent to "pkru_bits != 0"
+ */
+ if (!wf || (!uf && !is_write_protection(vcpu)))
+ pkru_bits &= ~(1 << PKRU_WRITE);
+
+ /* Flip pfec on PK bit if pkru_bits is zero */
+ pfec ^= pkru_bits ? 0 : PFERR_PK_MASK;
+ }
+ else
+ pfec &= ~PFERR_PK_MASK;
/*
* If CPL < 3, SMAP prevention are disabled if EFLAGS.AC = 1.
@@ -163,8 +209,8 @@ static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
* but it will be one in index if SMAP checks are being overridden.
* It is important to keep this branchless.
*/
- unsigned long smap = (cpl - 3) & (rflags & X86_EFLAGS_AC);
- int index = (pfec >> 1) +
+ smap = (cpl - 3) & (rflags & X86_EFLAGS_AC);
+ index = (pfec >> 1) +
(smap >> (X86_EFLAGS_AC_BIT - PFERR_RSVD_BIT + 1));
WARN_ON(pfec & PFERR_RSVD_MASK);
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 736e6ab..02daa97 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -253,6 +253,15 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
}
return 0;
}
+static inline unsigned FNAME(gpte_pkeys)(struct kvm_vcpu *vcpu, u64 gpte)
+{
+ unsigned pkeys = 0;
+#if PTTYPE == 64
+ pte_t pte = {.pte = gpte};
+ pkeys = pte_pkey(pte);
+#endif
+ return pkeys;
+}
/*
* Fetch a guest pte for a guest virtual address
@@ -265,12 +274,13 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
pt_element_t pte;
pt_element_t __user *uninitialized_var(ptep_user);
gfn_t table_gfn;
- unsigned index, pt_access, pte_access, accessed_dirty;
+ unsigned index, pt_access, pte_access, accessed_dirty, pte_pkeys;
gpa_t pte_gpa;
int offset;
const int write_fault = access & PFERR_WRITE_MASK;
const int user_fault = access & PFERR_USER_MASK;
const int fetch_fault = access & PFERR_FETCH_MASK;
+ const int pk_fault = access & PFERR_PK_MASK;
u16 errcode = 0;
gpa_t real_gpa;
gfn_t gfn;
@@ -356,7 +366,9 @@ retry_walk:
walker->ptes[walker->level - 1] = pte;
} while (!is_last_gpte(mmu, walker->level, pte));
- if (unlikely(permission_fault(vcpu, mmu, pte_access, access))) {
+ pte_pkeys = FNAME(gpte_pkeys)(vcpu, pte);
+ if (unlikely(permission_fault(vcpu, mmu, pte_access, pte_pkeys,
+ access))) {
errcode |= PFERR_PRESENT_MASK;
goto error;
}
@@ -399,7 +411,7 @@ retry_walk:
return 1;
error:
- errcode |= write_fault | user_fault;
+ errcode |= write_fault | user_fault | pk_fault;
if (fetch_fault && (mmu->nx ||
kvm_read_cr4_bits(vcpu, X86_CR4_SMEP)))
errcode |= PFERR_FETCH_MASK;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 5181834..7a84b83 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4107,7 +4107,7 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
if (vcpu_match_mmio_gva(vcpu, gva)
&& !permission_fault(vcpu, vcpu->arch.walk_mmu,
- vcpu->arch.access, access)) {
+ vcpu->arch.access, 0, access)) {
*gpa = vcpu->arch.mmio_gfn << PAGE_SHIFT |
(gva & (PAGE_SIZE - 1));
trace_vcpu_match_mmio(gva, *gpa, write, false);
--
2.4.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 5/7] KVM, pkeys: Add pkeys support for gva_to_gpa funcions
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
` (3 preceding siblings ...)
2015-11-18 5:44 ` [PATCH v3 4/7] KVM, pkeys: add pkeys support for permission_fault logic Huaitong Han
@ 2015-11-18 5:44 ` Huaitong Han
2015-11-18 5:44 ` [PATCH v3 6/7] KVM, pkeys: add pkeys support for xsave state Huaitong Han
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Huaitong Han @ 2015-11-18 5:44 UTC (permalink / raw)
To: pbonzini, gleb; +Cc: kvm, Huaitong Han
This patch adds pkeys support for gva_to_gpa funcions.
Signed-off-by: Huaitong Han <huaitong.han@intel.com>
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7a84b83..bd942f3 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3960,6 +3960,7 @@ gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva,
struct x86_exception *exception)
{
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
+ access |= kvm_read_cr4_bits(vcpu, X86_CR4_PKE) ? PFERR_PK_MASK : 0;
return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, exception);
}
@@ -3976,6 +3977,7 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva,
{
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
access |= PFERR_WRITE_MASK;
+ access |= kvm_read_cr4_bits(vcpu, X86_CR4_PKE) ? PFERR_PK_MASK : 0;
return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, exception);
}
@@ -4026,10 +4028,13 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt,
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
unsigned offset;
int ret;
+ gpa_t gpa;
+
+ access |= kvm_read_cr4_bits(vcpu, X86_CR4_PKE) ? PFERR_PK_MASK : 0;
/* Inline kvm_read_guest_virt_helper for speed. */
- gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, access|PFERR_FETCH_MASK,
- exception);
+ gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr,
+ access | PFERR_FETCH_MASK, exception);
if (unlikely(gpa == UNMAPPED_GVA))
return X86EMUL_PROPAGATE_FAULT;
@@ -4050,6 +4055,7 @@ int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt,
{
struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
+ access |= kvm_read_cr4_bits(vcpu, X86_CR4_PKE) ? PFERR_PK_MASK : 0;
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access,
exception);
@@ -4073,9 +4079,13 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
void *data = val;
int r = X86EMUL_CONTINUE;
+ u32 access = PFERR_WRITE_MASK;
+
+ access |= kvm_read_cr4_bits(vcpu, X86_CR4_PKE) ? PFERR_PK_MASK : 0;
+
while (bytes) {
gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr,
- PFERR_WRITE_MASK,
+ access,
exception);
unsigned offset = addr & (PAGE_SIZE-1);
unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
--
2.4.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 6/7] KVM, pkeys: add pkeys support for xsave state
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
` (4 preceding siblings ...)
2015-11-18 5:44 ` [PATCH v3 5/7] KVM, pkeys: Add pkeys support for gva_to_gpa funcions Huaitong Han
@ 2015-11-18 5:44 ` Huaitong Han
2015-11-18 5:44 ` [PATCH v3 7/7] KVM, pkeys: disable PKU feature without ept Huaitong Han
2015-11-18 11:01 ` [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Paolo Bonzini
7 siblings, 0 replies; 11+ messages in thread
From: Huaitong Han @ 2015-11-18 5:44 UTC (permalink / raw)
To: pbonzini, gleb; +Cc: kvm, Huaitong Han
This patch adds pkeys support for xsave state.
Signed-off-by: Huaitong Han <huaitong.han@intel.com>
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index f2afa5f..0f71d5d 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -182,7 +182,8 @@ bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
#define KVM_SUPPORTED_XCR0 (XFEATURE_MASK_FP | XFEATURE_MASK_SSE \
| XFEATURE_MASK_YMM | XFEATURE_MASK_BNDREGS \
- | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512)
+ | XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \
+ | XFEATURE_MASK_PKRU)
extern u64 host_xcr0;
extern u64 kvm_supported_xcr0(void);
--
2.4.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 7/7] KVM, pkeys: disable PKU feature without ept
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
` (5 preceding siblings ...)
2015-11-18 5:44 ` [PATCH v3 6/7] KVM, pkeys: add pkeys support for xsave state Huaitong Han
@ 2015-11-18 5:44 ` Huaitong Han
2015-11-18 9:06 ` Paolo Bonzini
2015-11-18 11:01 ` [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Paolo Bonzini
7 siblings, 1 reply; 11+ messages in thread
From: Huaitong Han @ 2015-11-18 5:44 UTC (permalink / raw)
To: pbonzini, gleb; +Cc: kvm, Huaitong Han
This patch disables CPUID:PKU without ept, becase pkeys is not supported
with softmmu.
Signed-off-by: Huaitong Han <huaitong.han@intel.com>
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index ece687b..e422f0a 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -447,6 +447,9 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
entry->ebx |= F(TSC_ADJUST);
entry->ecx &= kvm_supported_word11_x86_features;
cpuid_mask(&entry->ecx, 13);
+ if (!tdp_enabled)
+ /* PKU cannot work with softmmu */
+ entry->ecx &= ~F(PKU);
} else {
entry->ebx = 0;
entry->ecx = 0;
--
2.4.3
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 7/7] KVM, pkeys: disable PKU feature without ept
2015-11-18 5:44 ` [PATCH v3 7/7] KVM, pkeys: disable PKU feature without ept Huaitong Han
@ 2015-11-18 9:06 ` Paolo Bonzini
2015-11-18 9:58 ` Han, Huaitong
0 siblings, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2015-11-18 9:06 UTC (permalink / raw)
To: Huaitong Han, gleb; +Cc: kvm
On 18/11/2015 06:44, Huaitong Han wrote:
> This patch disables CPUID:PKU without ept, becase pkeys is not supported
> with softmmu.
Sure, but _what_ makes it impossible to support pkeys with shadow pages?
Is it enough to add the pkey bits to the role (and then to
kvm_get_mmu_page, mmu_set_spte, set_spte) or are there fundamental problems?
The trick to handle !CR0.WP in FNAME(page_fault) (search for
"walker.pte_access &= ~ACC_USER_MASK"; it's documented in
Documentation/virtual/kvm/mmu.txt as well) should work for PKRU.
If you just want me to change it to "is not yet implemented for shadow
paging", I can do that.
Thanks,
Paolo
> Signed-off-by: Huaitong Han <huaitong.han@intel.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 7/7] KVM, pkeys: disable PKU feature without ept
2015-11-18 9:06 ` Paolo Bonzini
@ 2015-11-18 9:58 ` Han, Huaitong
0 siblings, 0 replies; 11+ messages in thread
From: Han, Huaitong @ 2015-11-18 9:58 UTC (permalink / raw)
To: pbonzini@redhat.com; +Cc: gleb@kernel.org, kvm@vger.kernel.org
On Wed, 2015-11-18 at 10:06 +0100, Paolo Bonzini wrote:
>
> On 18/11/2015 06:44, Huaitong Han wrote:
> > This patch disables CPUID:PKU without ept, becase pkeys is not
> > supported
> > with softmmu.
>
> Sure, but _what_ makes it impossible to support pkeys with shadow
> pages?
>
> Is it enough to add the pkey bits to the role (and then to
> kvm_get_mmu_page, mmu_set_spte, set_spte) or are there fundamental
> problems?
>
> The trick to handle !CR0.WP in FNAME(page_fault) (search for
> "walker.pte_access &= ~ACC_USER_MASK"; it's documented in
> Documentation/virtual/kvm/mmu.txt as well) should work for PKRU.
>
> If you just want me to change it to "is not yet implemented for
> shadow
> paging", I can do that.
Yes, the comments should be described as "becase pkeys is not yet
implemented for shadow paging."
Thanks
Huaitong.
>
> Thanks,
>
> Paolo
>
> > Signed-off-by: Huaitong Han <huaitong.han@intel.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 0/7] KVM, pkeys: add memory protection-key support
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
` (6 preceding siblings ...)
2015-11-18 5:44 ` [PATCH v3 7/7] KVM, pkeys: disable PKU feature without ept Huaitong Han
@ 2015-11-18 11:01 ` Paolo Bonzini
7 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2015-11-18 11:01 UTC (permalink / raw)
To: Huaitong Han, gleb; +Cc: kvm
On 18/11/2015 06:43, Huaitong Han wrote:
> Changes in v3:
> *Add comments for patch that disable PKU feature without ept.
>
> Changes in v2:
> *Add pku.c for kvm-unit-tests.
> *Optimize permission_fault codes for patch4.
> *Delete is_long_mode and PK for patch5.
> *Squash cpuid and cr4 patches.
>
> The protection-key feature provides an additional mechanism by which IA-32e
> paging controls access to usermode addresses.
>
> Hardware support for protection keys for user pages is enumerated with CPUID
> feature flag CPUID.7.0.ECX[3]:PKU. Software support is CPUID.7.0.ECX[4]:OSPKE
> with the setting of CR4.PKE(bit 22).
>
> When CR4.PKE = 1, every linear address is associated with the 4-bit protection
> key located in bits 62:59 of the paging-structure entry that mapped the page
> containing the linear address. The PKRU register determines, for each
> protection key, whether user-mode addresses with that protection key may be
> read or written.
>
> The PKRU register (protection key rights for user pages) is a 32-bit register
> with the following format: for each i (0 ≤ i ≤ 15), PKRU[2i] is the
> access-disable bit for protection key i (ADi); PKRU[2i+1] is the write-disable
> bit for protection key i (WDi).
>
> Software can use the RDPKRU and WRPKRU instructions with ECX = 0 to read and
> write PKRU. In addition, the PKRU register is XSAVE-managed state and can thus
> be read and written by instructions in the XSAVE feature set.
>
> PFEC.PK (bit 5) is defined as protection key violations.
>
> The specification of Protection Keys can be found at SDM (4.6.2, volume 3)
> http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf.
>
> The kernel native patchset have not yet been merged to upstream, you can found
> at git://git.kernel.org/pub/scm/linux/kernel/git/daveh/x86-pkeys.git pkeys-v007.
>
> Huaitong Han (7):
> KVM, pkeys: expose CPUID/CR4 to guest
> KVM, pkeys: disable pkeys for guests in non-paging mode
> KVM, pkeys: update memeory permission bitmask for pkeys
> KVM, pkeys: add pkeys support for permission_fault logic
> KVM, pkeys: Add pkeys support for gva_to_gpa funcions
> KVM, pkeys: add pkeys support for xsave state
> KVM, pkeys: disable PKU feature without ept
>
> arch/x86/include/asm/kvm_host.h | 11 +++++---
> arch/x86/kvm/cpuid.c | 24 ++++++++++++++++--
> arch/x86/kvm/cpuid.h | 8 ++++++
> arch/x86/kvm/mmu.c | 32 +++++++++++++++++++++--
> arch/x86/kvm/mmu.h | 56 +++++++++++++++++++++++++++++++++++++----
> arch/x86/kvm/paging_tmpl.h | 18 ++++++++++---
> arch/x86/kvm/vmx.c | 10 ++++----
> arch/x86/kvm/x86.c | 27 ++++++++++++++------
> arch/x86/kvm/x86.h | 3 ++-
> 9 files changed, 161 insertions(+), 28 deletions(-)
>
Looks good, but it will have to wait for kernel PKU support.
Thanks,
Paolo
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2015-11-18 11:02 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-18 5:43 [PATCH v3 0/7] KVM, pkeys: add memory protection-key support Huaitong Han
2015-11-18 5:43 ` [PATCH v3 1/7] KVM, pkeys: expose CPUID/CR4 to guest Huaitong Han
2015-11-18 5:43 ` [PATCH v3 2/7] KVM, pkeys: disable pkeys for guests in non-paging mode Huaitong Han
2015-11-18 5:44 ` [PATCH v3 3/7] KVM, pkeys: update memeory permission bitmask for pkeys Huaitong Han
2015-11-18 5:44 ` [PATCH v3 4/7] KVM, pkeys: add pkeys support for permission_fault logic Huaitong Han
2015-11-18 5:44 ` [PATCH v3 5/7] KVM, pkeys: Add pkeys support for gva_to_gpa funcions Huaitong Han
2015-11-18 5:44 ` [PATCH v3 6/7] KVM, pkeys: add pkeys support for xsave state Huaitong Han
2015-11-18 5:44 ` [PATCH v3 7/7] KVM, pkeys: disable PKU feature without ept Huaitong Han
2015-11-18 9:06 ` Paolo Bonzini
2015-11-18 9:58 ` Han, Huaitong
2015-11-18 11:01 ` [PATCH v3 0/7] KVM, pkeys: add memory protection-key support 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.