diff options
Diffstat (limited to 'target-i386/helper.c')
-rw-r--r-- | target-i386/helper.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/target-i386/helper.c b/target-i386/helper.c index 3f60ec6122..575583942a 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -676,6 +676,10 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) hflags |= HF_SMAP_MASK; } + if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKU)) { + new_cr4 &= ~CR4_PKE_MASK; + } + env->cr[4] = new_cr4; env->hflags = hflags; @@ -920,6 +924,24 @@ do_check_protect_pse36: goto do_fault_protect; } + if ((env->cr[4] & CR4_PKE_MASK) && (env->hflags & HF_LMA_MASK) && + (ptep & PG_USER_MASK) && env->pkru) { + uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; + uint32_t pkru_ad = (env->pkru >> pk * 2) & 1; + uint32_t pkru_wd = (env->pkru >> pk * 2) & 2; + + if (pkru_ad) { + prot &= ~(PAGE_READ | PAGE_WRITE); + } else if (pkru_wd && (is_user || env->cr[0] & CR0_WP_MASK)) { + prot &= ~PAGE_WRITE; + } + if ((prot & (1 << is_write1)) == 0) { + assert(is_write1 != 2); + error_code |= PG_ERROR_PK_MASK; + goto do_fault_protect; + } + } + /* yes, it can! */ is_dirty = is_write && !(pte & PG_DIRTY_MASK); if (!(pte & PG_ACCESSED_MASK) || is_dirty) { |