Signed-off-by: Richard Henderson <[email protected]>
---
linux-user/aarch64/signal.c | 44 ++++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index f7edfa249e..899fce7643 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -73,6 +73,13 @@ struct target_esr_context {
uint64_t esr;
};
+#define TARGET_FPMR_MAGIC 0x46504d52
+
+struct target_fpmr_context {
+ struct target_aarch64_ctx head;
+ uint64_t fpmr;
+};
+
#define TARGET_EXTRA_MAGIC 0x45585401
struct target_extra_context {
@@ -362,6 +369,14 @@ static bool target_setup_gcs_record(struct
target_gcs_context *ctx,
return true;
}
+static void target_setup_fpmr_record(struct target_fpmr_context *ctx,
+ CPUARMState *env)
+{
+ __put_user(TARGET_FPMR_MAGIC, &ctx->head.magic);
+ __put_user(sizeof(*ctx), &ctx->head.size);
+ __put_user(env->vfp.fpmr, &ctx->fpmr);
+}
+
static void target_restore_general_frame(CPUARMState *env,
struct target_rt_sigframe *sf)
{
@@ -518,6 +533,12 @@ static void target_restore_tpidr2_record(CPUARMState *env,
__get_user(env->cp15.tpidr2_el0, &tpidr2->tpidr2);
}
+static void target_restore_fpmr_record(CPUARMState *env,
+ struct target_fpmr_context *fpmr)
+{
+ __get_user(env->vfp.fpmr, &fpmr->fpmr);
+}
+
static bool target_restore_zt_record(CPUARMState *env,
struct target_zt_context *zt, int size,
int svcr)
@@ -610,6 +631,7 @@ static int target_restore_sigframe(CPUARMState *env,
struct target_tpidr2_context *tpidr2 = NULL;
struct target_zt_context *zt = NULL;
struct target_gcs_context *gcs = NULL;
+ struct target_fpmr_context *fpmr = NULL;
uint64_t extra_datap = 0;
bool used_extra = false;
bool rebuild_hflags = false;
@@ -691,6 +713,15 @@ static int target_restore_sigframe(CPUARMState *env,
gcs = (struct target_gcs_context *)ctx;
break;
+ case TARGET_FPMR_MAGIC:
+ if (fpmr
+ || size != sizeof(struct target_fpmr_context)
+ || !cpu_isar_feature(aa64_fpmr, env_archcpu(env))) {
+ goto err;
+ }
+ fpmr = (struct target_fpmr_context *)ctx;
+ break;
+
case TARGET_EXTRA_MAGIC:
if (extra || size != sizeof(struct target_extra_context)) {
goto err;
@@ -735,6 +766,9 @@ static int target_restore_sigframe(CPUARMState *env,
if (tpidr2) {
target_restore_tpidr2_record(env, tpidr2);
}
+ if (fpmr) {
+ target_restore_fpmr_record(env, fpmr);
+ }
/*
* NB that we must restore ZT after ZA so the check that there's
* no ZT record if SVCR.ZA is 0 gets the right value of SVCR.
@@ -817,7 +851,7 @@ static void target_setup_frame(int usig, struct
target_sigaction *ka,
uc.tuc_mcontext.__reserved),
};
int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0, tpidr2_ofs = 0;
- int zt_ofs = 0, esr_ofs = 0, gcs_ofs = 0;
+ int zt_ofs = 0, esr_ofs = 0, gcs_ofs = 0, fpmr_ofs = 0;
int sve_size = 0, za_size = 0, tpidr2_size = 0, zt_size = 0;
struct target_rt_sigframe *frame;
struct target_rt_frame_record *fr;
@@ -841,6 +875,11 @@ static void target_setup_frame(int usig, struct
target_sigaction *ka,
&layout);
}
+ if (cpu_isar_feature(aa64_fpmr, env_archcpu(env))) {
+ fpmr_ofs = alloc_sigframe_space(sizeof(struct target_fpmr_context),
+ &layout);
+ }
+
/* SVE state needs saving only if it exists. */
if (cpu_isar_feature(aa64_sve, env_archcpu(env)) ||
cpu_isar_feature(aa64_sme, env_archcpu(env))) {
@@ -917,6 +956,9 @@ static void target_setup_frame(int usig, struct
target_sigaction *ka,
!target_setup_gcs_record((void *)frame + gcs_ofs, env, return_addr)) {
goto give_sigsegv;
}
+ if (fpmr_ofs) {
+ target_setup_fpmr_record((void *)frame + fpmr_ofs, env);
+ }
target_setup_end_record((void *)frame + layout.std_end_ofs);
if (layout.extra_ofs) {
target_setup_extra_record((void *)frame + layout.extra_ofs,
--
2.43.0