summaryrefslogtreecommitdiffstats
path: root/examples/stubs.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/stubs.c')
-rw-r--r--examples/stubs.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/examples/stubs.c b/examples/stubs.c
new file mode 100644
index 0000000000..c0ef65048e
--- /dev/null
+++ b/examples/stubs.c
@@ -0,0 +1,87 @@
+#include <exports.h>
+
+#if defined(CONFIG_I386)
+/*
+ * x86 does not have a dedicated register to store the pointer to
+ * the global_data. Thus the jump table address is stored in a
+ * global variable, but such approach does not allow for execution
+ * from flash memory. The global_data address is passed as argv[-1]
+ * to the application program.
+ */
+static void **jt;
+
+#define EXPORT_FUNC(x) \
+ asm volatile ( \
+" .globl " #x "\n" \
+#x ":\n" \
+" movl %0, %%eax\n" \
+" movl jt, %%ecx\n" \
+" jmp *(%%ecx, %%eax)\n" \
+ : : "i"(XF_ ## x * sizeof(void *)) : "eax", "ecx");
+#elif defined(CONFIG_PPC)
+/*
+ * r29 holds the pointer to the global_data, r11 is a call-clobbered
+ * register
+ */
+#define EXPORT_FUNC(x) \
+ asm volatile ( \
+" .globl " #x "\n" \
+#x ":\n" \
+" lwz %%r11, %0(%%r29)\n" \
+" lwz %%r11, %1(%%r11)\n" \
+" mtctr %%r11\n" \
+" bctr\n" \
+ : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r11");
+#elif defined(CONFIG_ARM)
+/*
+ * r8 holds the pointer to the global_data, ip is a call-clobbered
+ * register
+ */
+#define EXPORT_FUNC(x) \
+ asm volatile ( \
+" .globl " #x "\n" \
+#x ":\n" \
+" ldr ip, [r8, %0]\n" \
+" ldr pc, [ip, %1]\n" \
+ : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "ip");
+#elif defined(CONFIG_MIPS)
+/*
+ * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call-
+ * clobbered register that is also used to set gp ($26). Note that the
+ * jr instruction also executes the instruction immediately following
+ * it; however, GCC/mips generates an additional `nop' after each asm
+ * statement
+ */
+#define EXPORT_FUNC(x) \
+ asm volatile ( \
+" .globl " #x "\n" \
+#x ":\n" \
+" lw $25, %0($26)\n" \
+" lw $25, %1($25)\n" \
+" jr $25\n" \
+ : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "t9");
+#else
+#error stubs definition missing for this architecture
+#endif
+
+/* This function is necessary to prevent the compiler from
+ * generating prologue/epilogue, preparing stack frame etc.
+ * The stub functions are special, they do not use the stack
+ * frame passed to them, but pass it intact to the actual
+ * implementation. On the other hand, asm() statements with
+ * arguments can be used only inside the functions (gcc limitation)
+ */
+static void __attribute__((unused)) dummy(void)
+{
+#include <_exports.h>
+}
+
+void app_startup(char **argv)
+{
+#if defined(CONFIG_I386)
+ /* x86 does not have a dedicated register for passing global_data */
+ jt = ((gd_t *)argv[-1])->jt;
+#endif
+}
+
+#undef EXPORT_FUNC
OpenPOWER on IntegriCloud