From patchwork Fri Mar 11 16:01:03 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 8567191 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 947D39F1C0 for ; Fri, 11 Mar 2016 16:04:34 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8FCD72024D for ; Fri, 11 Mar 2016 16:04:33 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7F7A62022A for ; Fri, 11 Mar 2016 16:04:32 +0000 (UTC) Received: from localhost ([::1]:56126 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aePYF-0000QM-UZ for patchwork-qemu-devel@patchwork.kernel.org; Fri, 11 Mar 2016 11:04:31 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42257) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aePV0-0002vl-GO for qemu-devel@nongnu.org; Fri, 11 Mar 2016 11:01:14 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aePUx-0001Ns-6O for qemu-devel@nongnu.org; Fri, 11 Mar 2016 11:01:10 -0500 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]:35729) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aePUw-0001NX-Sx for qemu-devel@nongnu.org; Fri, 11 Mar 2016 11:01:07 -0500 Received: by mail-wm0-x241.google.com with SMTP id n205so3242530wmf.2 for ; Fri, 11 Mar 2016 08:01:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id; bh=sGi99pLlrrZdISYVXqt7umGHUvUj7TMuPXadU+HhgUs=; b=G6t1ZhU2i086jValuc1cF0roYwhkssZgWt/9UtWtCovH/0hW1FhXdNStZP5LxaEQ60 rGkY4iA+OItp5qzZds9DAbAi8EN/dQeCTNtS4OGDymMEpLfn+98T0YGGwX7r/EnMS07Y R657ee7DnzzNFOaLPnDHibsh372UOzXippjsBzuxFAL3ObyHHA7zAiFSzJy79PVmZND5 KNlREU99nA2aFCX8Ff/4QHuQy2Tf41QJfhIYV9PpR7EJ8YE494jIchYlQUyGfCPIi6Ds dlRd2qLngMzR6N0tM6OsURc1o8E9LBQlQJ9V8ucb/rOWD+9ffTFTtEIJEiWAAYsdeR8T daag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id; bh=sGi99pLlrrZdISYVXqt7umGHUvUj7TMuPXadU+HhgUs=; b=S+T+eqvbvyg+uFzJ53ELmCfnRKHLKSz6ZwS2R8HYESDXUq78lSSMt3+7Lh7QvuwLQO Ps7LzRClPLZlkA5VTvrWnwMIKk3KxFUP0ntVJqcBBhSOmgI2MKfrdckyPiVFZ2vNpec/ VObsm2TUuXFScaQ2BPCLAKinY1rje5QAGbwjYeRiZhnUHpo00genDWeVuaGG+BprHUEG 6YUM4l0PuklVzx7CHWZV227MxKwgGhPNsyt4OJEDRLmh2grpd29LnQxh22DVHo+qlzck nNmcg4MAn/eY1Q+zneSfqX94CxCYP73qC8mlsR8GF3LUqKflffkwm8hqha/jMQATjl2R Yzfg== X-Gm-Message-State: AD7BkJKO8sgb0s2Cg7kWo1F999NpvINrqSNnGpazhdMQlV6znAuvvjZd89BA3lZ/FUX5Qg== X-Received: by 10.194.134.134 with SMTP id pk6mr10669561wjb.176.1457712066099; Fri, 11 Mar 2016 08:01:06 -0800 (PST) Received: from donizetti.lan (94-39-161-17.adsl-ull.clienti.tiscali.it. [94.39.161.17]) by smtp.gmail.com with ESMTPSA id c71sm2921136wmd.4.2016.03.11.08.01.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 11 Mar 2016 08:01:05 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Fri, 11 Mar 2016 17:01:03 +0100 Message-Id: <1457712063-20807-1-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 2.5.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::241 Cc: rth@redhat.com, ehabkost@redhat.com Subject: [Qemu-devel] [PATCH v2] target-i386: implement PKE for TCG X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Tested with kvm-unit-tests. Signed-off-by: Paolo Bonzini --- target-i386/cpu.c | 13 ++++++++++--- target-i386/cpu.h | 6 +++++- target-i386/fpu_helper.c | 27 +++++++++++++++++++++++++++ target-i386/helper.c | 22 ++++++++++++++++++++++ target-i386/helper.h | 2 ++ target-i386/misc_helper.c | 27 +++++++++++++++++++++++++++ target-i386/translate.c | 18 +++++++++++++++++- 7 files changed, 110 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0f38d1e..dd85975 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -360,7 +360,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) @@ -2421,6 +2421,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; @@ -2728,9 +2731,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; } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 5148c82..732eb6d 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -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 */ diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c index d1a7f4c..fee5573 100644 --- a/target-i386/fpu_helper.c +++ b/target-i386/fpu_helper.c @@ -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) diff --git a/target-i386/helper.c b/target-i386/helper.c index 3f60ec6..5755839 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -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) { diff --git a/target-i386/helper.h b/target-i386/helper.h index e33451a..1320edc 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -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) diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index 5fbab8f..e31ec97 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -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); +} diff --git a/target-i386/translate.c b/target-i386/translate.c index e48eb4c..f80a397 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7292,7 +7292,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);