perror_with_name (_("Unable to store GCS registers"));
}
+/* Fill GDB's REGCACHE with the FPMR register set content from the
+ thread associated with REGCACHE. */
+
+static void
+fetch_fpmr_from_thread (struct regcache *regcache)
+{
+ aarch64_gdbarch_tdep *tdep
+ = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
+
+ int tid = regcache->ptid ().lwp ();
+
+ struct iovec iov;
+ uint64_t val;
+ iov.iov_base = &val;
+ iov.iov_len = sizeof (val);
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_FPMR, &iov) < 0)
+ perror_with_name (_("Unable to fetch FPMR register set"));
+ regcache->raw_supply (tdep->fpmr_regnum, &val);
+}
+
+/* Store the NT_ARM_FPMR register set contents from GDB's REGCACHE to the
+ thread associated with REGCACHE. */
+
+static void
+store_fpmr_to_thread (struct regcache *regcache)
+{
+ aarch64_gdbarch_tdep *tdep
+ = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
+
+ int tid = regcache->ptid ().lwp ();
+
+ struct iovec iov;
+ uint64_t val;
+ iov.iov_base = &val;
+ iov.iov_len = sizeof (val);
+
+ regcache->raw_collect (tdep->fpmr_regnum, (char *) &val);
+ if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_FPMR, &iov) < 0)
+ perror_with_name (_("Unable to store FPMR register set"));
+}
+
/* The AArch64 version of the "fetch_registers" target_ops method. Fetch
REGNO from the target and place the result into REGCACHE. */
if (tdep->has_gcs_linux ())
fetch_gcsregs_from_thread (regcache);
+
+ if (tdep->has_fpmr ())
+ fetch_fpmr_from_thread (regcache);
}
/* General purpose register? */
else if (regno < AARCH64_V0_REGNUM)
&& (regno == tdep->gcs_reg_base || regno == tdep->gcs_linux_reg_base
|| regno == tdep->gcs_linux_reg_base + 1))
fetch_gcsregs_from_thread (regcache);
+ /* FPMR? */
+ else if (tdep->has_fpmr () && (regno == tdep->fpmr_regnum))
+ fetch_fpmr_from_thread (regcache);
}
/* A version of the "fetch_registers" target_ops method used when running
if (tdep->has_gcs_linux ())
store_gcsregs_to_thread (regcache);
+
+ if (tdep->has_fpmr ())
+ store_fpmr_to_thread (regcache);
}
/* General purpose register? */
else if (regno < AARCH64_V0_REGNUM)
&& (regno == tdep->gcs_reg_base || regno == tdep->gcs_linux_reg_base
|| regno == tdep->gcs_linux_reg_base + 1))
store_gcsregs_to_thread (regcache);
+ /* FPMR? */
+ else if (tdep->has_fpmr () && regno == tdep->fpmr_regnum)
+ store_fpmr_to_thread (regcache);
/* PAuth registers are read-only. */
}
if ((hwcap2 & HWCAP2_SME2) || (hwcap2 & HWCAP2_SME2P1))
features.sme2 = supports_zt_registers (tid);
+ /* Check for FPMR. */
+ features.fpmr = hwcap2 & HWCAP2_FPMR;
+
return aarch64_read_description (features);
}
features.pauth = hwcap & AARCH64_HWCAP_PACA;
features.gcs = features.gcs_linux = hwcap & HWCAP_GCS;
features.mte = hwcap2 & HWCAP2_MTE;
+ features.fpmr = hwcap2 & HWCAP2_FPMR;
/* Handle the TLS section. */
asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
features.gcs_linux = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.gcs.linux")
!= nullptr);
+ /* Check for FPMR feature. */
+ features.fpmr = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr")
+ != nullptr);
+
return features;
}
num_pseudo_regs += 32; /* add the Bn scalar register pseudos */
}
+ int fpmr_regnum = -1;
+ const struct tdesc_feature *feature_fpmr
+ = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr");
+ if (feature_fpmr != nullptr)
+ {
+ fpmr_regnum = num_regs++;
+ valid_p &= tdesc_numbered_register (feature_fpmr, tdesc_data.get (),
+ fpmr_regnum, "fpmr");
+ }
+
int first_sme_regnum = -1;
int first_sme2_regnum = -1;
int first_sme_pseudo_regnum = -1;
tdep->tls_register_count = tls_register_count;
tdep->gcs_reg_base = first_gcs_regnum;
tdep->gcs_linux_reg_base = first_gcs_linux_regnum;
+ tdep->fpmr_regnum = fpmr_regnum;
/* Set the SME register set details. The pseudo-registers will be adjusted
later. */
{
return gcs_linux_reg_base != -1;
}
+
+ /* First FPMR register. This is -1 if FPMR is not supported. */
+ int fpmr_regnum = -1;
+
+ bool
+ has_fpmr () const
+ {
+ return fpmr_regnum != -1;
+ }
};
const target_desc *aarch64_read_description (const aarch64_features &features);
#include "../features/aarch64-core.c"
#include "../features/aarch64-fpu.c"
+#include "../features/aarch64-fpmr.c"
#include "../features/aarch64-sve.c"
#include "../features/aarch64-pauth.c"
#include "../features/aarch64-mte.c"
if (features.gcs_linux)
regnum = create_feature_aarch64_gcs_linux (tdesc.get (), regnum);
+ if (features.fpmr)
+ regnum = create_feature_aarch64_fpmr (tdesc.get (), regnum);
+
return tdesc.release ();
}
uint64_t vq = 0;
bool pauth = false;
bool mte = false;
+ bool fpmr = false;
/* A positive TLS value indicates the number of TLS registers available. */
uint8_t tls = 0;
&& lhs.svq == rhs.svq
&& lhs.sme2 == rhs.sme2
&& lhs.gcs == rhs.gcs
- && lhs.gcs_linux == rhs.gcs_linux;
+ && lhs.gcs_linux == rhs.gcs_linux
+ && lhs.fpmr == rhs.fpmr;
}
namespace std
h = h << 1 | features.gcs;
h = h << 1 | features.gcs_linux;
+ /* FPMR feature. */
+ h = h << 1 | features.fpmr;
return h;
}
};
/* Size of the SME2 ZT0 register in bytes. */
#define AARCH64_SME2_ZT0_SIZE 64
+/* Feature check for Floating Point Mode Register. */
+#ifndef HWCAP2_FPMR
+#define HWCAP2_FPMR (1ULL << 48)
+#endif /* HWCAP2_FPMR */
+
#endif /* GDB_ARCH_AARCH64_H */
# For targets with feature based target descriptions,
# the set of xml files we'll generate .c files for GDB from.
FEATURE_XMLFILES = aarch64-core.xml \
+ aarch64-fpmr.xml \
aarch64-fpu.xml \
aarch64-pauth.xml \
aarch64-mte.xml \
--- /dev/null
+/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro:
+ Original: aarch64-fpmr.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_aarch64_fpmr (struct target_desc *result, long regnum)
+{
+ struct tdesc_feature *feature;
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.fpmr");
+ tdesc_type_with_fields *type_with_fields;
+ type_with_fields = tdesc_create_enum (feature, "fp8_fmt", 3);
+ tdesc_add_enum_value (type_with_fields, 0, "E5M2");
+ tdesc_add_enum_value (type_with_fields, 1, "E4M3");
+
+ type_with_fields = tdesc_create_enum (feature, "osc", 1);
+ tdesc_add_enum_value (type_with_fields, 0, "Inf/NaN");
+ tdesc_add_enum_value (type_with_fields, 1, "MaxNormal");
+
+ type_with_fields = tdesc_create_enum (feature, "osm", 1);
+ tdesc_add_enum_value (type_with_fields, 0, "Inf");
+ tdesc_add_enum_value (type_with_fields, 1, "MaxNormal");
+
+ type_with_fields = tdesc_create_flags (feature, "fpmr_flags", 8);
+ tdesc_type *field_type;
+ field_type = tdesc_named_type (feature, "fp8_fmt");
+ tdesc_add_typed_bitfield (type_with_fields, "F8S1", 0, 2, field_type);
+ field_type = tdesc_named_type (feature, "fp8_fmt");
+ tdesc_add_typed_bitfield (type_with_fields, "F8S2", 3, 5, field_type);
+ field_type = tdesc_named_type (feature, "fp8_fmt");
+ tdesc_add_typed_bitfield (type_with_fields, "F8D", 6, 8, field_type);
+ field_type = tdesc_named_type (feature, "osm");
+ tdesc_add_typed_bitfield (type_with_fields, "OSM", 14, 14, field_type);
+ field_type = tdesc_named_type (feature, "osc");
+ tdesc_add_typed_bitfield (type_with_fields, "OSC", 15, 15, field_type);
+ tdesc_add_bitfield (type_with_fields, "LSCALE", 16, 22);
+ field_type = tdesc_named_type (feature, "int8");
+ tdesc_add_typed_bitfield (type_with_fields, "NSCALE", 24, 31, field_type);
+ tdesc_add_bitfield (type_with_fields, "LSCALE2", 32, 37);
+
+ tdesc_create_reg (feature, "fpmr", regnum++, 1, NULL, 64, "fpmr_flags");
+ return regnum;
+}
--- /dev/null
+<?xml version="1.0"?>
+<!-- Copyright (C) 2025 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.aarch64.fpmr">
+
+ <!-- FP8 format for F8S1, F8S2 and F8D fields. This is either E5M2 or
+ E4M3. -->
+ <enum id="fp8_fmt" size="3">
+ <evalue name="E5M2" value="0"/>
+ <evalue name="E4M3" value="1"/>
+ </enum>
+
+ <!-- Overflow saturation for FP8 convert instructions. Specifies the result
+ when a floating-point overflow exception is detected. -->
+ <enum id="osc" size="1">
+ <!-- Infinity or NaN is generated. -->
+ <evalue name="Inf/NaN" value="0"/>
+ <!-- Maximum normal number is generated. -->
+ <evalue name="MaxNormal" value="1"/>
+ </enum>
+
+ <!-- Overflow saturation for FP8 multiplication instructions. Specifies the
+ result when a floating-point overflow exception is detected. -->
+ <enum id="osm" size="1">
+ <!-- Infinity generated. -->
+ <evalue name="Inf" value="0"/>
+ <!-- Maximum normal number is generated. -->
+ <evalue name="MaxNormal" value="1"/>
+ </enum>
+
+ <flags id="fpmr_flags" size="8">
+ <!-- SRC1 Format. -->
+ <field name="F8S1" start="0" end="2" type="fp8_fmt"/>
+ <!-- SRC2 Format. -->
+ <field name="F8S2" start="3" end="5" type="fp8_fmt"/>
+ <!-- F8D Format. -->
+ <field name="F8D" start="6" end="8" type="fp8_fmt"/>
+ <!-- OSM. -->
+ <field name="OSM" start="14" end="14" type="osm"/>
+ <!-- OSC. -->
+ <field name="OSC" start="15" end="15" type="osc"/>
+ <!-- LSCALE. -->
+ <field name="LSCALE" start="16" end="22"/>
+ <!-- NSCALE. -->
+ <field name="NSCALE" start="24" end="31" type="int8"/>
+ <!-- LSCALE2. -->
+ <field name="LSCALE2" start="32" end="37"/>
+ </flags>
+
+ <reg name="fpmr" bitsize="64" type="fpmr_flags"/>
+
+</feature>