1 /* 2 * Copyright 2024, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ANDROID_APF_APF_H 18 #define ANDROID_APF_APF_H 19 20 /* A brief overview of APF: 21 * 22 * APF machine is composed of: 23 * 1. A read-only program consisting of bytecodes as described below. 24 * 2. Two 32-bit registers, called R0 and R1. 25 * 3. Sixteen 32-bit temporary memory slots (cleared between packets). 26 * 4. A read-only packet. 27 * 5. An optional read-write transmit buffer. 28 * The program is executed by the interpreter below and parses the packet 29 * to determine if the application processor (AP) should be woken up to 30 * handle the packet or if it can be dropped. The program may also choose 31 * to allocate/transmit/deallocate the transmit buffer. 32 * 33 * APF bytecode description: 34 * 35 * The APF interpreter uses big-endian byte order for loads from the packet 36 * and for storing immediates in instructions. 37 * 38 * Each instruction starts with a byte composed of: 39 * Top 5 bits form "opcode" field, see *_OPCODE defines below. 40 * Next 2 bits form "size field", which indicates the length of an immediate 41 * value which follows the first byte. Values in this field: 42 * 0 => immediate value is 0 and no bytes follow. 43 * 1 => immediate value is 1 byte big. 44 * 2 => immediate value is 2 bytes big. 45 * 3 => immediate value is 4 bytes big. 46 * Bottom bit forms "register" field, which (usually) indicates which register 47 * this instruction operates on. 48 * 49 * There are four main categories of instructions: 50 * Load instructions 51 * These instructions load byte(s) of the packet into a register. 52 * They load either 1, 2 or 4 bytes, as determined by the "opcode" field. 53 * They load into the register specified by the "register" field. 54 * The immediate value that follows the first byte of the instruction is 55 * the byte offset from the beginning of the packet to load from. 56 * There are "indexing" loads which add the value in R1 to the byte offset 57 * to load from. The "opcode" field determines which loads are "indexing". 58 * Arithmetic instructions 59 * These instructions perform simple operations, like addition, on register 60 * values. The result of these instructions is always written into R0. One 61 * argument of the arithmetic operation is R0's value. The other argument 62 * of the arithmetic operation is determined by the "register" field: 63 * If the "register" field is 0 then the immediate value following 64 * the first byte of the instruction is used as the other argument 65 * to the arithmetic operation. 66 * If the "register" field is 1 then R1's value is used as the other 67 * argument to the arithmetic operation. 68 * Conditional jump instructions 69 * These instructions compare register R0's value with another value, and if 70 * the comparison succeeds, jump (i.e. adjust the program counter). The 71 * immediate value that follows the first byte of the instruction 72 * represents the jump target offset, i.e. the value added to the program 73 * counter if the comparison succeeds. The other value compared is 74 * determined by the "register" field: 75 * If the "register" field is 0 then another immediate value 76 * follows the jump target offset. This immediate value is of the 77 * same size as the jump target offset, and represents the value 78 * to compare against. 79 * If the "register" field is 1 then register R1's value is 80 * compared against. 81 * The type of comparison (e.g. equal to, greater than etc) is determined 82 * by the "opcode" field. The comparison interprets both values being 83 * compared as unsigned values. 84 * Miscellaneous instructions 85 * Instructions for: 86 * - allocating/transmitting/deallocating transmit buffer 87 * - building the transmit packet (copying bytes into it) 88 * - read/writing data section 89 * 90 * Miscellaneous details: 91 * 92 * Pre-filled temporary memory slot values 93 * When the APF program begins execution, six of the sixteen memory slots 94 * are pre-filled by the interpreter with values that may be useful for 95 * programs: 96 * #0 to #7 are zero initialized. 97 * Slot #8 is initialized with apf version (on APF >4). 98 * Slot #9 this is slot #15 with greater resolution (1/16384ths of a second) 99 * Slot #10 starts at zero, implicitly used as tx buffer output pointer. 100 * Slot #11 contains the size (in bytes) of the APF program. 101 * Slot #12 contains the total size of the APF program + data. 102 * Slot #13 is filled with the IPv4 header length. This value is calculated 103 * by loading the first byte of the IPv4 header and taking the 104 * bottom 4 bits and multiplying their value by 4. This value is 105 * set to zero if the first 4 bits after the link layer header are 106 * not 4, indicating not IPv4. 107 * Slot #14 is filled with size of the packet in bytes, including the 108 * ethernet link-layer header. 109 * Slot #15 is filled with the filter age in seconds. This is the number of 110 * seconds since the host installed the program. This may 111 * be used by filters that should have a particular lifetime. For 112 * example, it can be used to rate-limit particular packets to one 113 * every N seconds. 114 * Special jump targets: 115 * When an APF program executes a jump to the byte immediately after the last 116 * byte of the progam (i.e., one byte past the end of the program), this 117 * signals the program has completed and determined the packet should be 118 * passed to the AP. 119 * When an APF program executes a jump two bytes past the end of the program, 120 * this signals the program has completed and determined the packet should 121 * be dropped. 122 * Jump if byte sequence doesn't match: 123 * This is a special instruction to facilitate matching long sequences of 124 * bytes in the packet. Initially it is encoded like a conditional jump 125 * instruction with two exceptions: 126 * The first byte of the instruction is always followed by two immediate 127 * fields: The first immediate field is the jump target offset like other 128 * conditional jump instructions. The second immediate field specifies the 129 * number of bytes to compare. 130 * These two immediate fields are followed by a sequence of bytes. These 131 * bytes are compared with the bytes in the packet starting from the 132 * position specified by the value of the register specified by the 133 * "register" field of the instruction. 134 */ 135 136 // Number of temporary memory slots, see ldm/stm instructions. 137 #define MEMORY_ITEMS 16 138 // Upon program execution, some temporary memory slots are prefilled: 139 140 typedef union { 141 struct { 142 u32 pad[8]; // 0..7 143 u32 apf_version; // 8: Initialized with apf_version() 144 u32 filter_age_16384ths; // 9: Age since filter installed in 1/16384 seconds. 145 u32 tx_buf_offset; // 10: Offset in tx_buf where next byte will be written 146 u32 program_size; // 11: Size of program (in bytes) 147 u32 ram_len; // 12: Total size of program + data, ie. ram_len 148 u32 ipv4_header_size; // 13: 4*([APF_FRAME_HEADER_SIZE]&15) 149 u32 packet_size; // 14: Size of packet in bytes. 150 u32 filter_age; // 15: Age since filter installed in seconds. 151 } named; 152 u32 slot[MEMORY_ITEMS]; 153 } memory_type; 154 155 /* ---------------------------------------------------------------------------------------------- */ 156 157 // Standard opcodes. 158 159 /* Unconditionally pass (if R=0) or drop (if R=1) packet and optionally increment counter. 160 * An optional non-zero unsigned immediate value can be provided to encode the counter number. 161 * The counter is located (-4 * counter number) bytes from the end of the data region. 162 * It is a U32 big-endian value and is always incremented by 1. 163 * This is more or less equivalent to: lddw R0, -4*N; add R0, 1; stdw R0, -4*N; {pass,drop} 164 * e.g. "pass", "pass 1", "drop", "drop 1" 165 */ 166 #define PASSDROP_OPCODE 0 167 168 #define LDB_OPCODE 1 // Load 1 byte from immediate offset, e.g. "ldb R0, [5]" 169 #define LDH_OPCODE 2 // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]" 170 #define LDW_OPCODE 3 // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]" 171 #define LDBX_OPCODE 4 // Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5+R0]" 172 #define LDHX_OPCODE 5 // Load 2 bytes from immediate offset plus register, e.g. "ldhx R0, [5+R0]" 173 #define LDWX_OPCODE 6 // Load 4 bytes from immediate offset plus register, e.g. "ldwx R0, [5+R0]" 174 #define ADD_OPCODE 7 // Add, e.g. "add R0,5" 175 #define MUL_OPCODE 8 // Multiply, e.g. "mul R0,5" 176 #define DIV_OPCODE 9 // Divide, e.g. "div R0,5" 177 #define AND_OPCODE 10 // And, e.g. "and R0,5" 178 #define OR_OPCODE 11 // Or, e.g. "or R0,5" 179 #define SH_OPCODE 12 // Left shift, e.g. "sh R0, 5" or "sh R0, -5" (shifts right) 180 #define LI_OPCODE 13 // Load signed immediate, e.g. "li R0,5" 181 #define JMP_OPCODE 14 // Unconditional jump, e.g. "jmp label" 182 #define JEQ_OPCODE 15 // Compare equal and branch, e.g. "jeq R0,5,label" 183 #define JNE_OPCODE 16 // Compare not equal and branch, e.g. "jne R0,5,label" 184 #define JGT_OPCODE 17 // Compare greater than and branch, e.g. "jgt R0,5,label" 185 #define JLT_OPCODE 18 // Compare less than and branch, e.g. "jlt R0,5,label" 186 #define JSET_OPCODE 19 // Compare any bits set and branch, e.g. "jset R0,5,label" 187 #define JBSMATCH_OPCODE 20 // Compare byte sequence [R=0 not] equal, e.g. "jbsne R0,2,label,0x1122" 188 // NOTE: Only APFv6+ implements R=1 'jbseq' version and multi match 189 // imm1 is jmp target, imm2 is (cnt - 1) * 2048 + compare_len, 190 // which is followed by cnt * compare_len bytes to compare against. 191 // Warning: do not specify the same byte sequence multiple times. 192 #define EXT_OPCODE 21 // Immediate value is one of *_EXT_OPCODE 193 #define LDDW_OPCODE 22 // Load 4 bytes from data address (register + signed imm): "lddw R0, [5+R1]" 194 // LDDW/STDW in APFv6+ *mode* load/store from counter specified in imm. 195 #define STDW_OPCODE 23 // Store 4 bytes to data address (register + signed imm): "stdw R0, [5+R1]" 196 197 /* Write 1, 2 or 4 byte immediate to the output buffer and auto-increment the output buffer pointer. 198 * Immediate length field specifies size of write. R must be 0. imm_len != 0. 199 * e.g. "write 5" 200 */ 201 #define WRITE_OPCODE 24 202 203 /* Copy bytes from input packet/APF program/data region to output buffer and 204 * auto-increment the output buffer pointer. 205 * Register bit is used to specify the source of data copy. 206 * R=0 means copy from packet. 207 * R=1 means copy from APF program/data region. 208 * The source offset is stored in imm1, copy length is stored in u8 imm2. 209 * e.g. "pktcopy 0, 16" or "datacopy 0, 16" 210 */ 211 #define PKTDATACOPY_OPCODE 25 212 213 #define JNSET_OPCODE 26 // JSET with reverse condition (jump if no bits set) 214 215 /* ---------------------------------------------------------------------------------------------- */ 216 217 // Extended opcodes. 218 // These all have an opcode of EXT_OPCODE and specify the actual opcode in the immediate field. 219 220 #define LDM_EXT_OPCODE 0 // Load from temporary memory, e.g. "ldm R0,5" 221 // Values 0-15 represent loading the different temporary memory slots. 222 #define STM_EXT_OPCODE 16 // Store to temporary memory, e.g. "stm R0,5" 223 // Values 16-31 represent storing to the different temporary memory slots. 224 #define NOT_EXT_OPCODE 32 // Not, e.g. "not R0" 225 #define NEG_EXT_OPCODE 33 // Negate, e.g. "neg R0" 226 #define SWAP_EXT_OPCODE 34 // Swap, e.g. "swap R0,R1" 227 #define MOV_EXT_OPCODE 35 // Move, e.g. "move R0,R1" 228 229 /* Allocate writable output buffer. 230 * R=0: register R0 specifies the length 231 * R=1: length provided in u16 imm2 232 * e.g. "allocate R0" or "allocate 123" 233 * On failure automatically executes 'pass 3' 234 */ 235 #define ALLOCATE_EXT_OPCODE 36 236 /* Transmit and deallocate the buffer (transmission can be delayed until the program 237 * terminates). Length of buffer is the output buffer pointer (0 means discard). 238 * R=1 iff udp style L4 checksum 239 * u8 imm2 - ip header offset from start of buffer (255 for non-ip packets) 240 * u8 imm3 - offset from start of buffer to store L4 checksum (255 for no L4 checksum) 241 * u8 imm4 - offset from start of buffer to begin L4 checksum calculation (present iff imm3 != 255) 242 * u16 imm5 - partial checksum value to include in L4 checksum (present iff imm3 != 255) 243 * "e.g. transmit" 244 */ 245 #define TRANSMIT_EXT_OPCODE 37 246 /* Write 1, 2 or 4 byte value from register to the output buffer and auto-increment the 247 * output buffer pointer. 248 * e.g. "ewrite1 r0" or "ewrite2 r1" 249 */ 250 #define EWRITE1_EXT_OPCODE 38 251 #define EWRITE2_EXT_OPCODE 39 252 #define EWRITE4_EXT_OPCODE 40 253 254 /* Copy bytes from input packet/APF program/data region to output buffer and 255 * auto-increment the output buffer pointer. 256 * Register bit is used to specify the source of data copy. 257 * R=0 means copy from packet. 258 * R=1 means copy from APF program/data region. 259 * The source offset is stored in R0, copy length is stored in u8 imm2 or R1. 260 * e.g. "epktcopy r0, 16", "edatacopy r0, 16", "epktcopy r0, r1", "edatacopy r0, r1" 261 */ 262 #define EPKTDATACOPYIMM_EXT_OPCODE 41 263 #define EPKTDATACOPYR1_EXT_OPCODE 42 264 /* Jumps if the UDP payload content (starting at R0) does [not] match one 265 * of the specified QNAMEs in question records, applying case insensitivity. 266 * SAFE version PASSES corrupt packets, while the other one DROPS. 267 * R=0/1 meaning 'does not match'/'matches' 268 * R0: Offset to UDP payload content 269 * imm1: Extended opcode 270 * imm2: Jump label offset 271 * imm3(u8): Question type (PTR/SRV/TXT/A/AAAA) 272 * imm4(bytes): null terminated list of null terminated LV-encoded QNAMEs 273 * e.g.: "jdnsqeq R0,label,0xc,\002aa\005local\0\0", "jdnsqne R0,label,0xc,\002aa\005local\0\0" 274 */ 275 #define JDNSQMATCH_EXT_OPCODE 43 276 #define JDNSQMATCHSAFE_EXT_OPCODE 45 277 /* Jumps if the UDP payload content (starting at R0) does [not] match one 278 * of the specified NAMEs in answers/authority/additional records, applying 279 * case insensitivity. 280 * SAFE version PASSES corrupt packets, while the other one DROPS. 281 * R=0/1 meaning 'does not match'/'matches' 282 * R0: Offset to UDP payload content 283 * imm1: Extended opcode 284 * imm2: Jump label offset 285 * imm3(bytes): null terminated list of null terminated LV-encoded NAMEs 286 * e.g.: "jdnsaeq R0,label,0xc,\002aa\005local\0\0", "jdnsane R0,label,0xc,\002aa\005local\0\0" 287 */ 288 #define JDNSAMATCH_EXT_OPCODE 44 289 #define JDNSAMATCHSAFE_EXT_OPCODE 46 290 291 /* Jump if register is [not] one of the list of values 292 * R bit - specifies the register (R0/R1) to test 293 * imm1: Extended opcode 294 * imm2: Jump label offset 295 * imm3(u8): top 5 bits - number 'n' of following u8/be16/be32 values - 2 296 * middle 2 bits - 1..4 length of immediates - 1 297 * bottom 1 bit - =0 jmp if in set, =1 if not in set 298 * imm4(n * 1/2/3/4 bytes): the *UNIQUE* values to compare against 299 */ 300 #define JONEOF_EXT_OPCODE 47 301 302 /* Specify length of exception buffer, which is populated on abnormal program termination. 303 * imm1: Extended opcode 304 * imm2(u16): Length of exception buffer (located *immediately* after the program itself) 305 */ 306 #define EXCEPTIONBUFFER_EXT_OPCODE 48 307 308 // This extended opcode is used to implement PKTDATACOPY_OPCODE 309 #define PKTDATACOPYIMM_EXT_OPCODE 65536 310 311 #define EXTRACT_OPCODE(i) (((i) >> 3) & 31) 312 #define EXTRACT_REGISTER(i) ((i) & 1) 313 #define EXTRACT_IMM_LENGTH(i) (((i) >> 1) & 3) 314 315 #endif // ANDROID_APF_APF_H 316