diff options
Diffstat (limited to 'gdb/nat')
-rw-r--r-- | gdb/nat/aarch64-scalable-linux-ptrace.c | 134 | ||||
-rw-r--r-- | gdb/nat/aarch64-scalable-linux-ptrace.h | 26 |
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 */ |