diff --git a/qemu/target/i386/cpu.c b/qemu/target/i386/cpu.c index 36b52050..6684c7c6 100644 --- a/qemu/target/i386/cpu.c +++ b/qemu/target/i386/cpu.c @@ -755,7 +755,7 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_7_0_EBX_RDSEED */ #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57) + CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) #define TCG_7_0_EDX_FEATURES 0 #define TCG_7_1_EAX_FEATURES 0 #define TCG_APM_FEATURES 0 @@ -862,7 +862,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "la57", NULL, NULL, NULL, NULL, NULL, "rdpid", NULL, NULL, "cldemote", NULL, "movdiri", - "movdir64b", NULL, NULL, NULL, + "movdir64b", NULL, NULL, "pks", }, .cpuid = { .eax = 7, diff --git a/qemu/target/i386/cpu.h b/qemu/target/i386/cpu.h index 1d7f2b86..ea7f64d1 100644 --- a/qemu/target/i386/cpu.h +++ b/qemu/target/i386/cpu.h @@ -228,6 +228,7 @@ #define CR4_SMEP_MASK (1U << 20) #define CR4_SMAP_MASK (1U << 21) #define CR4_PKE_MASK (1U << 22) +#define CR4_PKS_MASK (1U << 24) #define DR6_BD (1 << 13) #define DR6_BS (1 << 14) @@ -328,6 +329,7 @@ #define MSR_IA32_CORE_CAPABILITY 0xcf #define MSR_IA32_ARCH_CAPABILITIES 0x10a #define MSR_IA32_TSCDEADLINE 0x6e0 +#define MSR_IA32_PKRS 0x6e1 #define FEATURE_CONTROL_LOCKED (1<<0) #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2) @@ -718,6 +720,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_ECX_MOVDIRI (1U << 27) /* Move 64 Bytes as Direct Store Instruction */ #define CPUID_7_0_ECX_MOVDIR64B (1U << 28) +/* Protection Keys for Supervisor-mode Pages */ +#define CPUID_7_0_ECX_PKS (1U << 31) /* AVX512 Neural Network Instructions */ #define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) @@ -1399,6 +1403,7 @@ typedef struct CPUX86State { uint64_t msr_smi_count; uint32_t pkru; + uint32_t pkrs; uint64_t spec_ctrl; uint64_t virt_ssbd; diff --git a/qemu/target/i386/excp_helper.c b/qemu/target/i386/excp_helper.c index c85b0f36..14342a94 100644 --- a/qemu/target/i386/excp_helper.c +++ b/qemu/target/i386/excp_helper.c @@ -362,6 +362,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, uint64_t rsvd_mask = PG_HI_RSVD_MASK; uint32_t page_offset; target_ulong vaddr; + uint32_t pkr; is_user = mmu_idx == MMU_USER_IDX; #if defined(DEBUG_MMU) @@ -589,21 +590,28 @@ do_check_protect_pse36: !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) { prot |= PAGE_EXEC; } - 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; - uint32_t pkru_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - if (pkru_ad) { - pkru_prot &= ~(PAGE_READ | PAGE_WRITE); - } else if (pkru_wd && (is_user || env->cr[0] & CR0_WP_MASK)) { - pkru_prot &= ~PAGE_WRITE; + if (!(env->hflags & HF_LMA_MASK)) { + pkr = 0; + } else if (ptep & PG_USER_MASK) { + pkr = env->cr[4] & CR4_PKE_MASK ? env->pkru : 0; + } else { + pkr = env->cr[4] & CR4_PKS_MASK ? env->pkrs : 0; + } + if (pkr) { + uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; + uint32_t pkr_ad = (pkr >> pk * 2) & 1; + uint32_t pkr_wd = (pkr >> pk * 2) & 2; + uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + + if (pkr_ad) { + pkr_prot &= ~(PAGE_READ | PAGE_WRITE); + } else if (pkr_wd && (is_user || env->cr[0] & CR0_WP_MASK)) { + pkr_prot &= ~PAGE_WRITE; } - prot &= pkru_prot; - if ((pkru_prot & (1 << is_write1)) == 0) { + prot &= pkr_prot; + if ((pkr_prot & (1 << is_write1)) == 0) { assert(is_write1 != 2); error_code |= PG_ERROR_PK_MASK; goto do_fault_protect; diff --git a/qemu/target/i386/helper.c b/qemu/target/i386/helper.c index 4ab3d7cb..15d4aa07 100644 --- a/qemu/target/i386/helper.c +++ b/qemu/target/i386/helper.c @@ -519,6 +519,9 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKU)) { new_cr4 &= ~CR4_PKE_MASK; } + if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKS)) { + new_cr4 &= ~CR4_PKS_MASK; + } env->cr[4] = new_cr4; env->hflags = hflags; diff --git a/qemu/target/i386/misc_helper.c b/qemu/target/i386/misc_helper.c index f054cc3e..71db8fb8 100644 --- a/qemu/target/i386/misc_helper.c +++ b/qemu/target/i386/misc_helper.c @@ -229,6 +229,7 @@ void helper_rdmsr(CPUX86State *env) void helper_wrmsr(CPUX86State *env) { uint64_t val; + CPUState *cs = env_cpu(env); cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC()); @@ -281,6 +282,13 @@ void helper_wrmsr(CPUX86State *env) case MSR_PAT: env->pat = val; break; + case MSR_IA32_PKRS: + if (val & 0xFFFFFFFF00000000ull) { + goto error; + } + env->pkrs = val; + tlb_flush(cs); + break; case MSR_VM_HSAVE_PA: env->vm_hsave = val; break; @@ -384,6 +392,10 @@ void helper_wrmsr(CPUX86State *env) /* XXX: exception? */ break; } + return; +error: + raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); + } void helper_rdmsr(CPUX86State *env) @@ -414,6 +426,9 @@ void helper_rdmsr(CPUX86State *env) case MSR_PAT: val = env->pat; break; + case MSR_IA32_PKRS: + val = env->pkrs; + break; case MSR_VM_HSAVE_PA: val = env->vm_hsave; break;