aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/i386/cpu.c4
-rw-r--r--target/i386/cpu.h5
-rw-r--r--target/i386/helper.c3
-rw-r--r--target/i386/machine.c24
-rw-r--r--target/i386/tcg/excp_helper.c32
-rw-r--r--target/i386/tcg/misc_helper.c14
6 files changed, 64 insertions, 18 deletions
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ff25ad6..0b0d65c 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -667,7 +667,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
@@ -964,7 +964,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/target/i386/cpu.h b/target/i386/cpu.h
index b39ec50..cc5a26f 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -247,6 +247,7 @@ typedef enum X86Seg {
#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)
@@ -357,6 +358,7 @@ typedef enum X86Seg {
#define MSR_IA32_TSX_CTRL 0x122
#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)
@@ -772,6 +774,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)
@@ -1487,6 +1491,7 @@ typedef struct CPUX86State {
uint64_t msr_smi_count;
uint32_t pkru;
+ uint32_t pkrs;
uint32_t tsx_ctrl;
uint64_t spec_ctrl;
diff --git a/target/i386/helper.c b/target/i386/helper.c
index 6bb0c53..618ad1c 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -194,6 +194,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/target/i386/machine.c b/target/i386/machine.c
index 1614e8c..3768a75 100644
--- a/target/i386/machine.c
+++ b/target/i386/machine.c
@@ -980,7 +980,6 @@ static const VMStateDescription vmstate_umwait = {
}
};
-#ifdef TARGET_X86_64
static bool pkru_needed(void *opaque)
{
X86CPU *cpu = opaque;
@@ -999,7 +998,25 @@ static const VMStateDescription vmstate_pkru = {
VMSTATE_END_OF_LIST()
}
};
-#endif
+
+static bool pkrs_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+
+ return env->pkrs != 0;
+}
+
+static const VMStateDescription vmstate_pkrs = {
+ .name = "cpu/pkrs",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pkrs_needed,
+ .fields = (VMStateField[]){
+ VMSTATE_UINT32(env.pkrs, X86CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
static bool tsc_khz_needed(void *opaque)
{
@@ -1480,9 +1497,8 @@ VMStateDescription vmstate_x86_cpu = {
&vmstate_umwait,
&vmstate_tsc_khz,
&vmstate_msr_smi_count,
-#ifdef TARGET_X86_64
&vmstate_pkru,
-#endif
+ &vmstate_pkrs,
&vmstate_spec_ctrl,
&vmstate_mcg_ext_ctl,
&vmstate_msr_intel_pt,
diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c
index a0f4443..b7d6259 100644
--- a/target/i386/tcg/excp_helper.c
+++ b/target/i386/tcg/excp_helper.c
@@ -361,6 +361,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)
@@ -588,21 +589,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) {
+
+ 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 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;
+ 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/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index 0bd6c95..f02e4fd 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -244,6 +244,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());
@@ -296,6 +297,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;
@@ -399,6 +407,9 @@ void helper_wrmsr(CPUX86State *env)
/* XXX: exception? */
break;
}
+ return;
+error:
+ raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
}
void helper_rdmsr(CPUX86State *env)
@@ -430,6 +441,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;