Home | History | Annotate | Download | only in apf
      1 /*
      2  * Copyright 2018, 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 // 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
     53 //    the byte offset from the beginning of the packet to load from.
     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 //
     85 //  Pre-filled temporary memory slot values
     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:
     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).
     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
     99 //               seconds since the AP sent the program to the chipset. This may
    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 
    124 // Number of temporary memory slots, see ldm/stm instructions.
    125 #define MEMORY_ITEMS 16
    126 // Upon program execution, some temporary memory slots are prefilled:
    127 #define MEMORY_OFFSET_PROGRAM_SIZE 11     // Size of program (in bytes)
    128 #define MEMORY_OFFSET_DATA_SIZE 12        // Total size of program + data
    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]"
    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]"
    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)
    146 #define LI_OPCODE 13    // Load signed immediate, e.g. "li R0,5"
    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
    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]"
    157 
    158 // Extended opcodes. These all have an opcode of EXT_OPCODE
    159 // and specify the actual opcode in the immediate field.
    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.
    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)
    172 
    173 #endif  // ANDROID_APF_APF_H
    174