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

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to