Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/linux-sunxi/sunxi-tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/fel.c
diff options
context:
space:
mode:
authorSiarhei Siamashka <siarhei.siamashka@gmail.com>2016-05-23 21:25:18 +0300
committerAndre Przywara <osp@andrep.de>2018-07-09 11:16:24 +0300
commit1091f3ac6b0f7e0f4249081a1e9d68f20b3fd01d (patch)
tree38aa532965c9431979ff64fc079d804f7442ddfc /fel.c
parentd0f2fbb8a1d26888c1741099bd37137890ada4a1 (diff)
fel: Support uploading & executing ARM AAPCS functions on the device
This patch adds a wrapper script, which can automatically compile and wrap a small C function, taking care of all the necessary function arguments marshalling. The functions 'aw_fel_remotefunc_prepare/aw_fel_remotefunc_execute' allow using such functions in the sunxi-fel tool to get this code executed remotely on the device. Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com> [Andre: adjust to match upstream changes] Signed-off-by: Andre Przywara <osp@andrep.de>
Diffstat (limited to 'fel.c')
-rw-r--r--fel.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/fel.c b/fel.c
index 148e558..188e1e3 100644
--- a/fel.c
+++ b/fel.c
@@ -243,6 +243,111 @@ void aw_fel_fill(feldev_handle *dev, uint32_t offset, size_t size, unsigned char
}
}
+/*
+ * Upload a function (implemented in native ARM code) to the device and
+ * prepare for executing it. Use a subset of 32-bit ARM AAPCS calling
+ * conventions: all arguments are integer 32-bit values, and an optional
+ * return value is a 32-bit integer too. The function code needs to be
+ * compiled in the ARM mode (Thumb2 is not supported), it also must be
+ * a position independent leaf function (have no calls to anything else)
+ * and have no references to any global variables.
+ *
+ * 'stack_size' - the required stack size for the function (can be
+ * calculated using the '-fstack-usage' GCC option)
+ * 'arm_code' - a pointer to the memory buffer with the function code
+ * 'arm_code_size' - the size of the function code
+ * 'num_args' - the number of 32-bit function arguments
+ * 'args' - an array with the function argument values
+ *
+ * Note: once uploaded, the function can be executed multiple times with
+ * exactly the same arguments. If some internal state needs to be
+ * updated between function calls, then it's best to pass a pointer
+ * to some state structure located elsewhere in SRAM as one of the
+ * function arguments.
+ */
+
+bool aw_fel_remotefunc_prepare(feldev_handle *dev,
+ size_t stack_size,
+ void *arm_code,
+ size_t arm_code_size,
+ size_t num_args,
+ uint32_t *args)
+{
+ size_t idx, i;
+ size_t tmp_buf_size;
+ soc_info_t *soc_info = dev->soc_info;
+ uint32_t *tmp_buf;
+ uint32_t new_sp, num_args_on_stack = (num_args <= 4 ? 0 : num_args - 4);
+ uint32_t entry_code[] = {
+ htole32(0xe58fe040), /* 0: str lr, [pc, #64] */
+ htole32(0xe58fd040), /* 4: str sp, [pc, #64] */
+ htole32(0xe59fd040), /* 8: ldr sp, [pc, #64] */
+ htole32(0xe28fc040), /* c: add ip, pc, #64 */
+ htole32(0xe1a0200d), /* 10: mov r2, sp */
+ htole32(0xe49c0004), /* 14: ldr r0, [ip], #4 */
+ htole32(0xe3500000), /* 18: cmp r0, #0 */
+ htole32(0x0a000003), /* 1c: beq 30 <entry+0x30> */
+ htole32(0xe49c1004), /* 20: ldr r1, [ip], #4 */
+ htole32(0xe4821004), /* 24: str r1, [r2], #4 */
+ htole32(0xe2500001), /* 28: subs r0, r0, #1 */
+ htole32(0x1afffffb), /* 2c: bne 20 <entry+0x20> */
+ htole32(0xe8bc000f), /* 30: ldm ip!, {r0, r1, r2, r3} */
+ htole32(0xe12fff3c), /* 34: blx ip */
+ htole32(0xe59fe008), /* 38: ldr lr, [pc, #8] */
+ htole32(0xe59fd008), /* 3c: ldr sp, [pc, #8] */
+ htole32(0xe58f0000), /* 40: str r0, [pc] */
+ htole32(0xe12fff1e), /* 44: bx lr */
+ htole32(0x00000000), /* 48: .word 0x00000000 */
+ htole32(0x00000000), /* 4c: .word 0x00000000 */
+ };
+
+ if (!soc_info)
+ return false;
+
+ /* Calculate the stack location */
+ new_sp = soc_info->scratch_addr +
+ sizeof(entry_code) +
+ 2 * 4 +
+ num_args_on_stack * 4 +
+ 4 * 4 +
+ arm_code_size +
+ stack_size;
+ new_sp = (new_sp + 7) & ~7;
+
+ tmp_buf_size = new_sp - soc_info->scratch_addr;
+ tmp_buf = calloc(tmp_buf_size, 1);
+ memcpy(tmp_buf, entry_code, sizeof(entry_code));
+ idx = sizeof(entry_code) / 4;
+ tmp_buf[idx++] = htole32(new_sp);
+ tmp_buf[idx++] = htole32(num_args_on_stack);
+ for (i = num_args - num_args_on_stack; i < num_args; i++)
+ tmp_buf[idx++] = htole32(args[i]);
+ for (i = 0; i < 4; i++)
+ tmp_buf[idx++] = (i < num_args ? htole32(args[i]) : 0);
+ memcpy(tmp_buf + idx, arm_code, arm_code_size);
+
+ aw_fel_write(dev, tmp_buf, soc_info->scratch_addr, tmp_buf_size);
+ free(tmp_buf);
+ return true;
+}
+
+/*
+ * Execute the previously uploaded function. The 'result' pointer allows to
+ * retrieve the return value.
+ */
+bool aw_fel_remotefunc_execute(feldev_handle *dev, uint32_t *result)
+{
+ soc_info_t *soc_info = dev->soc_info;
+ if (!soc_info)
+ return false;
+ aw_fel_execute(dev, soc_info->scratch_addr);
+ if (result) {
+ aw_fel_read(dev, soc_info->scratch_addr + 0x48, result, sizeof(uint32_t));
+ *result = le32toh(*result);
+ }
+ return true;
+}
+
static uint32_t fel_to_spl_thunk[] = {
#include "thunks/fel-to-spl-thunk.h"
};