target-i386: implement PKE for TCG
Tested with kvm-unit-tests. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									cf7cc9291b
								
							
						
					
					
						commit
						0f70ed4759
					
				| 
						 | 
				
			
			@ -361,7 +361,7 @@ static const char *cpuid_6_feature_name[] = {
 | 
			
		|||
          CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
 | 
			
		||||
          CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
 | 
			
		||||
          CPUID_7_0_EBX_RDSEED */
 | 
			
		||||
#define TCG_7_0_ECX_FEATURES 0
 | 
			
		||||
#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE)
 | 
			
		||||
#define TCG_APM_FEATURES 0
 | 
			
		||||
#define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT
 | 
			
		||||
#define TCG_XSAVE_FEATURES (CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1)
 | 
			
		||||
| 
						 | 
				
			
			@ -2426,6 +2426,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
 | 
			
		|||
            *eax = 0; /* Maximum ECX value for sub-leaves */
 | 
			
		||||
            *ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */
 | 
			
		||||
            *ecx = env->features[FEAT_7_0_ECX]; /* Feature flags */
 | 
			
		||||
            if ((*ecx & CPUID_7_0_ECX_PKU) && env->cr[4] & CR4_PKE_MASK) {
 | 
			
		||||
                *ecx |= CPUID_7_0_ECX_OSPKE;
 | 
			
		||||
            }
 | 
			
		||||
            *edx = 0; /* Reserved */
 | 
			
		||||
        } else {
 | 
			
		||||
            *eax = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2733,9 +2736,13 @@ static void x86_cpu_reset(CPUState *s)
 | 
			
		|||
    if (env->features[FEAT_1_EDX] & CPUID_SSE) {
 | 
			
		||||
        xcr0 |= XSTATE_SSE_MASK;
 | 
			
		||||
    }
 | 
			
		||||
    if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_MPX) {
 | 
			
		||||
        xcr0 |= XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK;
 | 
			
		||||
    for (i = 2; i < ARRAY_SIZE(x86_ext_save_areas); i++) {
 | 
			
		||||
        const ExtSaveArea *esa = &x86_ext_save_areas[i];
 | 
			
		||||
        if ((env->features[esa->feature] & esa->bits) == esa->bits) {
 | 
			
		||||
            xcr0 |= 1ull << i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
 | 
			
		||||
        cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,6 +232,7 @@
 | 
			
		|||
#define CR4_OSXSAVE_MASK (1U << 18)
 | 
			
		||||
#define CR4_SMEP_MASK   (1U << 20)
 | 
			
		||||
#define CR4_SMAP_MASK   (1U << 21)
 | 
			
		||||
#define CR4_PKE_MASK   (1U << 22)
 | 
			
		||||
 | 
			
		||||
#define DR6_BD          (1 << 13)
 | 
			
		||||
#define DR6_BS          (1 << 14)
 | 
			
		||||
| 
						 | 
				
			
			@ -260,6 +261,7 @@
 | 
			
		|||
#define PG_PSE_BIT      7
 | 
			
		||||
#define PG_GLOBAL_BIT   8
 | 
			
		||||
#define PG_PSE_PAT_BIT  12
 | 
			
		||||
#define PG_PKRU_BIT     59
 | 
			
		||||
#define PG_NX_BIT       63
 | 
			
		||||
 | 
			
		||||
#define PG_PRESENT_MASK  (1 << PG_PRESENT_BIT)
 | 
			
		||||
| 
						 | 
				
			
			@ -275,7 +277,8 @@
 | 
			
		|||
#define PG_ADDRESS_MASK  0x000ffffffffff000LL
 | 
			
		||||
#define PG_HI_RSVD_MASK  (PG_ADDRESS_MASK & ~PHYS_ADDR_MASK)
 | 
			
		||||
#define PG_HI_USER_MASK  0x7ff0000000000000LL
 | 
			
		||||
#define PG_NX_MASK       (1LL << PG_NX_BIT)
 | 
			
		||||
#define PG_PKRU_MASK     (15ULL << PG_PKRU_BIT)
 | 
			
		||||
#define PG_NX_MASK       (1ULL << PG_NX_BIT)
 | 
			
		||||
 | 
			
		||||
#define PG_ERROR_W_BIT     1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -284,6 +287,7 @@
 | 
			
		|||
#define PG_ERROR_U_MASK    0x04
 | 
			
		||||
#define PG_ERROR_RSVD_MASK 0x08
 | 
			
		||||
#define PG_ERROR_I_D_MASK  0x10
 | 
			
		||||
#define PG_ERROR_PK_MASK   0x20
 | 
			
		||||
 | 
			
		||||
#define MCG_CTL_P       (1ULL<<8)   /* MCG_CAP register available */
 | 
			
		||||
#define MCG_SER_P       (1ULL<<24) /* MCA recovery/new status bits */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1184,6 +1184,11 @@ static void do_xsave_bndcsr(CPUX86State *env, target_ulong addr, uintptr_t ra)
 | 
			
		|||
    cpu_stq_data_ra(env, addr + 8, env->bndcs_regs.sts, ra);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void do_xsave_pkru(CPUX86State *env, target_ulong addr, uintptr_t ra)
 | 
			
		||||
{
 | 
			
		||||
    cpu_stq_data_ra(env, addr, env->pkru, ra);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void helper_fxsave(CPUX86State *env, target_ulong ptr)
 | 
			
		||||
{
 | 
			
		||||
    uintptr_t ra = GETPC();
 | 
			
		||||
| 
						 | 
				
			
			@ -1257,6 +1262,10 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
 | 
			
		|||
        target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset;
 | 
			
		||||
        do_xsave_bndcsr(env, ptr + off, ra);
 | 
			
		||||
    }
 | 
			
		||||
    if (opt & XSTATE_PKRU_MASK) {
 | 
			
		||||
        target_ulong off = x86_ext_save_areas[XSTATE_PKRU_BIT].offset;
 | 
			
		||||
        do_xsave_pkru(env, ptr + off, ra);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Update the XSTATE_BV field.  */
 | 
			
		||||
    old_bv = cpu_ldq_data_ra(env, ptr + 512, ra);
 | 
			
		||||
| 
						 | 
				
			
			@ -1339,6 +1348,11 @@ static void do_xrstor_bndcsr(CPUX86State *env, target_ulong addr, uintptr_t ra)
 | 
			
		|||
    env->bndcs_regs.sts = cpu_ldq_data_ra(env, addr + 8, ra);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void do_xrstor_pkru(CPUX86State *env, target_ulong addr, uintptr_t ra)
 | 
			
		||||
{
 | 
			
		||||
    env->pkru = cpu_ldq_data_ra(env, addr, ra);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void helper_fxrstor(CPUX86State *env, target_ulong ptr)
 | 
			
		||||
{
 | 
			
		||||
    uintptr_t ra = GETPC();
 | 
			
		||||
| 
						 | 
				
			
			@ -1438,6 +1452,19 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
 | 
			
		|||
        }
 | 
			
		||||
        cpu_sync_bndcs_hflags(env);
 | 
			
		||||
    }
 | 
			
		||||
    if (rfbm & XSTATE_PKRU_MASK) {
 | 
			
		||||
        uint64_t old_pkru = env->pkru;
 | 
			
		||||
        if (xstate_bv & XSTATE_PKRU_MASK) {
 | 
			
		||||
            target_ulong off = x86_ext_save_areas[XSTATE_PKRU_BIT].offset;
 | 
			
		||||
            do_xrstor_pkru(env, ptr + off, ra);
 | 
			
		||||
        } else {
 | 
			
		||||
            env->pkru = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (env->pkru != old_pkru) {
 | 
			
		||||
            CPUState *cs = CPU(x86_env_get_cpu(env));
 | 
			
		||||
            tlb_flush(cs, 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -198,6 +198,8 @@ DEF_HELPER_FLAGS_3(xsaveopt, TCG_CALL_NO_WG, void, env, tl, i64)
 | 
			
		|||
DEF_HELPER_FLAGS_3(xrstor, TCG_CALL_NO_WG, void, env, tl, i64)
 | 
			
		||||
DEF_HELPER_FLAGS_2(xgetbv, TCG_CALL_NO_WG, i64, env, i32)
 | 
			
		||||
DEF_HELPER_FLAGS_3(xsetbv, TCG_CALL_NO_WG, void, env, i32, i64)
 | 
			
		||||
DEF_HELPER_FLAGS_2(rdpkru, TCG_CALL_NO_WG, i64, env, i32)
 | 
			
		||||
DEF_HELPER_FLAGS_3(wrpkru, TCG_CALL_NO_WG, void, env, i32, i64)
 | 
			
		||||
 | 
			
		||||
DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
 | 
			
		||||
DEF_HELPER_FLAGS_1(ctz, TCG_CALL_NO_RWG_SE, tl, tl)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -609,3 +609,30 @@ void helper_debug(CPUX86State *env)
 | 
			
		|||
    cs->exception_index = EXCP_DEBUG;
 | 
			
		||||
    cpu_loop_exit(cs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t helper_rdpkru(CPUX86State *env, uint32_t ecx)
 | 
			
		||||
{
 | 
			
		||||
    if ((env->cr[4] & CR4_PKE_MASK) == 0) {
 | 
			
		||||
        raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
 | 
			
		||||
    }
 | 
			
		||||
    if (ecx != 0) {
 | 
			
		||||
        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return env->pkru;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val)
 | 
			
		||||
{
 | 
			
		||||
    CPUState *cs = CPU(x86_env_get_cpu(env));
 | 
			
		||||
 | 
			
		||||
    if ((env->cr[4] & CR4_PKE_MASK) == 0) {
 | 
			
		||||
        raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
 | 
			
		||||
    }
 | 
			
		||||
    if (ecx != 0 || (val & 0xFFFFFFFF00000000ull)) {
 | 
			
		||||
        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    env->pkru = val;
 | 
			
		||||
    tlb_flush(cs, 1);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7322,7 +7322,23 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
 | 
			
		|||
            }
 | 
			
		||||
            gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case 0xee: /* rdpkru */
 | 
			
		||||
            if (prefixes & PREFIX_LOCK) {
 | 
			
		||||
                goto illegal_op;
 | 
			
		||||
            }
 | 
			
		||||
            tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_regs[R_ECX]);
 | 
			
		||||
            gen_helper_rdpkru(cpu_tmp1_i64, cpu_env, cpu_tmp2_i32);
 | 
			
		||||
            tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], cpu_tmp1_i64);
 | 
			
		||||
            break;
 | 
			
		||||
        case 0xef: /* wrpkru */
 | 
			
		||||
            if (prefixes & PREFIX_LOCK) {
 | 
			
		||||
                goto illegal_op;
 | 
			
		||||
            }
 | 
			
		||||
            tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
 | 
			
		||||
                                  cpu_regs[R_EDX]);
 | 
			
		||||
            tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_regs[R_ECX]);
 | 
			
		||||
            gen_helper_wrpkru(cpu_env, cpu_tmp2_i32, cpu_tmp1_i64);
 | 
			
		||||
            break;
 | 
			
		||||
        CASE_MODRM_OP(6): /* lmsw */
 | 
			
		||||
            if (s->cpl != 0) {
 | 
			
		||||
                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue