linux-user/aarch64: Implement FPMR signal frames

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260522220306.235200-17-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson
2026-05-22 15:02:18 -07:00
committed by Peter Maydell
parent 5dd04faf9f
commit 82e6411eac

View File

@@ -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,