aboutsummaryrefslogtreecommitdiff
path: root/target/i386/tcg
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2021-01-27 09:28:49 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2021-02-08 14:43:55 +0100
commite7e7bdababeefff10736c6adf410c66d2f0d46fe (patch)
tree51083d40362f1a247b4aa24a92611d5d7f534a7d /target/i386/tcg
parent51909241d26fe6fe18a08def93ccc8273f61a8b3 (diff)
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. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target/i386/tcg')
-rw-r--r--target/i386/tcg/excp_helper.c32
-rw-r--r--target/i386/tcg/misc_helper.c14
2 files changed, 34 insertions, 12 deletions
diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c
index a0f44431fe..b7d6259e4a 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 0bd6c95749..f02e4fd400 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;