summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej Żenczykowski <maze@google.com>2024-03-19 11:09:00 -0700
committerMaciej Żenczykowski <maze@google.com>2024-03-19 14:37:32 -0700
commit03c86c94ba3022c7b019f6a30c8f58251cc7b449 (patch)
treef67821b6a47e0666fdf4c7ac78f6d5a97570462b
parent82326fbd6b3b3cdb4b16cad70f502f9d69586fb7 (diff)
downloadapf-03c86c94ba3022c7b019f6a30c8f58251cc7b449.tar.gz
v5: rework LDDW/STDW for APFv6 mode to make them more useful
This makes LDDW/STDW honour firmware endianness in AFPv6+ mode, thus making it possible to store things like APF filter age, or APF version in APF counters without having to further special case reading them. It also removes the (no longer useful) indexing by OTHER_REG, and effectively hardcodes the *4. This makes it possible to more easily use counters as a sort of 'long-term' (ie. surviving from one packet to the next) memory. (Reminder: the standard m[] slots are only valid for the duration of the program.) Note: We can no longer specify the counter to load/store via register, but this seems pretty much impossible to sanely use anyway. If it turns out this support is for some reason desirable, we can easily change imm=0 to mean counter OTHER_REG, but currently this just seems like wasted instructions... After: text data bss dec hex filename 3924 0 0 3924 f54 apf_interpreter.arm.o text data bss dec hex filename 4938 0 0 4938 134a apf_interpreter.x86.o Test: TreeHugger Signed-off-by: Maciej Żenczykowski <maze@google.com> Change-Id: Iccd1c5d40bf074cec8c02953182648709fd45289
-rw-r--r--v5/apf.h1
-rw-r--r--v5/apf_interpreter.c59
-rw-r--r--v5/apf_interpreter_source.c58
3 files changed, 64 insertions, 54 deletions
diff --git a/v5/apf.h b/v5/apf.h
index 69fd941..4f9bccc 100644
--- a/v5/apf.h
+++ b/v5/apf.h
@@ -188,6 +188,7 @@ typedef union {
// NOTE: Only APFv6+ implements R=1 'jbseq' version
#define EXT_OPCODE 21 // Immediate value is one of *_EXT_OPCODE
#define LDDW_OPCODE 22 // Load 4 bytes from data address (register + signed imm): "lddw R0, [5+R1]"
+ // LDDW/STDW in APFv6+ *mode* load/store from counter specified in imm.
#define STDW_OPCODE 23 // Store 4 bytes to data address (register + signed imm): "stdw R0, [5+R1]"
/* Write 1, 2 or 4 byte immediate to the output buffer and auto-increment the output buffer pointer.
diff --git a/v5/apf_interpreter.c b/v5/apf_interpreter.c
index 84afca8..f71db4d 100644
--- a/v5/apf_interpreter.c
+++ b/v5/apf_interpreter.c
@@ -260,6 +260,7 @@ typedef union {
/* NOTE: Only APFv6+ implements R=1 'jbseq' version */
#define EXT_OPCODE 21 /* Immediate value is one of *_EXT_OPCODE */
#define LDDW_OPCODE 22 /* Load 4 bytes from data address (register + signed imm): "lddw R0, [5+R1]" */
+ /* LDDW/STDW in APFv6+ *mode* load/store from counter specified in imm. */
#define STDW_OPCODE 23 /* Store 4 bytes to data address (register + signed imm): "stdw R0, [5+R1]" */
/* Write 1, 2 or 4 byte immediate to the output buffer and auto-increment the output buffer pointer.
@@ -595,7 +596,7 @@ extern void APF_TRACE_HOOK(u32 pc, const u32* regs, const u8* program,
#define ENFORCE_UNSIGNED(c) ((c)==(u32)(c))
u32 apf_version(void) {
- return 20240313;
+ return 20240314;
}
typedef struct {
@@ -975,34 +976,38 @@ static int do_apf_run(apf_context* ctx) {
return PASS_PACKET; /* Bail out */
}
break;
- case LDDW_OPCODE: {
- u32 offs = OTHER_REG + (u32)signed_imm;
- u32 size = 4;
- u32 val = 0;
- /* Negative offsets wrap around the end of the address space. */
- /* This allows us to efficiently access the end of the */
- /* address space with one-byte immediates without using %=. */
- if (offs & 0x80000000) offs += ctx->ram_len; /* unsigned overflow intended */
- ASSERT_IN_DATA_BOUNDS(offs, size);
- while (size--) val = (val << 8) | ctx->program[offs++];
- REG = val;
- break;
- }
- case STDW_OPCODE: {
- u32 offs = OTHER_REG + (u32)signed_imm;
- u32 size = 4;
- u32 val = REG;
- /* Negative offsets wrap around the end of the address space. */
- /* This allows us to efficiently access the end of the */
- /* address space with one-byte immediates without using %=. */
- if (offs & 0x80000000) offs += ctx->ram_len; /* unsigned overflow intended */
- ASSERT_IN_DATA_BOUNDS(offs, size);
- while (size--) {
- ctx->program[offs++] = (val >> 24);
- val <<= 8;
+ case LDDW_OPCODE:
+ case STDW_OPCODE:
+ if (ctx->v6) {
+ if (!imm) return PASS_PACKET;
+ if (imm > 0xFFFF) return PASS_PACKET;
+ if (imm * 4 > ctx->ram_len) return PASS_PACKET;
+ if (opcode == LDDW_OPCODE) {
+ REG = counter[-(s32)imm];
+ } else {
+ counter[-(s32)imm] = REG;
+ }
+ } else {
+ u32 offs = OTHER_REG + (u32)signed_imm;
+ /* Negative offsets wrap around the end of the address space. */
+ /* This allows us to efficiently access the end of the */
+ /* address space with one-byte immediates without using %=. */
+ if (offs & 0x80000000) offs += ctx->ram_len; /* unsigned overflow intended */
+ u32 size = 4;
+ ASSERT_IN_DATA_BOUNDS(offs, size);
+ if (opcode == LDDW_OPCODE) {
+ u32 val = 0;
+ while (size--) val = (val << 8) | ctx->program[offs++];
+ REG = val;
+ } else {
+ u32 val = REG;
+ while (size--) {
+ ctx->program[offs++] = (val >> 24);
+ val <<= 8;
+ }
+ }
}
break;
- }
case WRITE_OPCODE: {
ASSERT_RETURN(ctx->tx_buf);
ASSERT_RETURN(len_field);
diff --git a/v5/apf_interpreter_source.c b/v5/apf_interpreter_source.c
index 5951bfe..5523ac1 100644
--- a/v5/apf_interpreter_source.c
+++ b/v5/apf_interpreter_source.c
@@ -61,7 +61,7 @@ extern void APF_TRACE_HOOK(u32 pc, const u32* regs, const u8* program,
#define ENFORCE_UNSIGNED(c) ((c)==(u32)(c))
u32 apf_version(void) {
- return 20240313;
+ return 20240314;
}
typedef struct {
@@ -441,34 +441,38 @@ static int do_apf_run(apf_context* ctx) {
return PASS_PACKET; // Bail out
}
break;
- case LDDW_OPCODE: {
- u32 offs = OTHER_REG + (u32)signed_imm;
- u32 size = 4;
- u32 val = 0;
- // Negative offsets wrap around the end of the address space.
- // This allows us to efficiently access the end of the
- // address space with one-byte immediates without using %=.
- if (offs & 0x80000000) offs += ctx->ram_len; // unsigned overflow intended
- ASSERT_IN_DATA_BOUNDS(offs, size);
- while (size--) val = (val << 8) | ctx->program[offs++];
- REG = val;
- break;
- }
- case STDW_OPCODE: {
- u32 offs = OTHER_REG + (u32)signed_imm;
- u32 size = 4;
- u32 val = REG;
- // Negative offsets wrap around the end of the address space.
- // This allows us to efficiently access the end of the
- // address space with one-byte immediates without using %=.
- if (offs & 0x80000000) offs += ctx->ram_len; // unsigned overflow intended
- ASSERT_IN_DATA_BOUNDS(offs, size);
- while (size--) {
- ctx->program[offs++] = (val >> 24);
- val <<= 8;
+ case LDDW_OPCODE:
+ case STDW_OPCODE:
+ if (ctx->v6) {
+ if (!imm) return PASS_PACKET;
+ if (imm > 0xFFFF) return PASS_PACKET;
+ if (imm * 4 > ctx->ram_len) return PASS_PACKET;
+ if (opcode == LDDW_OPCODE) {
+ REG = counter[-(s32)imm];
+ } else {
+ counter[-(s32)imm] = REG;
+ }
+ } else {
+ u32 offs = OTHER_REG + (u32)signed_imm;
+ // Negative offsets wrap around the end of the address space.
+ // This allows us to efficiently access the end of the
+ // address space with one-byte immediates without using %=.
+ if (offs & 0x80000000) offs += ctx->ram_len; // unsigned overflow intended
+ u32 size = 4;
+ ASSERT_IN_DATA_BOUNDS(offs, size);
+ if (opcode == LDDW_OPCODE) {
+ u32 val = 0;
+ while (size--) val = (val << 8) | ctx->program[offs++];
+ REG = val;
+ } else {
+ u32 val = REG;
+ while (size--) {
+ ctx->program[offs++] = (val >> 24);
+ val <<= 8;
+ }
+ }
}
break;
- }
case WRITE_OPCODE: {
ASSERT_RETURN(ctx->tx_buf);
ASSERT_RETURN(len_field);