summary refs log tree commit diff stats
path: root/target-i386/fpu_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-i386/fpu_helper.c')
-rw-r--r--target-i386/fpu_helper.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index d1a7f4cbec..fee5573a10 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)