Updated EWRITE opcode logic to reflect latest design.
* design doc: go/apf-v6-proposal
Bug: 293811969
Test: TH
Change-Id: I0ed11f5397232a2656559b4b515fe70915619f2f
diff --git a/src/android/net/apf/ApfGenerator.java b/src/android/net/apf/ApfGenerator.java
index ee09e2c..80832a6 100644
--- a/src/android/net/apf/ApfGenerator.java
+++ b/src/android/net/apf/ApfGenerator.java
@@ -119,9 +119,12 @@
// "e.g. discard"
TRANSMIT(37),
DISCARD(37),
- EWRITE1(38), // Write 1 byte from register to the output buffer, e.g. "EWRITE1 R0"
- EWRITE2(39), // Write 2 bytes from register to the output buffer, e.g. "EWRITE2 R0"
- EWRITE4(40), // Write 4 bytes from register to the output buffer, e.g. "EWRITE4 R0"
+ // Write 1, 2 or 4 byte value from register to the output buffer and auto-increment the
+ // output buffer pointer.
+ // e.g. "ewrite1 r0"
+ EWRITE1(38),
+ EWRITE2(39),
+ EWRITE4(40),
// Copy the data from input packet to output buffer. The source offset is encoded as [Rx
// + second imm]. The copy length is encoded in the third imm. "e.g. EPKTCOPY [R0 + 5], 5"
EPKTCOPY(41),
@@ -1065,34 +1068,32 @@
return append(new Instruction(Opcodes.WRITE).overrideLenField(4).addU32(val));
}
- // TODO: add back when support EWRITE opcode
-// /**
-// * Add an instruction to the end of the program to write 1, 2 or 4 bytes value from register
-// * to output buffer.
-// *
-// * @param register the register contains the value to be written
-// * @param size the size of the value
-// * @return the ApfGenerator object
-// * @throws IllegalInstructionException throws when size is not 1, 2 or 4
-// */
-// public ApfGenerator addWrite(Register register, byte size)
-// throws IllegalInstructionException {
-// requireApfVersion(5);
-// if (!(size == 1 || size == 2 || size == 4)) {
-// throw new IllegalInstructionException(
-// "length field must be 1, 2 or 4");
-// }
-// Instruction instruction = new Instruction(Opcodes.EXT, register);
-// if (size == 1) {
-// instruction.addUnsignedImm(ExtendedOpcodes.EWRITE1.value);
-// } else if (size == 2) {
-// instruction.addUnsignedImm(ExtendedOpcodes.EWRITE2.value);
-// } else {
-// instruction.addUnsignedImm(ExtendedOpcodes.EWRITE4.value);
-// }
-// addInstruction(instruction);
-// return this;
-// }
+ /**
+ * Add an instruction to the end of the program to write 1 byte value from register to output
+ * buffer.
+ */
+ public ApfGenerator addWriteU8(Register reg) throws IllegalInstructionException {
+ requireApfVersion(MIN_APF_VERSION_IN_DEV);
+ return append(new Instruction(ExtendedOpcodes.EWRITE1, reg));
+ }
+
+ /**
+ * Add an instruction to the end of the program to write 2 byte value from register to output
+ * buffer.
+ */
+ public ApfGenerator addWriteU16(Register reg) throws IllegalInstructionException {
+ requireApfVersion(MIN_APF_VERSION_IN_DEV);
+ return append(new Instruction(ExtendedOpcodes.EWRITE2, reg));
+ }
+
+ /**
+ * Add an instruction to the end of the program to write 4 byte value from register to output
+ * buffer.
+ */
+ public ApfGenerator addWriteU32(Register reg) throws IllegalInstructionException {
+ requireApfVersion(MIN_APF_VERSION_IN_DEV);
+ return append(new Instruction(ExtendedOpcodes.EWRITE4, reg));
+ }
/**
* Add an instruction to the end of the program to copy data from APF program/data region to
diff --git a/tests/unit/src/android/net/apf/ApfV5Test.kt b/tests/unit/src/android/net/apf/ApfV5Test.kt
index 318c243..e64c866 100644
--- a/tests/unit/src/android/net/apf/ApfV5Test.kt
+++ b/tests/unit/src/android/net/apf/ApfV5Test.kt
@@ -16,6 +16,8 @@
package android.net.apf
import android.net.apf.ApfGenerator.IllegalInstructionException
+import android.net.apf.ApfGenerator.Register.R0
+import android.net.apf.ApfGenerator.Register.R1
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import java.lang.IllegalArgumentException
@@ -47,6 +49,12 @@
assertFailsWith<IllegalInstructionException> { gen.addWrite4(100) }
assertFailsWith<IllegalInstructionException> { gen.addPacketCopy(100, 100) }
assertFailsWith<IllegalInstructionException> { gen.addDataCopy(100, 100) }
+ assertFailsWith<IllegalInstructionException> { gen.addWriteU8(R0) }
+ assertFailsWith<IllegalInstructionException> { gen.addWriteU16(R0) }
+ assertFailsWith<IllegalInstructionException> { gen.addWriteU32(R0) }
+ assertFailsWith<IllegalInstructionException> { gen.addWriteU8(R1) }
+ assertFailsWith<IllegalInstructionException> { gen.addWriteU16(R1) }
+ assertFailsWith<IllegalInstructionException> { gen.addWriteU32(R1) }
}
@Test
@@ -171,21 +179,31 @@
" 20: write 0x00000000",
" 25: write 0x80000000"),
ApfJniUtils.disassembleApf(program))
- // TODO: add back the following test case when implementing EWRITE opcodes.
-// gen = ApfGenerator(ApfGenerator.MIN_APF_VERSION_IN_DEV)
-// gen.addWrite(ApfGenerator.Register.R0, 1)
-// gen.addWrite(ApfGenerator.Register.R0, 2)
-// gen.addWrite(ApfGenerator.Register.R0, 4)
-// program = gen.generate()
-// assertContentEquals(byteArrayOf(
-// encodeInstruction(21, 1, 0), 38,
-// encodeInstruction(21, 1, 0), 39,
-// encodeInstruction(21, 1, 0), 40
-// ), program)
+
+ gen = ApfGenerator(ApfGenerator.MIN_APF_VERSION_IN_DEV)
+ gen.addWriteU8(R0)
+ gen.addWriteU16(R0)
+ gen.addWriteU32(R0)
+ gen.addWriteU8(R1)
+ gen.addWriteU16(R1)
+ gen.addWriteU32(R1)
+ program = gen.generate()
+ assertContentEquals(byteArrayOf(
+ encodeInstruction(21, 1, 0), 38,
+ encodeInstruction(21, 1, 0), 39,
+ encodeInstruction(21, 1, 0), 40,
+ encodeInstruction(21, 1, 1), 38,
+ encodeInstruction(21, 1, 1), 39,
+ encodeInstruction(21, 1, 1), 40
+ ), program)
+ // TODO: add back disassembling test check after we update the apf_disassembler
// assertContentEquals(arrayOf(
-// " 0: write r0, 1",
-// " 2: write r0, 2",
-// " 4: write r0, 4"), ApfJniUtils.disassembleApf(program))
+// " 0: ewrite1 r0",
+// " 2: ewrite2 r0",
+// " 4: ewrite4 r0",
+// " 6: ewrite1 r1",
+// " 8: ewrite2 r1",
+// " 10: ewrite4 r1"), ApfJniUtils.disassembleApf(program))
gen = ApfGenerator(ApfGenerator.MIN_APF_VERSION_IN_DEV)
gen.addDataCopy(0, 10)