aboutsummaryrefslogtreecommitdiff
path: root/gdb/nat
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/nat')
-rw-r--r--gdb/nat/aarch64-scalable-linux-ptrace.c134
-rw-r--r--gdb/nat/aarch64-scalable-linux-ptrace.h26
2 files changed, 160 insertions, 0 deletions
diff --git a/gdb/nat/aarch64-scalable-linux-ptrace.c b/gdb/nat/aarch64-scalable-linux-ptrace.c
index d3a50ed..dc0e45f 100644
--- a/gdb/nat/aarch64-scalable-linux-ptrace.c
+++ b/gdb/nat/aarch64-scalable-linux-ptrace.c
@@ -519,10 +519,75 @@ aarch64_initialize_za_regset (int tid)
if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZA, &iovec) < 0)
perror_with_name (_("Failed to initialize the NT_ARM_ZA register set."));
+ if (supports_zt_registers (tid))
+ {
+ /* If this target supports SME2, upon initializing ZA, we also need to
+ initialize the ZT registers with 0 values. Do so now. */
+ gdb::byte_vector zt_new_state (AARCH64_SME2_ZT0_SIZE, 0);
+ aarch64_store_zt_regset (tid, zt_new_state);
+ }
+
/* The NT_ARM_ZA register set should now contain a zero-initialized ZA
payload. */
}
+/* See nat/aarch64-scalable-linux-ptrace.h. */
+
+gdb::byte_vector
+aarch64_fetch_zt_regset (int tid)
+{
+ /* Read NT_ARM_ZT. This register set is only available if
+ the ZA bit is non-zero. */
+ gdb::byte_vector zt_state (AARCH64_SME2_ZT0_SIZE);
+
+ struct iovec iovec;
+ iovec.iov_len = AARCH64_SME2_ZT0_SIZE;
+ iovec.iov_base = zt_state.data ();
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZT, &iovec) < 0)
+ perror_with_name (_("Failed to fetch NT_ARM_ZT register set."));
+
+ return zt_state;
+}
+
+/* See nat/aarch64-scalable-linux-ptrace.h. */
+
+void
+aarch64_store_zt_regset (int tid, const gdb::byte_vector &zt_state)
+{
+ gdb_assert (zt_state.size () == AARCH64_SME2_ZT0_SIZE
+ || zt_state.size () == 0);
+
+ /* We need to be mindful of writing data to NT_ARM_ZT. If the ZA bit
+ is 0 and we write something to ZT, it will flip the ZA bit.
+
+ Right now this is taken care of by callers of this function. */
+ struct iovec iovec;
+ iovec.iov_len = zt_state.size ();
+ iovec.iov_base = (void *) zt_state.data ();
+
+ /* Write the contents of ZT_STATE to the NT_ARM_ZT register set. */
+ if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_ZT, &iovec) < 0)
+ perror_with_name (_("Failed to write to the NT_ARM_ZT register set."));
+}
+
+/* See nat/aarch64-scalable-linux-ptrace.h. */
+
+bool
+supports_zt_registers (int tid)
+{
+ gdb_byte zt_state[AARCH64_SME2_ZT0_SIZE];
+
+ struct iovec iovec;
+ iovec.iov_len = AARCH64_SME2_ZT0_SIZE;
+ iovec.iov_base = (void *) zt_state;
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_ZT, &iovec) < 0)
+ return false;
+
+ return true;
+}
+
/* If we are running in BE mode, byteswap the contents
of SRC to DST for SIZE bytes. Other, just copy the contents
from SRC to DST. */
@@ -989,3 +1054,72 @@ aarch64_za_regs_copy_from_reg_buf (int tid,
/* At this point we have written the data contained in the register cache to
the thread's NT_ARM_ZA register set. */
}
+
+/* See nat/aarch64-scalable-linux-ptrace.h. */
+
+void
+aarch64_zt_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf,
+ int zt_regnum)
+{
+ /* If we have ZA state, read the ZT state. Otherwise, make the contents of
+ ZT in the register cache all zeroes. This is how we present the ZT
+ state when it is not initialized (ZA not active). */
+ if (aarch64_has_za_state (tid))
+ {
+ /* Fetch the current ZT state from the thread. */
+ gdb::byte_vector zt_state = aarch64_fetch_zt_regset (tid);
+
+ /* Sanity check. */
+ gdb_assert (!zt_state.empty ());
+
+ /* Copy the ZT data to the register buffer. */
+ reg_buf->raw_supply (zt_regnum, zt_state.data ());
+ }
+ else
+ {
+ /* Zero out ZT. */
+ gdb::byte_vector zt_zeroed (AARCH64_SME2_ZT0_SIZE, 0);
+ reg_buf->raw_supply (zt_regnum, zt_zeroed.data ());
+ }
+
+ /* The register buffer should now contain the updated copy of the NT_ARM_ZT
+ state. */
+}
+
+/* See nat/aarch64-scalable-linux-ptrace.h. */
+
+void
+aarch64_zt_regs_copy_from_reg_buf (int tid,
+ struct reg_buffer_common *reg_buf,
+ int zt_regnum)
+{
+ /* Do we have a valid ZA state? */
+ bool valid_za = aarch64_has_za_state (tid);
+
+ /* Is the register buffer contents for ZT all zeroes? */
+ gdb::byte_vector zt_bytes (AARCH64_SME2_ZT0_SIZE, 0);
+ bool zt_is_all_zeroes
+ = reg_buf->raw_compare (zt_regnum, zt_bytes.data (), 0);
+
+ /* If ZA state is valid or if we have non-zero data for ZT in the register
+ buffer, we will invoke ptrace to write the ZT state. Otherwise we don't
+ have to do anything here. */
+ if (valid_za || !zt_is_all_zeroes)
+ {
+ if (!valid_za)
+ {
+ /* ZA state is not valid. That means we need to initialize the ZA
+ state prior to writing the ZT state. */
+ aarch64_initialize_za_regset (tid);
+ }
+
+ /* Extract the ZT data from the register buffer. */
+ reg_buf->raw_collect (zt_regnum, zt_bytes.data ());
+
+ /* Write the ZT data to thread TID. */
+ aarch64_store_zt_regset (tid, zt_bytes);
+ }
+
+ /* At this point we have (potentially) written the data contained in the
+ register cache to the thread's NT_ARM_ZT register set. */
+}
diff --git a/gdb/nat/aarch64-scalable-linux-ptrace.h b/gdb/nat/aarch64-scalable-linux-ptrace.h
index d609933..69c9982 100644
--- a/gdb/nat/aarch64-scalable-linux-ptrace.h
+++ b/gdb/nat/aarch64-scalable-linux-ptrace.h
@@ -120,6 +120,16 @@ extern void aarch64_store_za_regset (int tid, const gdb::byte_vector &za_state);
size. The bytes of the ZA register are initialized to zero. */
extern void aarch64_initialize_za_regset (int tid);
+/* Given TID, return the NT_ARM_ZT register set data as a vector of bytes. */
+extern gdb::byte_vector aarch64_fetch_zt_regset (int tid);
+
+/* Write ZT_STATE for TID. */
+extern void aarch64_store_zt_regset (int tid, const gdb::byte_vector &zt_state);
+
+/* Return TRUE if thread TID supports the NT_ARM_ZT register set.
+ Return FALSE otherwise. */
+extern bool supports_zt_registers (int tid);
+
/* Given a register buffer REG_BUF, update it with SVE/SSVE register data
from SVE_STATE. */
extern void
@@ -151,4 +161,20 @@ aarch64_za_regs_copy_from_reg_buf (int tid,
struct reg_buffer_common *reg_buf,
int za_regnum, int svg_regnum,
int svcr_regnum);
+
+/* Given a thread id TID and a register buffer REG_BUF, update the register
+ buffer with the ZT register set state from thread TID.
+
+ ZT_REGNUM is the register number for ZT0. */
+extern void
+aarch64_zt_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf,
+ int zt_regnum);
+
+/* Given a thread id TID and a register buffer REG_BUF containing the ZT
+ register set state, write the ZT data to thread TID.
+
+ ZT_REGNUM is the register number for ZT0. */
+extern void
+aarch64_zt_regs_copy_from_reg_buf (int tid, struct reg_buffer_common *reg_buf,
+ int zt_regnum);
#endif /* NAT_AARCH64_SCALABLE_LINUX_PTRACE_H */