aboutsummaryrefslogtreecommitdiff
path: root/target/i386/tcg/fpu_helper.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2024-05-26 17:51:00 -0700
committerRichard Henderson <richard.henderson@linaro.org>2024-05-26 17:51:00 -0700
commit60b54b67c63d8f076152e0f7dccf39854dfc6a77 (patch)
treed2ed3e41fe3b8cc1ef13bd60abd86065cff7e162 /target/i386/tcg/fpu_helper.c
parent78ef97c0aa6c03d78950116921cdf893632d22b1 (diff)
parent701890bdd09b289fd9cb852e714e91373088b0f3 (diff)
Merge tag 'pull-lu-20240526' of https://gitlab.com/rth7680/qemu into staging
target/i386: Introduce X86Access and use for xsave and friends linux-user/i386: Fix allocation and alignment of fp state in signal frame # -----BEGIN PGP SIGNATURE----- # # iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmZT2GwdHHJpY2hhcmQu # aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV87pQf9F/cmrKQG1mVWKmJd # MI7l63lbxejdgAADv1nmro+oapCsJSaQeUSrYp904ydqJjVfBJkaoXfknGsvxrNA # oW7nEuYt0sBKdaBUKhYpMOJ3ivfw7lVVMJmjNv9ngZRhW+WOoJrBHoleUkVLiM7D # rxkMLL+LQ7BR9i0Lv1unorOkqUPGNOnEd45qRn6k1g/Qnqi8SNMzxFwO8+232u8m # EG9un/oh4mKPyb5vSg3Y4JLg+yDKCRScBqBU1wcKFe1u+umBkv2BNcU+k62AJh1q # bv8i1n+X/dFAd1aj0NEupi04EOZIof5m3T4YIWg7M4I94NiFWNZ18vgskkmiO+Mo # 0KPd/A== # =sYrE # -----END PGP SIGNATURE----- # gpg: Signature made Sun 26 May 2024 05:48:44 PM PDT # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate] * tag 'pull-lu-20240526' of https://gitlab.com/rth7680/qemu: (28 commits) target/i386: Pass host pointer and size to cpu_x86_{xsave,xrstor} target/i386: Pass host pointer and size to cpu_x86_{fxsave,fxrstor} target/i386: Pass host pointer and size to cpu_x86_{fsave,frstor} target/i386: Convert do_xrstor to X86Access target/i386: Convert do_xsave to X86Access linux-user/i386: Honor xfeatures in xrstor_sigcontext linux-user/i386: Fix allocation and alignment of fp state linux-user/i386: Return boolean success from xrstor_sigcontext linux-user/i386: Return boolean success from restore_sigcontext linux-user/i386: Fix -mregparm=3 for signal delivery linux-user/i386: Split out struct target_fregs_state linux-user/i386: Replace target_fpstate_fxsave with X86LegacyXSaveArea linux-user/i386: Remove xfeatures from target_fpstate_fxsave linux-user/i386: Drop xfeatures_size from sigcontext arithmetic target/i386: Add {hw,sw}_reserved to X86LegacyXSaveArea target/i386: Add rbfm argument to cpu_x86_{xsave,xrstor} target/i386: Split out do_xsave_chk target/i386: Convert do_xrstor_* to X86Access target/i386: Convert do_xsave_* to X86Access tagret/i386: Convert do_fxsave, do_fxrstor to X86Access ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target/i386/tcg/fpu_helper.c')
-rw-r--r--target/i386/tcg/fpu_helper.c553
1 files changed, 341 insertions, 212 deletions
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index 8df8cae631..e322293371 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -27,6 +27,7 @@
#include "fpu/softfloat.h"
#include "fpu/softfloat-macros.h"
#include "helper-tcg.h"
+#include "access.h"
/* float macros */
#define FT0 (env->ft0)
@@ -84,23 +85,22 @@ static inline void fpop(CPUX86State *env)
env->fpstt = (env->fpstt + 1) & 7;
}
-static floatx80 do_fldt(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
+static floatx80 do_fldt(X86Access *ac, target_ulong ptr)
{
CPU_LDoubleU temp;
- temp.l.lower = cpu_ldq_data_ra(env, ptr, retaddr);
- temp.l.upper = cpu_lduw_data_ra(env, ptr + 8, retaddr);
+ temp.l.lower = access_ldq(ac, ptr);
+ temp.l.upper = access_ldw(ac, ptr + 8);
return temp.d;
}
-static void do_fstt(CPUX86State *env, floatx80 f, target_ulong ptr,
- uintptr_t retaddr)
+static void do_fstt(X86Access *ac, target_ulong ptr, floatx80 f)
{
CPU_LDoubleU temp;
temp.d = f;
- cpu_stq_data_ra(env, ptr, temp.l.lower, retaddr);
- cpu_stw_data_ra(env, ptr + 8, temp.l.upper, retaddr);
+ access_stq(ac, ptr, temp.l.lower);
+ access_stw(ac, ptr + 8, temp.l.upper);
}
/* x87 FPU helpers */
@@ -382,16 +382,22 @@ int64_t helper_fisttll_ST0(CPUX86State *env)
void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)
{
int new_fpstt;
+ X86Access ac;
+
+ access_prepare(&ac, env, ptr, 10, MMU_DATA_LOAD, GETPC());
new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = do_fldt(env, ptr, GETPC());
+ env->fpregs[new_fpstt].d = do_fldt(&ac, ptr);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void helper_fstt_ST0(CPUX86State *env, target_ulong ptr)
{
- do_fstt(env, ST0, ptr, GETPC());
+ X86Access ac;
+
+ access_prepare(&ac, env, ptr, 10, MMU_DATA_STORE, GETPC());
+ do_fstt(&ac, ptr, ST0);
}
void helper_fpush(CPUX86State *env)
@@ -769,18 +775,21 @@ void helper_fninit(CPUX86State *env)
void helper_fbld_ST0(CPUX86State *env, target_ulong ptr)
{
+ X86Access ac;
floatx80 tmp;
uint64_t val;
unsigned int v;
int i;
+ access_prepare(&ac, env, ptr, 10, MMU_DATA_LOAD, GETPC());
+
val = 0;
for (i = 8; i >= 0; i--) {
- v = cpu_ldub_data_ra(env, ptr + i, GETPC());
+ v = access_ldb(&ac, ptr + i);
val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
}
tmp = int64_to_floatx80(val, &env->fp_status);
- if (cpu_ldub_data_ra(env, ptr + 9, GETPC()) & 0x80) {
+ if (access_ldb(&ac, ptr + 9) & 0x80) {
tmp = floatx80_chs(tmp);
}
fpush(env);
@@ -794,7 +803,9 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr)
target_ulong mem_ref, mem_end;
int64_t val;
CPU_LDoubleU temp;
+ X86Access ac;
+ access_prepare(&ac, env, ptr, 10, MMU_DATA_STORE, GETPC());
temp.d = ST0;
val = floatx80_to_int64(ST0, &env->fp_status);
@@ -802,20 +813,20 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr)
if (val >= 1000000000000000000LL || val <= -1000000000000000000LL) {
set_float_exception_flags(float_flag_invalid, &env->fp_status);
while (mem_ref < ptr + 7) {
- cpu_stb_data_ra(env, mem_ref++, 0, GETPC());
+ access_stb(&ac, mem_ref++, 0);
}
- cpu_stb_data_ra(env, mem_ref++, 0xc0, GETPC());
- cpu_stb_data_ra(env, mem_ref++, 0xff, GETPC());
- cpu_stb_data_ra(env, mem_ref++, 0xff, GETPC());
+ access_stb(&ac, mem_ref++, 0xc0);
+ access_stb(&ac, mem_ref++, 0xff);
+ access_stb(&ac, mem_ref++, 0xff);
merge_exception_flags(env, old_flags);
return;
}
mem_end = mem_ref + 9;
if (SIGND(temp)) {
- cpu_stb_data_ra(env, mem_end, 0x80, GETPC());
+ access_stb(&ac, mem_end, 0x80);
val = -val;
} else {
- cpu_stb_data_ra(env, mem_end, 0x00, GETPC());
+ access_stb(&ac, mem_end, 0x00);
}
while (mem_ref < mem_end) {
if (val == 0) {
@@ -824,10 +835,10 @@ void helper_fbst_ST0(CPUX86State *env, target_ulong ptr)
v = val % 100;
val = val / 100;
v = ((v / 10) << 4) | (v % 10);
- cpu_stb_data_ra(env, mem_ref++, v, GETPC());
+ access_stb(&ac, mem_ref++, v);
}
while (mem_ref < mem_end) {
- cpu_stb_data_ra(env, mem_ref++, 0, GETPC());
+ access_stb(&ac, mem_ref++, 0);
}
merge_exception_flags(env, old_flags);
}
@@ -2364,9 +2375,9 @@ void helper_fxam_ST0(CPUX86State *env)
}
}
-static void do_fstenv(CPUX86State *env, target_ulong ptr, int data32,
- uintptr_t retaddr)
+static void do_fstenv(X86Access *ac, target_ulong ptr, int data32)
{
+ CPUX86State *env = ac->env;
int fpus, fptag, exp, i;
uint64_t mant;
CPU_LDoubleU tmp;
@@ -2393,28 +2404,31 @@ static void do_fstenv(CPUX86State *env, target_ulong ptr, int data32,
}
if (data32) {
/* 32 bit */
- cpu_stl_data_ra(env, ptr, env->fpuc, retaddr);
- cpu_stl_data_ra(env, ptr + 4, fpus, retaddr);
- cpu_stl_data_ra(env, ptr + 8, fptag, retaddr);
- cpu_stl_data_ra(env, ptr + 12, env->fpip, retaddr); /* fpip */
- cpu_stl_data_ra(env, ptr + 16, env->fpcs, retaddr); /* fpcs */
- cpu_stl_data_ra(env, ptr + 20, env->fpdp, retaddr); /* fpoo */
- cpu_stl_data_ra(env, ptr + 24, env->fpds, retaddr); /* fpos */
+ access_stl(ac, ptr, env->fpuc);
+ access_stl(ac, ptr + 4, fpus);
+ access_stl(ac, ptr + 8, fptag);
+ access_stl(ac, ptr + 12, env->fpip); /* fpip */
+ access_stl(ac, ptr + 16, env->fpcs); /* fpcs */
+ access_stl(ac, ptr + 20, env->fpdp); /* fpoo */
+ access_stl(ac, ptr + 24, env->fpds); /* fpos */
} else {
/* 16 bit */
- cpu_stw_data_ra(env, ptr, env->fpuc, retaddr);
- cpu_stw_data_ra(env, ptr + 2, fpus, retaddr);
- cpu_stw_data_ra(env, ptr + 4, fptag, retaddr);
- cpu_stw_data_ra(env, ptr + 6, env->fpip, retaddr);
- cpu_stw_data_ra(env, ptr + 8, env->fpcs, retaddr);
- cpu_stw_data_ra(env, ptr + 10, env->fpdp, retaddr);
- cpu_stw_data_ra(env, ptr + 12, env->fpds, retaddr);
+ access_stw(ac, ptr, env->fpuc);
+ access_stw(ac, ptr + 2, fpus);
+ access_stw(ac, ptr + 4, fptag);
+ access_stw(ac, ptr + 6, env->fpip);
+ access_stw(ac, ptr + 8, env->fpcs);
+ access_stw(ac, ptr + 10, env->fpdp);
+ access_stw(ac, ptr + 12, env->fpds);
}
}
void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
{
- do_fstenv(env, ptr, data32, GETPC());
+ X86Access ac;
+
+ access_prepare(&ac, env, ptr, 14 << data32, MMU_DATA_STORE, GETPC());
+ do_fstenv(&ac, ptr, data32);
}
static void cpu_set_fpus(CPUX86State *env, uint16_t fpus)
@@ -2433,20 +2447,15 @@ static void cpu_set_fpus(CPUX86State *env, uint16_t fpus)
#endif
}
-static void do_fldenv(CPUX86State *env, target_ulong ptr, int data32,
- uintptr_t retaddr)
+static void do_fldenv(X86Access *ac, target_ulong ptr, int data32)
{
int i, fpus, fptag;
+ CPUX86State *env = ac->env;
+
+ cpu_set_fpuc(env, access_ldw(ac, ptr));
+ fpus = access_ldw(ac, ptr + (2 << data32));
+ fptag = access_ldw(ac, ptr + (4 << data32));
- if (data32) {
- cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
- fpus = cpu_lduw_data_ra(env, ptr + 4, retaddr);
- fptag = cpu_lduw_data_ra(env, ptr + 8, retaddr);
- } else {
- cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
- fpus = cpu_lduw_data_ra(env, ptr + 2, retaddr);
- fptag = cpu_lduw_data_ra(env, ptr + 4, retaddr);
- }
cpu_set_fpus(env, fpus);
for (i = 0; i < 8; i++) {
env->fptags[i] = ((fptag & 3) == 3);
@@ -2456,21 +2465,22 @@ static void do_fldenv(CPUX86State *env, target_ulong ptr, int data32,
void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32)
{
- do_fldenv(env, ptr, data32, GETPC());
+ X86Access ac;
+
+ access_prepare(&ac, env, ptr, 14 << data32, MMU_DATA_STORE, GETPC());
+ do_fldenv(&ac, ptr, data32);
}
-static void do_fsave(CPUX86State *env, target_ulong ptr, int data32,
- uintptr_t retaddr)
+static void do_fsave(X86Access *ac, target_ulong ptr, int data32)
{
- floatx80 tmp;
- int i;
+ CPUX86State *env = ac->env;
- do_fstenv(env, ptr, data32, retaddr);
+ do_fstenv(ac, ptr, data32);
+ ptr += 14 << data32;
- ptr += (target_ulong)14 << data32;
- for (i = 0; i < 8; i++) {
- tmp = ST(i);
- do_fstt(env, tmp, ptr, retaddr);
+ for (int i = 0; i < 8; i++) {
+ floatx80 tmp = ST(i);
+ do_fstt(ac, ptr, tmp);
ptr += 10;
}
@@ -2479,20 +2489,22 @@ static void do_fsave(CPUX86State *env, target_ulong ptr, int data32,
void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
{
- do_fsave(env, ptr, data32, GETPC());
+ int size = (14 << data32) + 80;
+ X86Access ac;
+
+ access_prepare(&ac, env, ptr, size, MMU_DATA_STORE, GETPC());
+ do_fsave(&ac, ptr, data32);
}
-static void do_frstor(CPUX86State *env, target_ulong ptr, int data32,
- uintptr_t retaddr)
+static void do_frstor(X86Access *ac, target_ulong ptr, int data32)
{
- floatx80 tmp;
- int i;
+ CPUX86State *env = ac->env;
- do_fldenv(env, ptr, data32, retaddr);
- ptr += (target_ulong)14 << data32;
+ do_fldenv(ac, ptr, data32);
+ ptr += 14 << data32;
- for (i = 0; i < 8; i++) {
- tmp = do_fldt(env, ptr, retaddr);
+ for (int i = 0; i < 8; i++) {
+ floatx80 tmp = do_fldt(ac, ptr);
ST(i) = tmp;
ptr += 10;
}
@@ -2500,13 +2512,18 @@ static void do_frstor(CPUX86State *env, target_ulong ptr, int data32,
void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
{
- do_frstor(env, ptr, data32, GETPC());
+ int size = (14 << data32) + 80;
+ X86Access ac;
+
+ access_prepare(&ac, env, ptr, size, MMU_DATA_LOAD, GETPC());
+ do_frstor(&ac, ptr, data32);
}
#define XO(X) offsetof(X86XSaveArea, X)
-static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xsave_fpu(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
int fpus, fptag, i;
target_ulong addr;
@@ -2516,33 +2533,37 @@ static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
fptag |= (env->fptags[i] << i);
}
- cpu_stw_data_ra(env, ptr + XO(legacy.fcw), env->fpuc, ra);
- cpu_stw_data_ra(env, ptr + XO(legacy.fsw), fpus, ra);
- cpu_stw_data_ra(env, ptr + XO(legacy.ftw), fptag ^ 0xff, ra);
+ access_stw(ac, ptr + XO(legacy.fcw), env->fpuc);
+ access_stw(ac, ptr + XO(legacy.fsw), fpus);
+ access_stw(ac, ptr + XO(legacy.ftw), fptag ^ 0xff);
/* In 32-bit mode this is eip, sel, dp, sel.
In 64-bit mode this is rip, rdp.
But in either case we don't write actual data, just zeros. */
- cpu_stq_data_ra(env, ptr + XO(legacy.fpip), 0, ra); /* eip+sel; rip */
- cpu_stq_data_ra(env, ptr + XO(legacy.fpdp), 0, ra); /* edp+sel; rdp */
+ access_stq(ac, ptr + XO(legacy.fpip), 0); /* eip+sel; rip */
+ access_stq(ac, ptr + XO(legacy.fpdp), 0); /* edp+sel; rdp */
addr = ptr + XO(legacy.fpregs);
+
for (i = 0; i < 8; i++) {
floatx80 tmp = ST(i);
- do_fstt(env, tmp, addr, ra);
+ do_fstt(ac, addr, tmp);
addr += 16;
}
}
-static void do_xsave_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xsave_mxcsr(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
+
update_mxcsr_from_sse_status(env);
- cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr), env->mxcsr, ra);
- cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr_mask), 0x0000ffff, ra);
+ access_stl(ac, ptr + XO(legacy.mxcsr), env->mxcsr);
+ access_stl(ac, ptr + XO(legacy.mxcsr_mask), 0x0000ffff);
}
-static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xsave_sse(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
int i, nb_xmm_regs;
target_ulong addr;
@@ -2554,14 +2575,15 @@ static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
addr = ptr + XO(legacy.xmm_regs);
for (i = 0; i < nb_xmm_regs; i++) {
- cpu_stq_data_ra(env, addr, env->xmm_regs[i].ZMM_Q(0), ra);
- cpu_stq_data_ra(env, addr + 8, env->xmm_regs[i].ZMM_Q(1), ra);
+ access_stq(ac, addr, env->xmm_regs[i].ZMM_Q(0));
+ access_stq(ac, addr + 8, env->xmm_regs[i].ZMM_Q(1));
addr += 16;
}
}
-static void do_xsave_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xsave_ymmh(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
int i, nb_xmm_regs;
if (env->hflags & HF_CS64_MASK) {
@@ -2571,58 +2593,67 @@ static void do_xsave_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra)
}
for (i = 0; i < nb_xmm_regs; i++, ptr += 16) {
- cpu_stq_data_ra(env, ptr, env->xmm_regs[i].ZMM_Q(2), ra);
- cpu_stq_data_ra(env, ptr + 8, env->xmm_regs[i].ZMM_Q(3), ra);
+ access_stq(ac, ptr, env->xmm_regs[i].ZMM_Q(2));
+ access_stq(ac, ptr + 8, env->xmm_regs[i].ZMM_Q(3));
}
}
-static void do_xsave_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xsave_bndregs(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs);
int i;
for (i = 0; i < 4; i++, addr += 16) {
- cpu_stq_data_ra(env, addr, env->bnd_regs[i].lb, ra);
- cpu_stq_data_ra(env, addr + 8, env->bnd_regs[i].ub, ra);
+ access_stq(ac, addr, env->bnd_regs[i].lb);
+ access_stq(ac, addr + 8, env->bnd_regs[i].ub);
}
}
-static void do_xsave_bndcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xsave_bndcsr(X86Access *ac, target_ulong ptr)
{
- cpu_stq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.cfgu),
- env->bndcs_regs.cfgu, ra);
- cpu_stq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.sts),
- env->bndcs_regs.sts, ra);
+ CPUX86State *env = ac->env;
+
+ access_stq(ac, ptr + offsetof(XSaveBNDCSR, bndcsr.cfgu),
+ env->bndcs_regs.cfgu);
+ access_stq(ac, ptr + offsetof(XSaveBNDCSR, bndcsr.sts),
+ env->bndcs_regs.sts);
}
-static void do_xsave_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xsave_pkru(X86Access *ac, target_ulong ptr)
{
- cpu_stq_data_ra(env, ptr, env->pkru, ra);
+ access_stq(ac, ptr, ac->env->pkru);
}
-static void do_fxsave(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_fxsave(X86Access *ac, target_ulong ptr)
{
- /* The operand must be 16 byte aligned */
- if (ptr & 0xf) {
- raise_exception_ra(env, EXCP0D_GPF, ra);
- }
-
- do_xsave_fpu(env, ptr, ra);
+ CPUX86State *env = ac->env;
+ do_xsave_fpu(ac, ptr);
if (env->cr[4] & CR4_OSFXSR_MASK) {
- do_xsave_mxcsr(env, ptr, ra);
+ do_xsave_mxcsr(ac, ptr);
/* Fast FXSAVE leaves out the XMM registers */
if (!(env->efer & MSR_EFER_FFXSR)
|| (env->hflags & HF_CPL_MASK)
|| !(env->hflags & HF_LMA_MASK)) {
- do_xsave_sse(env, ptr, ra);
+ do_xsave_sse(ac, ptr);
}
}
}
void helper_fxsave(CPUX86State *env, target_ulong ptr)
{
- do_fxsave(env, ptr, GETPC());
+ uintptr_t ra = GETPC();
+ X86Access ac;
+
+ /* The operand must be 16 byte aligned */
+ if (ptr & 0xf) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ access_prepare(&ac, env, ptr, sizeof(X86LegacyXSaveArea),
+ MMU_DATA_STORE, ra);
+ do_fxsave(&ac, ptr);
}
static uint64_t get_xinuse(CPUX86State *env)
@@ -2639,57 +2670,73 @@ static uint64_t get_xinuse(CPUX86State *env)
return inuse;
}
-static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
- uint64_t inuse, uint64_t opt, uintptr_t ra)
+static void do_xsave_access(X86Access *ac, target_ulong ptr, uint64_t rfbm,
+ uint64_t inuse, uint64_t opt)
{
uint64_t old_bv, new_bv;
- /* The OS must have enabled XSAVE. */
- if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
- raise_exception_ra(env, EXCP06_ILLOP, ra);
- }
-
- /* The operand must be 64 byte aligned. */
- if (ptr & 63) {
- raise_exception_ra(env, EXCP0D_GPF, ra);
- }
-
- /* Never save anything not enabled by XCR0. */
- rfbm &= env->xcr0;
- opt &= rfbm;
-
if (opt & XSTATE_FP_MASK) {
- do_xsave_fpu(env, ptr, ra);
+ do_xsave_fpu(ac, ptr);
}
if (rfbm & XSTATE_SSE_MASK) {
/* Note that saving MXCSR is not suppressed by XSAVEOPT. */
- do_xsave_mxcsr(env, ptr, ra);
+ do_xsave_mxcsr(ac, ptr);
}
if (opt & XSTATE_SSE_MASK) {
- do_xsave_sse(env, ptr, ra);
+ do_xsave_sse(ac, ptr);
}
if (opt & XSTATE_YMM_MASK) {
- do_xsave_ymmh(env, ptr + XO(avx_state), ra);
+ do_xsave_ymmh(ac, ptr + XO(avx_state));
}
if (opt & XSTATE_BNDREGS_MASK) {
- do_xsave_bndregs(env, ptr + XO(bndreg_state), ra);
+ do_xsave_bndregs(ac, ptr + XO(bndreg_state));
}
if (opt & XSTATE_BNDCSR_MASK) {
- do_xsave_bndcsr(env, ptr + XO(bndcsr_state), ra);
+ do_xsave_bndcsr(ac, ptr + XO(bndcsr_state));
}
if (opt & XSTATE_PKRU_MASK) {
- do_xsave_pkru(env, ptr + XO(pkru_state), ra);
+ do_xsave_pkru(ac, ptr + XO(pkru_state));
}
/* Update the XSTATE_BV field. */
- old_bv = cpu_ldq_data_ra(env, ptr + XO(header.xstate_bv), ra);
+ old_bv = access_ldq(ac, ptr + XO(header.xstate_bv));
new_bv = (old_bv & ~rfbm) | (inuse & rfbm);
- cpu_stq_data_ra(env, ptr + XO(header.xstate_bv), new_bv, ra);
+ access_stq(ac, ptr + XO(header.xstate_bv), new_bv);
+}
+
+static void do_xsave_chk(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+{
+ /* The OS must have enabled XSAVE. */
+ if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
+ raise_exception_ra(env, EXCP06_ILLOP, ra);
+ }
+
+ /* The operand must be 64 byte aligned. */
+ if (ptr & 63) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+}
+
+static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
+ uint64_t inuse, uint64_t opt, uintptr_t ra)
+{
+ X86Access ac;
+ unsigned size;
+
+ do_xsave_chk(env, ptr, ra);
+
+ /* Never save anything not enabled by XCR0. */
+ rfbm &= env->xcr0;
+ opt &= rfbm;
+ size = xsave_area_size(opt, false);
+
+ access_prepare(&ac, env, ptr, size, MMU_DATA_STORE, ra);
+ do_xsave_access(&ac, ptr, rfbm, inuse, opt);
}
void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
{
- do_xsave(env, ptr, rfbm, get_xinuse(env), -1, GETPC());
+ do_xsave(env, ptr, rfbm, get_xinuse(env), rfbm, GETPC());
}
void helper_xsaveopt(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
@@ -2698,36 +2745,41 @@ void helper_xsaveopt(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
do_xsave(env, ptr, rfbm, inuse, inuse, GETPC());
}
-static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xrstor_fpu(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
int i, fpuc, fpus, fptag;
target_ulong addr;
- fpuc = cpu_lduw_data_ra(env, ptr + XO(legacy.fcw), ra);
- fpus = cpu_lduw_data_ra(env, ptr + XO(legacy.fsw), ra);
- fptag = cpu_lduw_data_ra(env, ptr + XO(legacy.ftw), ra);
+ fpuc = access_ldw(ac, ptr + XO(legacy.fcw));
+ fpus = access_ldw(ac, ptr + XO(legacy.fsw));
+ fptag = access_ldw(ac, ptr + XO(legacy.ftw));
cpu_set_fpuc(env, fpuc);
cpu_set_fpus(env, fpus);
+
fptag ^= 0xff;
for (i = 0; i < 8; i++) {
env->fptags[i] = ((fptag >> i) & 1);
}
addr = ptr + XO(legacy.fpregs);
+
for (i = 0; i < 8; i++) {
- floatx80 tmp = do_fldt(env, addr, ra);
+ floatx80 tmp = do_fldt(ac, addr);
ST(i) = tmp;
addr += 16;
}
}
-static void do_xrstor_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xrstor_mxcsr(X86Access *ac, target_ulong ptr)
{
- cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + XO(legacy.mxcsr), ra));
+ CPUX86State *env = ac->env;
+ cpu_set_mxcsr(env, access_ldl(ac, ptr + XO(legacy.mxcsr)));
}
-static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xrstor_sse(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
int i, nb_xmm_regs;
target_ulong addr;
@@ -2739,8 +2791,8 @@ static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
addr = ptr + XO(legacy.xmm_regs);
for (i = 0; i < nb_xmm_regs; i++) {
- env->xmm_regs[i].ZMM_Q(0) = cpu_ldq_data_ra(env, addr, ra);
- env->xmm_regs[i].ZMM_Q(1) = cpu_ldq_data_ra(env, addr + 8, ra);
+ env->xmm_regs[i].ZMM_Q(0) = access_ldq(ac, addr);
+ env->xmm_regs[i].ZMM_Q(1) = access_ldq(ac, addr + 8);
addr += 16;
}
}
@@ -2761,8 +2813,9 @@ static void do_clear_sse(CPUX86State *env)
}
}
-static void do_xrstor_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xrstor_ymmh(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
int i, nb_xmm_regs;
if (env->hflags & HF_CS64_MASK) {
@@ -2772,8 +2825,8 @@ static void do_xrstor_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra)
}
for (i = 0; i < nb_xmm_regs; i++, ptr += 16) {
- env->xmm_regs[i].ZMM_Q(2) = cpu_ldq_data_ra(env, ptr, ra);
- env->xmm_regs[i].ZMM_Q(3) = cpu_ldq_data_ra(env, ptr + 8, ra);
+ env->xmm_regs[i].ZMM_Q(2) = access_ldq(ac, ptr);
+ env->xmm_regs[i].ZMM_Q(3) = access_ldq(ac, ptr + 8);
}
}
@@ -2793,100 +2846,97 @@ static void do_clear_ymmh(CPUX86State *env)
}
}
-static void do_xrstor_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xrstor_bndregs(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs);
int i;
for (i = 0; i < 4; i++, addr += 16) {
- env->bnd_regs[i].lb = cpu_ldq_data_ra(env, addr, ra);
- env->bnd_regs[i].ub = cpu_ldq_data_ra(env, addr + 8, ra);
+ env->bnd_regs[i].lb = access_ldq(ac, addr);
+ env->bnd_regs[i].ub = access_ldq(ac, addr + 8);
}
}
-static void do_xrstor_bndcsr(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xrstor_bndcsr(X86Access *ac, target_ulong ptr)
{
+ CPUX86State *env = ac->env;
+
/* FIXME: Extend highest implemented bit of linear address. */
env->bndcs_regs.cfgu
- = cpu_ldq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.cfgu), ra);
+ = access_ldq(ac, ptr + offsetof(XSaveBNDCSR, bndcsr.cfgu));
env->bndcs_regs.sts
- = cpu_ldq_data_ra(env, ptr + offsetof(XSaveBNDCSR, bndcsr.sts), ra);
+ = access_ldq(ac, ptr + offsetof(XSaveBNDCSR, bndcsr.sts));
}
-static void do_xrstor_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_xrstor_pkru(X86Access *ac, target_ulong ptr)
{
- env->pkru = cpu_ldq_data_ra(env, ptr, ra);
+ ac->env->pkru = access_ldq(ac, ptr);
}
-static void do_fxrstor(CPUX86State *env, target_ulong ptr, uintptr_t ra)
+static void do_fxrstor(X86Access *ac, target_ulong ptr)
{
- /* The operand must be 16 byte aligned */
- if (ptr & 0xf) {
- raise_exception_ra(env, EXCP0D_GPF, ra);
- }
-
- do_xrstor_fpu(env, ptr, ra);
+ CPUX86State *env = ac->env;
+ do_xrstor_fpu(ac, ptr);
if (env->cr[4] & CR4_OSFXSR_MASK) {
- do_xrstor_mxcsr(env, ptr, ra);
+ do_xrstor_mxcsr(ac, ptr);
/* Fast FXRSTOR leaves out the XMM registers */
if (!(env->efer & MSR_EFER_FFXSR)
|| (env->hflags & HF_CPL_MASK)
|| !(env->hflags & HF_LMA_MASK)) {
- do_xrstor_sse(env, ptr, ra);
+ do_xrstor_sse(ac, ptr);
}
}
}
void helper_fxrstor(CPUX86State *env, target_ulong ptr)
{
- do_fxrstor(env, ptr, GETPC());
+ uintptr_t ra = GETPC();
+ X86Access ac;
+
+ /* The operand must be 16 byte aligned */
+ if (ptr & 0xf) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ access_prepare(&ac, env, ptr, sizeof(X86LegacyXSaveArea),
+ MMU_DATA_LOAD, ra);
+ do_fxrstor(&ac, ptr);
}
-static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr_t ra)
+static bool valid_xrstor_header(X86Access *ac, uint64_t *pxsbv,
+ target_ulong ptr)
{
uint64_t xstate_bv, xcomp_bv, reserve0;
- rfbm &= env->xcr0;
+ xstate_bv = access_ldq(ac, ptr + XO(header.xstate_bv));
+ xcomp_bv = access_ldq(ac, ptr + XO(header.xcomp_bv));
+ reserve0 = access_ldq(ac, ptr + XO(header.reserve0));
+ *pxsbv = xstate_bv;
- /* The OS must have enabled XSAVE. */
- if (!(env->cr[4] & CR4_OSXSAVE_MASK)) {
- raise_exception_ra(env, EXCP06_ILLOP, ra);
- }
-
- /* The operand must be 64 byte aligned. */
- if (ptr & 63) {
- raise_exception_ra(env, EXCP0D_GPF, ra);
- }
-
- xstate_bv = cpu_ldq_data_ra(env, ptr + XO(header.xstate_bv), ra);
-
- if ((int64_t)xstate_bv < 0) {
- /* FIXME: Compact form. */
- raise_exception_ra(env, EXCP0D_GPF, ra);
+ /*
+ * XCOMP_BV bit 63 indicates compact form, which we do not support,
+ * and thus must raise #GP. That leaves us in standard form.
+ * In standard form, bytes 23:8 must be zero -- which is both
+ * XCOMP_BV and the following 64-bit field.
+ */
+ if (xcomp_bv || reserve0) {
+ return false;
}
- /* Standard form. */
-
/* The XSTATE_BV field must not set bits not present in XCR0. */
- if (xstate_bv & ~env->xcr0) {
- raise_exception_ra(env, EXCP0D_GPF, ra);
- }
+ return (xstate_bv & ~ac->env->xcr0) == 0;
+}
- /* The XCOMP_BV field must be zero. Note that, as of the April 2016
- revision, the description of the XSAVE Header (Vol 1, Sec 13.4.2)
- describes only XCOMP_BV, but the description of the standard form
- of XRSTOR (Vol 1, Sec 13.8.1) checks bytes 23:8 for zero, which
- includes the next 64-bit field. */
- xcomp_bv = cpu_ldq_data_ra(env, ptr + XO(header.xcomp_bv), ra);
- reserve0 = cpu_ldq_data_ra(env, ptr + XO(header.reserve0), ra);
- if (xcomp_bv || reserve0) {
- raise_exception_ra(env, EXCP0D_GPF, ra);
- }
+static void do_xrstor(X86Access *ac, target_ulong ptr,
+ uint64_t rfbm, uint64_t xstate_bv)
+{
+ CPUX86State *env = ac->env;
if (rfbm & XSTATE_FP_MASK) {
if (xstate_bv & XSTATE_FP_MASK) {
- do_xrstor_fpu(env, ptr, ra);
+ do_xrstor_fpu(ac, ptr);
} else {
do_fninit(env);
memset(env->fpregs, 0, sizeof(env->fpregs));
@@ -2895,23 +2945,23 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr
if (rfbm & XSTATE_SSE_MASK) {
/* Note that the standard form of XRSTOR loads MXCSR from memory
whether or not the XSTATE_BV bit is set. */
- do_xrstor_mxcsr(env, ptr, ra);
+ do_xrstor_mxcsr(ac, ptr);
if (xstate_bv & XSTATE_SSE_MASK) {
- do_xrstor_sse(env, ptr, ra);
+ do_xrstor_sse(ac, ptr);
} else {
do_clear_sse(env);
}
}
if (rfbm & XSTATE_YMM_MASK) {
if (xstate_bv & XSTATE_YMM_MASK) {
- do_xrstor_ymmh(env, ptr + XO(avx_state), ra);
+ do_xrstor_ymmh(ac, ptr + XO(avx_state));
} else {
do_clear_ymmh(env);
}
}
if (rfbm & XSTATE_BNDREGS_MASK) {
if (xstate_bv & XSTATE_BNDREGS_MASK) {
- do_xrstor_bndregs(env, ptr + XO(bndreg_state), ra);
+ do_xrstor_bndregs(ac, ptr + XO(bndreg_state));
env->hflags |= HF_MPX_IU_MASK;
} else {
memset(env->bnd_regs, 0, sizeof(env->bnd_regs));
@@ -2920,7 +2970,7 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr
}
if (rfbm & XSTATE_BNDCSR_MASK) {
if (xstate_bv & XSTATE_BNDCSR_MASK) {
- do_xrstor_bndcsr(env, ptr + XO(bndcsr_state), ra);
+ do_xrstor_bndcsr(ac, ptr + XO(bndcsr_state));
} else {
memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs));
}
@@ -2929,7 +2979,7 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr
if (rfbm & XSTATE_PKRU_MASK) {
uint64_t old_pkru = env->pkru;
if (xstate_bv & XSTATE_PKRU_MASK) {
- do_xrstor_pkru(env, ptr + XO(pkru_state), ra);
+ do_xrstor_pkru(ac, ptr + XO(pkru_state));
} else {
env->pkru = 0;
}
@@ -2944,38 +2994,117 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr
void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
{
- do_xrstor(env, ptr, rfbm, GETPC());
+ uintptr_t ra = GETPC();
+ X86Access ac;
+ uint64_t xstate_bv;
+ unsigned size, size_ext;
+
+ do_xsave_chk(env, ptr, ra);
+
+ /* Begin with just the minimum size to validate the header. */
+ size = sizeof(X86LegacyXSaveArea) + sizeof(X86XSaveHeader);
+ access_prepare(&ac, env, ptr, size, MMU_DATA_LOAD, ra);
+ if (!valid_xrstor_header(&ac, &xstate_bv, ptr)) {
+ raise_exception_ra(env, EXCP0D_GPF, ra);
+ }
+
+ rfbm &= env->xcr0;
+ size_ext = xsave_area_size(rfbm & xstate_bv, false);
+ if (size < size_ext) {
+ /* TODO: See if existing page probe has covered extra size. */
+ access_prepare(&ac, env, ptr, size_ext, MMU_DATA_LOAD, ra);
+ }
+
+ do_xrstor(&ac, ptr, rfbm, xstate_bv);
}
#if defined(CONFIG_USER_ONLY)
-void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32)
+void cpu_x86_fsave(CPUX86State *env, void *host, size_t len)
{
- do_fsave(env, ptr, data32, 0);
+ X86Access ac = {
+ .haddr1 = host,
+ .size = 4 * 7 + 8 * 10,
+ .env = env,
+ };
+
+ assert(ac.size <= len);
+ do_fsave(&ac, 0, true);
}
-void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
+void cpu_x86_frstor(CPUX86State *env, void *host, size_t len)
{
- do_frstor(env, ptr, data32, 0);
+ X86Access ac = {
+ .haddr1 = host,
+ .size = 4 * 7 + 8 * 10,
+ .env = env,
+ };
+
+ assert(ac.size <= len);
+ do_frstor(&ac, 0, true);
}
-void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr)
+void cpu_x86_fxsave(CPUX86State *env, void *host, size_t len)
{
- do_fxsave(env, ptr, 0);
+ X86Access ac = {
+ .haddr1 = host,
+ .size = sizeof(X86LegacyXSaveArea),
+ .env = env,
+ };
+
+ assert(ac.size <= len);
+ do_fxsave(&ac, 0);
}
-void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr)
+void cpu_x86_fxrstor(CPUX86State *env, void *host, size_t len)
{
- do_fxrstor(env, ptr, 0);
+ X86Access ac = {
+ .haddr1 = host,
+ .size = sizeof(X86LegacyXSaveArea),
+ .env = env,
+ };
+
+ assert(ac.size <= len);
+ do_fxrstor(&ac, 0);
}
-void cpu_x86_xsave(CPUX86State *env, target_ulong ptr)
+void cpu_x86_xsave(CPUX86State *env, void *host, size_t len, uint64_t rfbm)
{
- do_xsave(env, ptr, -1, get_xinuse(env), -1, 0);
+ X86Access ac = {
+ .haddr1 = host,
+ .env = env,
+ };
+
+ /*
+ * Since this is only called from user-level signal handling,
+ * we should have done the job correctly there.
+ */
+ assert((rfbm & ~env->xcr0) == 0);
+ ac.size = xsave_area_size(rfbm, false);
+ assert(ac.size <= len);
+ do_xsave_access(&ac, 0, rfbm, get_xinuse(env), rfbm);
}
-void cpu_x86_xrstor(CPUX86State *env, target_ulong ptr)
+bool cpu_x86_xrstor(CPUX86State *env, void *host, size_t len, uint64_t rfbm)
{
- do_xrstor(env, ptr, -1, 0);
+ X86Access ac = {
+ .haddr1 = host,
+ .env = env,
+ };
+ uint64_t xstate_bv;
+
+ /*
+ * Since this is only called from user-level signal handling,
+ * we should have done the job correctly there.
+ */
+ assert((rfbm & ~env->xcr0) == 0);
+ ac.size = xsave_area_size(rfbm, false);
+ assert(ac.size <= len);
+
+ if (!valid_xrstor_header(&ac, &xstate_bv, 0)) {
+ return false;
+ }
+ do_xrstor(&ac, 0, rfbm, xstate_bv);
+ return true;
}
#endif