pan/cs: Add a facility to restrict register access

If the CS register file is used in a stateful mode, some of the registers
will survive the RUN_xxx boundary, and even serve as a context for
subsequent RUN_xxx calls.

Having a way to restrict register access outside specific sections of
code is a handy debug feature, so let's expose the necessary bits to
allow that.

It takes the form of a reg permission callback that gets called every
time a register serves are a source or destination, to make sure this
is allowed in this context.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Rebecca Mckeever <rebecca.mckeever@collabora.com>
Reviewed-by: Mary Guillemard <mary.guillemard@collabora.com>
Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com>
Reviewed-by: John Anthony <john.anthony@arm.com>
Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30969>
This commit is contained in:
Boris Brezillon
2024-09-03 18:09:56 +02:00
committed by Marge Bot
parent 07c463d06b
commit 07b31b2204
+41 -12
View File
@@ -68,6 +68,17 @@ struct cs_load_store_tracker {
uint8_t sb_slot;
};
enum cs_reg_perm {
CS_REG_NO_ACCESS = 0,
CS_REG_RD = BITFIELD_BIT(1),
CS_REG_WR = BITFIELD_BIT(2),
CS_REG_RW = CS_REG_RD | CS_REG_WR,
};
struct cs_builder;
typedef enum cs_reg_perm (*reg_perm_cb_t)(struct cs_builder *b, unsigned reg);
struct cs_builder_conf {
/* Number of 32-bit registers in the hardware register file */
uint8_t nr_registers;
@@ -81,6 +92,9 @@ struct cs_builder_conf {
/* Optional load/store tracker. */
struct cs_load_store_tracker *ls_tracker;
/* Optional register access checker. */
reg_perm_cb_t reg_perm;
/* Cookie passed back to alloc_buffer() */
void *cookie;
};
@@ -291,15 +305,22 @@ cs_to_reg_tuple(struct cs_index idx, ASSERTED unsigned expected_size)
static inline unsigned
cs_src_tuple(struct cs_builder *b, struct cs_index src, ASSERTED unsigned count)
{
struct cs_load_store_tracker *ls_tracker = b->conf.ls_tracker;
unsigned reg = cs_to_reg_tuple(src, count);
if (likely(!ls_tracker))
return reg;
if (unlikely(b->conf.reg_perm)) {
for (unsigned i = reg; i < reg + count; i++) {
assert((b->conf.reg_perm(b, i) & CS_REG_RD) ||
!"Trying to read a restricted register");
}
}
for (unsigned i = reg; i < reg + count; i++) {
if (BITSET_TEST(ls_tracker->pending_loads, i))
assert(!"register used as a source before flushing loads\n");
struct cs_load_store_tracker *ls_tracker = b->conf.ls_tracker;
if (unlikely(ls_tracker)) {
for (unsigned i = reg; i < reg + count; i++) {
if (BITSET_TEST(ls_tracker->pending_loads, i))
assert(!"register used as a source before flushing loads\n");
}
}
return reg;
@@ -320,15 +341,23 @@ cs_src64(struct cs_builder *b, struct cs_index src)
static inline unsigned
cs_dst_tuple(struct cs_builder *b, struct cs_index dst, ASSERTED unsigned count)
{
struct cs_load_store_tracker *ls_tracker = b->conf.ls_tracker;
unsigned reg = cs_to_reg_tuple(dst, count);
if (likely(!ls_tracker))
return reg;
if (unlikely(b->conf.reg_perm)) {
for (unsigned i = reg; i < reg + count; i++) {
assert((b->conf.reg_perm(b, i) & CS_REG_WR) ||
!"Trying to write a restricted register");
}
}
for (unsigned i = reg; i < reg + count; i++) {
if (BITSET_TEST(ls_tracker->pending_stores, i))
assert(!"register reused as a destination before flushing stores\n");
struct cs_load_store_tracker *ls_tracker = b->conf.ls_tracker;
if (unlikely(ls_tracker)) {
for (unsigned i = reg; i < reg + count; i++) {
if (BITSET_TEST(ls_tracker->pending_stores, i))
assert(
!"register reused as a destination before flushing stores\n");
}
}
return reg;