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,