apf: Tweak the interpreter data addressing scheme
After releasing APFv3, we realized that addressing memory from the top
could be simplified by adjusting a few details:
1) The APF interpreter now receives a single unified buffer containing
both the program bytecode and the data segment, unambiguously matching
the memory layout seen by installApfPacketFilter() and
readApfPacketFilter().
2) Data address zero coincides with the beginning of the APF program,
thus decoupling data addresses from the length of the program (which
could change between invokations of installApfPacketFilter()). This
simplifies the ApfGenerator by not requiring a data relocation step
similar to jump relocation.
3) For convenience, the interpreter pre-fills one volatile memory slot
with the total size of the APF buffer. The APF program can load this
value into a register to efficiently write near the end of the data
segment, thus allowing the program-data boundary to shift freely.
4) Negative addresses wrap around the end of the data buffer, such that
address -1 coincides with the last byte of the buffer.
5) The immediate offet of LDDW and SDDW are now sign-extended, such that
small negative offsets can be encoded as a 1-byte immediate. This,
combined with the modular addressing at (4), can be used to address
memory cells near the end of the data region with 2-byte opcodes.
Overall, the above changes allow building a simple 32bit counter with
a sequence more or less like this:
2 li R1, -4 ; R1 = -4 (last 32bit word of data)
1 lddw R0, [R1 + 0] ; R0 = old counter value
2 add R0, 42 ; Increment counter by some value
1 stdw R0, [R1 + 0] ; Write back the new value
Total: 6 bytes. Note how the above bytecode is independent of the actual
size of the program and data segments. To reduce bytecode size,
the counter increment sequence can be moved to an "IncrementAndDrop"
trampoline, taking only 2 bytes more than a direct jump to DROP:
2 li R1, -12 ; R0 = counter offset (third to last counter)
3 jmp CountAndDrop ; (could be 2 bytes if jumping nearby)
...
CountAndDrop:
1 lddw R0, [R1+0] ; R0 = old counter value
2 add R0, 1 ; Increment counter
1 stdw R0, [R1+0] ; Write back updated value
3 jmp DROP ; cya!
Adding a 1-byte INC instruction would make things a little nicer.
Change-Id: Ia9b25e49e127a48d7344ddc60b17c93d6421ab7d
Bug: 73804303
Test: runtest -x tests/net/java/android/net/apf/ApfTest.java
diff --git a/apf_interpreter.h b/apf_interpreter.h
index 78a0dd3..368ae04 100644
--- a/apf_interpreter.h
+++ b/apf_interpreter.h
@@ -27,26 +27,36 @@
* Version of APF instruction set processed by accept_packet().
* Should be returned by wifi_get_packet_filter_info.
*/
-#define APF_VERSION 3
+#define APF_VERSION 4
/**
* Runs a packet filtering program over a packet.
*
- * @param program the program bytecode.
- * @param program_len the length of {@code apf_program} in bytes.
+ * The text section containing the program instructions starts at address
+ * program and stops at + program_len - 1, and the writable data section
+ * begins at program + program_len and ends at program + ram_len - 1,
+ * as described in the following diagram:
+ *
+ * program program + program_len program + ram_len
+ * | text section | data section |
+ * +--------------------+------------------------+
+ *
+ * @param program the program bytecode, followed by the writable data region.
+ * @param program_len the length in bytes of the read-only portion of the APF
+ * buffer pointed to by {@code program}.
+ * @param ram_len total length of the APF buffer pointed to by {@code program},
+ * including the read-only bytecode portion and the read-write
+ * data portion.
* @param packet the packet bytes, starting from the 802.3 header and not
* including any CRC bytes at the end.
* @param packet_len the length of {@code packet} in bytes.
- * @param data writable data memory region (preserved between packets).
- * @param data_len the length of {@code data} in bytes.
* @param filter_age the number of seconds since the filter was programmed.
*
* @return non-zero if packet should be passed to AP, zero if
* packet should be dropped.
*/
-int accept_packet(const uint8_t* program, uint32_t program_len,
+int accept_packet(uint8_t* program, uint32_t program_len, uint32_t ram_len,
const uint8_t* packet, uint32_t packet_len,
- uint8_t* data, uint32_t data_len,
uint32_t filter_age);
#ifdef __cplusplus