mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-22 19:15:36 +00:00
target/i86: implement PKS
Protection Keys for Supervisor-mode pages is a simple extension of the PKU feature that QEMU already implements. For supervisor-mode pages, protection key restrictions come from a new MSR. The MSR has no XSAVE state associated to it. PKS is only respected in long mode. However, in principle it is possible to set the MSR even outside long mode, and in fact even the XSAVE state for PKRU could be set outside long mode using XRSTOR. So do not limit the migration subsections for PKRU and PKRS to long mode. Backports e7e7bdababeefff10736c6adf410c66d2f0d46fe
This commit is contained in:
parent
0c1c359b5c
commit
834e2b2643
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue