Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 1 | /* |
Bernie Innocenti | d2cc2b7 | 2018-04-10 22:52:30 +0900 | [diff] [blame] | 2 | * Copyright 2018, The Android Open Source Project |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 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 | |
Bernie Innocenti | d2cc2b7 | 2018-04-10 22:52:30 +0900 | [diff] [blame] | 17 | #ifndef ANDROID_APF_APF_H |
| 18 | #define ANDROID_APF_APF_H |
| 19 | |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 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. |
Bernie Innocenti | ea115f5 | 2018-03-19 17:58:35 +0900 | [diff] [blame] | 25 | // 3. Sixteen 32-bit temporary memory slots (cleared between packets). |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 26 | // 4. A read-only packet. |
| 27 | // The program is executed by the interpreter below and parses the packet |
| 28 | // to determine if the application processor (AP) should be woken up to |
| 29 | // handle the packet or if can be dropped. |
| 30 | // |
| 31 | // APF bytecode description: |
| 32 | // |
| 33 | // The APF interpreter uses big-endian byte order for loads from the packet |
| 34 | // and for storing immediates in instructions. |
| 35 | // |
| 36 | // Each instruction starts with a byte composed of: |
| 37 | // Top 5 bits form "opcode" field, see *_OPCODE defines below. |
| 38 | // Next 2 bits form "size field", which indicate the length of an immediate |
| 39 | // value which follows the first byte. Values in this field: |
| 40 | // 0 => immediate value is 0 and no bytes follow. |
| 41 | // 1 => immediate value is 1 byte big. |
| 42 | // 2 => immediate value is 2 bytes big. |
| 43 | // 3 => immediate value is 4 bytes big. |
| 44 | // Bottom bit forms "register" field, which indicates which register this |
| 45 | // instruction operates on. |
| 46 | // |
| 47 | // There are three main categories of instructions: |
| 48 | // Load instructions |
| 49 | // These instructions load byte(s) of the packet into a register. |
| 50 | // They load either 1, 2 or 4 bytes, as determined by the "opcode" field. |
| 51 | // They load into the register specified by the "register" field. |
| 52 | // The immediate value that follows the first byte of the instruction is |
Bernie Innocenti | ea115f5 | 2018-03-19 17:58:35 +0900 | [diff] [blame] | 53 | // the byte offset from the beginning of the packet to load from. |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 54 | // There are "indexing" loads which add the value in R1 to the byte offset |
| 55 | // to load from. The "opcode" field determines which loads are "indexing". |
| 56 | // Arithmetic instructions |
| 57 | // These instructions perform simple operations, like addition, on register |
| 58 | // values. The result of these instructions is always written into R0. One |
| 59 | // argument of the arithmetic operation is R0's value. The other argument |
| 60 | // of the arithmetic operation is determined by the "register" field: |
| 61 | // If the "register" field is 0 then the immediate value following |
| 62 | // the first byte of the instruction is used as the other argument |
| 63 | // to the arithmetic operation. |
| 64 | // If the "register" field is 1 then R1's value is used as the other |
| 65 | // argument to the arithmetic operation. |
| 66 | // Conditional jump instructions |
| 67 | // These instructions compare register R0's value with another value, and if |
| 68 | // the comparison succeeds, jump (i.e. adjust the program counter). The |
| 69 | // immediate value that follows the first byte of the instruction |
| 70 | // represents the jump target offset, i.e. the value added to the program |
| 71 | // counter if the comparison succeeds. The other value compared is |
| 72 | // determined by the "register" field: |
| 73 | // If the "register" field is 0 then another immediate value |
| 74 | // follows the jump target offset. This immediate value is of the |
| 75 | // same size as the jump target offset, and represents the value |
| 76 | // to compare against. |
| 77 | // If the "register" field is 1 then register R1's value is |
| 78 | // compared against. |
| 79 | // The type of comparison (e.g. equal to, greater than etc) is determined |
| 80 | // by the "opcode" field. The comparison interprets both values being |
| 81 | // compared as unsigned values. |
| 82 | // |
| 83 | // Miscellaneous details: |
| 84 | // |
Bernie Innocenti | ea115f5 | 2018-03-19 17:58:35 +0900 | [diff] [blame] | 85 | // Pre-filled temporary memory slot values |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 86 | // When the APF program begins execution, three of the sixteen memory slots |
| 87 | // are pre-filled by the interpreter with values that may be useful for |
| 88 | // programs: |
Bernie Innocenti | d2cc2b7 | 2018-04-10 22:52:30 +0900 | [diff] [blame] | 89 | // Slot #11 contains the size (in bytes) of the APF program. |
| 90 | // Slot #12 contains the total size of the APF buffer (program + data). |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 91 | // Slot #13 is filled with the IPv4 header length. This value is calculated |
| 92 | // by loading the first byte of the IPv4 header and taking the |
| 93 | // bottom 4 bits and multiplying their value by 4. This value is |
| 94 | // set to zero if the first 4 bits after the link layer header are |
| 95 | // not 4, indicating not IPv4. |
| 96 | // Slot #14 is filled with size of the packet in bytes, including the |
| 97 | // link-layer header if any. |
| 98 | // Slot #15 is filled with the filter age in seconds. This is the number of |
Bernie Innocenti | d2cc2b7 | 2018-04-10 22:52:30 +0900 | [diff] [blame] | 99 | // seconds since the AP sent the program to the chipset. This may |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 100 | // be used by filters that should have a particular lifetime. For |
| 101 | // example, it can be used to rate-limit particular packets to one |
| 102 | // every N seconds. |
| 103 | // Special jump targets: |
| 104 | // When an APF program executes a jump to the byte immediately after the last |
| 105 | // byte of the progam (i.e., one byte past the end of the program), this |
| 106 | // signals the program has completed and determined the packet should be |
| 107 | // passed to the AP. |
| 108 | // When an APF program executes a jump two bytes past the end of the program, |
| 109 | // this signals the program has completed and determined the packet should |
| 110 | // be dropped. |
| 111 | // Jump if byte sequence doesn't match: |
| 112 | // This is a special instruction to facilitate matching long sequences of |
| 113 | // bytes in the packet. Initially it is encoded like a conditional jump |
| 114 | // instruction with two exceptions: |
| 115 | // The first byte of the instruction is always followed by two immediate |
| 116 | // fields: The first immediate field is the jump target offset like other |
| 117 | // conditional jump instructions. The second immediate field specifies the |
| 118 | // number of bytes to compare. |
| 119 | // These two immediate fields are followed by a sequence of bytes. These |
| 120 | // bytes are compared with the bytes in the packet starting from the |
| 121 | // position specified by the value of the register specified by the |
| 122 | // "register" field of the instruction. |
| 123 | |
Bernie Innocenti | ea115f5 | 2018-03-19 17:58:35 +0900 | [diff] [blame] | 124 | // Number of temporary memory slots, see ldm/stm instructions. |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 125 | #define MEMORY_ITEMS 16 |
Bernie Innocenti | ea115f5 | 2018-03-19 17:58:35 +0900 | [diff] [blame] | 126 | // Upon program execution, some temporary memory slots are prefilled: |
Bernie Innocenti | d2cc2b7 | 2018-04-10 22:52:30 +0900 | [diff] [blame] | 127 | #define MEMORY_OFFSET_PROGRAM_SIZE 11 // Size of program (in bytes) |
| 128 | #define MEMORY_OFFSET_DATA_SIZE 12 // Total size of program + data |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 129 | #define MEMORY_OFFSET_IPV4_HEADER_SIZE 13 // 4*([APF_FRAME_HEADER_SIZE]&15) |
| 130 | #define MEMORY_OFFSET_PACKET_SIZE 14 // Size of packet in bytes. |
| 131 | #define MEMORY_OFFSET_FILTER_AGE 15 // Age since filter installed in seconds. |
| 132 | |
| 133 | // Leave 0 opcode unused as it's a good indicator of accidental incorrect execution (e.g. data). |
| 134 | #define LDB_OPCODE 1 // Load 1 byte from immediate offset, e.g. "ldb R0, [5]" |
| 135 | #define LDH_OPCODE 2 // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]" |
| 136 | #define LDW_OPCODE 3 // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]" |
Bernie Innocenti | ea115f5 | 2018-03-19 17:58:35 +0900 | [diff] [blame] | 137 | #define LDBX_OPCODE 4 // Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5+R0]" |
| 138 | #define LDHX_OPCODE 5 // Load 2 byte from immediate offset plus register, e.g. "ldhx R0, [5+R0]" |
| 139 | #define LDWX_OPCODE 6 // Load 4 byte from immediate offset plus register, e.g. "ldwx R0, [5+R0]" |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 140 | #define ADD_OPCODE 7 // Add, e.g. "add R0,5" |
| 141 | #define MUL_OPCODE 8 // Multiply, e.g. "mul R0,5" |
| 142 | #define DIV_OPCODE 9 // Divide, e.g. "div R0,5" |
| 143 | #define AND_OPCODE 10 // And, e.g. "and R0,5" |
| 144 | #define OR_OPCODE 11 // Or, e.g. "or R0,5" |
| 145 | #define SH_OPCODE 12 // Left shift, e.g, "sh R0, 5" or "sh R0, -5" (shifts right) |
Bernie Innocenti | d2cc2b7 | 2018-04-10 22:52:30 +0900 | [diff] [blame] | 146 | #define LI_OPCODE 13 // Load signed immediate, e.g. "li R0,5" |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 147 | #define JMP_OPCODE 14 // Unconditional jump, e.g. "jmp label" |
| 148 | #define JEQ_OPCODE 15 // Compare equal and branch, e.g. "jeq R0,5,label" |
| 149 | #define JNE_OPCODE 16 // Compare not equal and branch, e.g. "jne R0,5,label" |
| 150 | #define JGT_OPCODE 17 // Compare greater than and branch, e.g. "jgt R0,5,label" |
| 151 | #define JLT_OPCODE 18 // Compare less than and branch, e.g. "jlt R0,5,label" |
| 152 | #define JSET_OPCODE 19 // Compare any bits set and branch, e.g. "jset R0,5,label" |
| 153 | #define JNEBS_OPCODE 20 // Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455" |
| 154 | #define EXT_OPCODE 21 // Immediate value is one of *_EXT_OPCODE |
Bernie Innocenti | d2cc2b7 | 2018-04-10 22:52:30 +0900 | [diff] [blame] | 155 | #define LDDW_OPCODE 22 // Load 4 bytes from data address (register + simm): "lddw R0, [5+R1]" |
| 156 | #define STDW_OPCODE 23 // Store 4 bytes to data address (register + simm): "stdw R0, [5+R1]" |
Bernie Innocenti | ea115f5 | 2018-03-19 17:58:35 +0900 | [diff] [blame] | 157 | |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 158 | // Extended opcodes. These all have an opcode of EXT_OPCODE |
| 159 | // and specify the actual opcode in the immediate field. |
Bernie Innocenti | ea115f5 | 2018-03-19 17:58:35 +0900 | [diff] [blame] | 160 | #define LDM_EXT_OPCODE 0 // Load from temporary memory, e.g. "ldm R0,5" |
| 161 | // Values 0-15 represent loading the different temporary memory slots. |
| 162 | #define STM_EXT_OPCODE 16 // Store to temporary memory, e.g. "stm R0,5" |
| 163 | // Values 16-31 represent storing to the different temporary memory slots. |
Paul Jensen | 497d4ee | 2016-05-09 10:47:56 -0400 | [diff] [blame] | 164 | #define NOT_EXT_OPCODE 32 // Not, e.g. "not R0" |
| 165 | #define NEG_EXT_OPCODE 33 // Negate, e.g. "neg R0" |
| 166 | #define SWAP_EXT_OPCODE 34 // Swap, e.g. "swap R0,R1" |
| 167 | #define MOV_EXT_OPCODE 35 // Move, e.g. "move R0,R1" |
| 168 | |
| 169 | #define EXTRACT_OPCODE(i) (((i) >> 3) & 31) |
| 170 | #define EXTRACT_REGISTER(i) ((i) & 1) |
| 171 | #define EXTRACT_IMM_LENGTH(i) (((i) >> 1) & 3) |
Bernie Innocenti | d2cc2b7 | 2018-04-10 22:52:30 +0900 | [diff] [blame] | 172 | |
| 173 | #endif // ANDROID_APF_APF_H |