10910d0bcSMike Partington #include <common.h> 21bc15386SPeter Tyser #include <exports.h> 32d5db193SMasahiro Yamada #include <linux/compiler.h> 41bc15386SPeter Tyser 549cad547SMartin Dorwig #define FO(x) offsetof(struct jt_funcs, x) 649cad547SMartin Dorwig 7fea25720SGraeme Russ #if defined(CONFIG_X86) 81bc15386SPeter Tyser /* 91bc15386SPeter Tyser * x86 does not have a dedicated register to store the pointer to 101bc15386SPeter Tyser * the global_data. Thus the jump table address is stored in a 111bc15386SPeter Tyser * global variable, but such approach does not allow for execution 121bc15386SPeter Tyser * from flash memory. The global_data address is passed as argv[-1] 131bc15386SPeter Tyser * to the application program. 141bc15386SPeter Tyser */ 1549cad547SMartin Dorwig static struct jt_funcs *jt; 161bc15386SPeter Tyser gd_t *global_data; 171bc15386SPeter Tyser 1849cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 191bc15386SPeter Tyser asm volatile ( \ 201bc15386SPeter Tyser " .globl " #x "\n" \ 211bc15386SPeter Tyser #x ":\n" \ 221bc15386SPeter Tyser " movl %0, %%eax\n" \ 231bc15386SPeter Tyser " movl jt, %%ecx\n" \ 241bc15386SPeter Tyser " jmp *(%%ecx, %%eax)\n" \ 2549cad547SMartin Dorwig : : "i"(FO(x)) : "eax", "ecx"); 261bc15386SPeter Tyser #elif defined(CONFIG_PPC) 271bc15386SPeter Tyser /* 281bc15386SPeter Tyser * r2 holds the pointer to the global_data, r11 is a call-clobbered 291bc15386SPeter Tyser * register 301bc15386SPeter Tyser */ 3149cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 321bc15386SPeter Tyser asm volatile ( \ 331bc15386SPeter Tyser " .globl " #x "\n" \ 341bc15386SPeter Tyser #x ":\n" \ 351bc15386SPeter Tyser " lwz %%r11, %0(%%r2)\n" \ 361bc15386SPeter Tyser " lwz %%r11, %1(%%r11)\n" \ 371bc15386SPeter Tyser " mtctr %%r11\n" \ 381bc15386SPeter Tyser " bctr\n" \ 3949cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r11"); 401bc15386SPeter Tyser #elif defined(CONFIG_ARM) 410ae76531SDavid Feng #ifdef CONFIG_ARM64 420ae76531SDavid Feng /* 430ae76531SDavid Feng * x18 holds the pointer to the global_data, x9 is a call-clobbered 440ae76531SDavid Feng * register 450ae76531SDavid Feng */ 4649cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 470ae76531SDavid Feng asm volatile ( \ 480ae76531SDavid Feng " .globl " #x "\n" \ 490ae76531SDavid Feng #x ":\n" \ 500ae76531SDavid Feng " ldr x9, [x18, %0]\n" \ 510ae76531SDavid Feng " ldr x9, [x9, %1]\n" \ 520ae76531SDavid Feng " br x9\n" \ 5349cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "x9"); 540ae76531SDavid Feng #else 551bc15386SPeter Tyser /* 56a5a42eecSJeroen Hofstee * r9 holds the pointer to the global_data, ip is a call-clobbered 571bc15386SPeter Tyser * register 581bc15386SPeter Tyser */ 5949cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 601bc15386SPeter Tyser asm volatile ( \ 611bc15386SPeter Tyser " .globl " #x "\n" \ 621bc15386SPeter Tyser #x ":\n" \ 63a5a42eecSJeroen Hofstee " ldr ip, [r9, %0]\n" \ 641bc15386SPeter Tyser " ldr pc, [ip, %1]\n" \ 6549cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "ip"); 660ae76531SDavid Feng #endif 671bc15386SPeter Tyser #elif defined(CONFIG_MIPS) 68*4a48cfc4SStanislav Galabov #ifdef CONFIG_CPU_MIPS64 69*4a48cfc4SStanislav Galabov /* 70*4a48cfc4SStanislav Galabov * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call- 71*4a48cfc4SStanislav Galabov * clobbered register that is also used to set gp ($26). Note that the 72*4a48cfc4SStanislav Galabov * jr instruction also executes the instruction immediately following 73*4a48cfc4SStanislav Galabov * it; however, GCC/mips generates an additional `nop' after each asm 74*4a48cfc4SStanislav Galabov * statement 75*4a48cfc4SStanislav Galabov */ 76*4a48cfc4SStanislav Galabov #define EXPORT_FUNC(f, a, x, ...) \ 77*4a48cfc4SStanislav Galabov asm volatile ( \ 78*4a48cfc4SStanislav Galabov " .globl " #x "\n" \ 79*4a48cfc4SStanislav Galabov #x ":\n" \ 80*4a48cfc4SStanislav Galabov " ld $25, %0($26)\n" \ 81*4a48cfc4SStanislav Galabov " ld $25, %1($25)\n" \ 82*4a48cfc4SStanislav Galabov " jr $25\n" \ 83*4a48cfc4SStanislav Galabov : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "t9"); 84*4a48cfc4SStanislav Galabov #else 851bc15386SPeter Tyser /* 861bc15386SPeter Tyser * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call- 871bc15386SPeter Tyser * clobbered register that is also used to set gp ($26). Note that the 881bc15386SPeter Tyser * jr instruction also executes the instruction immediately following 891bc15386SPeter Tyser * it; however, GCC/mips generates an additional `nop' after each asm 901bc15386SPeter Tyser * statement 911bc15386SPeter Tyser */ 9249cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 931bc15386SPeter Tyser asm volatile ( \ 941bc15386SPeter Tyser " .globl " #x "\n" \ 951bc15386SPeter Tyser #x ":\n" \ 961bc15386SPeter Tyser " lw $25, %0($26)\n" \ 971bc15386SPeter Tyser " lw $25, %1($25)\n" \ 981bc15386SPeter Tyser " jr $25\n" \ 9949cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "t9"); 100*4a48cfc4SStanislav Galabov #endif 1011bc15386SPeter Tyser #elif defined(CONFIG_NIOS2) 1021bc15386SPeter Tyser /* 1030df01fd3SThomas Chou * gp holds the pointer to the global_data, r8 is call-clobbered 1041bc15386SPeter Tyser */ 10549cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 1061bc15386SPeter Tyser asm volatile ( \ 1071bc15386SPeter Tyser " .globl " #x "\n" \ 1081bc15386SPeter Tyser #x ":\n" \ 1091bc15386SPeter Tyser " movhi r8, %%hi(%0)\n" \ 1101bc15386SPeter Tyser " ori r8, r0, %%lo(%0)\n" \ 1110df01fd3SThomas Chou " add r8, r8, gp\n" \ 1121bc15386SPeter Tyser " ldw r8, 0(r8)\n" \ 1131bc15386SPeter Tyser " ldw r8, %1(r8)\n" \ 1141bc15386SPeter Tyser " jmp r8\n" \ 11549cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "gp"); 1161bc15386SPeter Tyser #elif defined(CONFIG_M68K) 1171bc15386SPeter Tyser /* 1181bc15386SPeter Tyser * d7 holds the pointer to the global_data, a0 is a call-clobbered 1191bc15386SPeter Tyser * register 1201bc15386SPeter Tyser */ 12149cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 1221bc15386SPeter Tyser asm volatile ( \ 1231bc15386SPeter Tyser " .globl " #x "\n" \ 1241bc15386SPeter Tyser #x ":\n" \ 1251bc15386SPeter Tyser " move.l %%d7, %%a0\n" \ 1261bc15386SPeter Tyser " adda.l %0, %%a0\n" \ 1271bc15386SPeter Tyser " move.l (%%a0), %%a0\n" \ 1281bc15386SPeter Tyser " adda.l %1, %%a0\n" \ 1291bc15386SPeter Tyser " move.l (%%a0), %%a0\n" \ 1301bc15386SPeter Tyser " jmp (%%a0)\n" \ 13149cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "a0"); 1321bc15386SPeter Tyser #elif defined(CONFIG_MICROBLAZE) 1331bc15386SPeter Tyser /* 1341bc15386SPeter Tyser * r31 holds the pointer to the global_data. r5 is a call-clobbered. 1351bc15386SPeter Tyser */ 13649cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 1371bc15386SPeter Tyser asm volatile ( \ 1381bc15386SPeter Tyser " .globl " #x "\n" \ 1391bc15386SPeter Tyser #x ":\n" \ 1401bc15386SPeter Tyser " lwi r5, r31, %0\n" \ 1411bc15386SPeter Tyser " lwi r5, r5, %1\n" \ 1421bc15386SPeter Tyser " bra r5\n" \ 14349cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r5"); 1441bc15386SPeter Tyser #elif defined(CONFIG_BLACKFIN) 1451bc15386SPeter Tyser /* 146c4db335cSRobin Getz * P3 holds the pointer to the global_data, P0 is a call-clobbered 1471bc15386SPeter Tyser * register 1481bc15386SPeter Tyser */ 14949cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 1501bc15386SPeter Tyser asm volatile ( \ 1511bc15386SPeter Tyser " .globl _" #x "\n_" \ 1521bc15386SPeter Tyser #x ":\n" \ 153c4db335cSRobin Getz " P0 = [P3 + %0]\n" \ 1541bc15386SPeter Tyser " P0 = [P0 + %1]\n" \ 1551bc15386SPeter Tyser " JUMP (P0)\n" \ 15649cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "P0"); 1571bc15386SPeter Tyser #elif defined(CONFIG_AVR32) 1581bc15386SPeter Tyser /* 1591bc15386SPeter Tyser * r6 holds the pointer to the global_data. r8 is call clobbered. 1601bc15386SPeter Tyser */ 16149cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 1621bc15386SPeter Tyser asm volatile( \ 1631bc15386SPeter Tyser " .globl\t" #x "\n" \ 1641bc15386SPeter Tyser #x ":\n" \ 1651bc15386SPeter Tyser " ld.w r8, r6[%0]\n" \ 1661bc15386SPeter Tyser " ld.w pc, r8[%1]\n" \ 1671bc15386SPeter Tyser : \ 16849cad547SMartin Dorwig : "i"(offsetof(gd_t, jt)), "i"(FO(x)) \ 1691bc15386SPeter Tyser : "r8"); 1701bc15386SPeter Tyser #elif defined(CONFIG_SH) 1711bc15386SPeter Tyser /* 1721bc15386SPeter Tyser * r13 holds the pointer to the global_data. r1 is a call clobbered. 1731bc15386SPeter Tyser */ 17449cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 1751bc15386SPeter Tyser asm volatile ( \ 1761bc15386SPeter Tyser " .align 2\n" \ 1771bc15386SPeter Tyser " .globl " #x "\n" \ 1781bc15386SPeter Tyser #x ":\n" \ 1791bc15386SPeter Tyser " mov r13, r1\n" \ 1801bc15386SPeter Tyser " add %0, r1\n" \ 1811bc15386SPeter Tyser " mov.l @r1, r2\n" \ 1821bc15386SPeter Tyser " add %1, r2\n" \ 1831bc15386SPeter Tyser " mov.l @r2, r1\n" \ 1841bc15386SPeter Tyser " jmp @r1\n" \ 1851bc15386SPeter Tyser " nop\n" \ 1861bc15386SPeter Tyser " nop\n" \ 18749cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r1", "r2"); 1881bc15386SPeter Tyser #elif defined(CONFIG_SPARC) 1891bc15386SPeter Tyser /* 1901bc15386SPeter Tyser * g7 holds the pointer to the global_data. g1 is call clobbered. 1911bc15386SPeter Tyser */ 19249cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 1931bc15386SPeter Tyser asm volatile( \ 1941bc15386SPeter Tyser " .globl\t" #x "\n" \ 1951bc15386SPeter Tyser #x ":\n" \ 1961bc15386SPeter Tyser " set %0, %%g1\n" \ 1971bc15386SPeter Tyser " or %%g1, %%g7, %%g1\n" \ 1981bc15386SPeter Tyser " ld [%%g1], %%g1\n" \ 1991bc15386SPeter Tyser " ld [%%g1 + %1], %%g1\n" \ 2002c0c58b9SSergey Mironov " jmp %%g1\n" \ 2011bc15386SPeter Tyser " nop\n" \ 20249cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "g1"); 20372c73ddeSMacpaul Lin #elif defined(CONFIG_NDS32) 20472c73ddeSMacpaul Lin /* 20572c73ddeSMacpaul Lin * r16 holds the pointer to the global_data. gp is call clobbered. 20672c73ddeSMacpaul Lin * not support reduced register (16 GPR). 20772c73ddeSMacpaul Lin */ 20849cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 20972c73ddeSMacpaul Lin asm volatile ( \ 21072c73ddeSMacpaul Lin " .globl " #x "\n" \ 21172c73ddeSMacpaul Lin #x ":\n" \ 21272c73ddeSMacpaul Lin " lwi $r16, [$gp + (%0)]\n" \ 21372c73ddeSMacpaul Lin " lwi $r16, [$r16 + (%1)]\n" \ 21472c73ddeSMacpaul Lin " jr $r16\n" \ 21549cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "$r16"); 2163553493dSStefan Kristiansson #elif defined(CONFIG_OPENRISC) 2173553493dSStefan Kristiansson /* 2183553493dSStefan Kristiansson * r10 holds the pointer to the global_data, r13 is a call-clobbered 2193553493dSStefan Kristiansson * register 2203553493dSStefan Kristiansson */ 22149cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 2223553493dSStefan Kristiansson asm volatile ( \ 2233553493dSStefan Kristiansson " .globl " #x "\n" \ 2243553493dSStefan Kristiansson #x ":\n" \ 2253553493dSStefan Kristiansson " l.lwz r13, %0(r10)\n" \ 2263553493dSStefan Kristiansson " l.lwz r13, %1(r13)\n" \ 2273553493dSStefan Kristiansson " l.jr r13\n" \ 2283553493dSStefan Kristiansson " l.nop\n" \ 22949cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r13"); 230794ab574SAlexey Brodkin #elif defined(CONFIG_ARC) 231794ab574SAlexey Brodkin /* 232794ab574SAlexey Brodkin * r25 holds the pointer to the global_data. r10 is call clobbered. 233794ab574SAlexey Brodkin */ 23449cad547SMartin Dorwig #define EXPORT_FUNC(f, a, x, ...) \ 235794ab574SAlexey Brodkin asm volatile( \ 236794ab574SAlexey Brodkin " .align 4\n" \ 237794ab574SAlexey Brodkin " .globl " #x "\n" \ 238794ab574SAlexey Brodkin #x ":\n" \ 239794ab574SAlexey Brodkin " ld r10, [r25, %0]\n" \ 240794ab574SAlexey Brodkin " ld r10, [r10, %1]\n" \ 241794ab574SAlexey Brodkin " j [r10]\n" \ 24249cad547SMartin Dorwig : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r10"); 2431bc15386SPeter Tyser #else 24472c73ddeSMacpaul Lin /*" addi $sp, $sp, -24\n" \ 24572c73ddeSMacpaul Lin " br $r16\n" \*/ 24672c73ddeSMacpaul Lin 2471bc15386SPeter Tyser #error stubs definition missing for this architecture 2481bc15386SPeter Tyser #endif 2491bc15386SPeter Tyser 2501bc15386SPeter Tyser /* This function is necessary to prevent the compiler from 2511bc15386SPeter Tyser * generating prologue/epilogue, preparing stack frame etc. 2521bc15386SPeter Tyser * The stub functions are special, they do not use the stack 2531bc15386SPeter Tyser * frame passed to them, but pass it intact to the actual 2541bc15386SPeter Tyser * implementation. On the other hand, asm() statements with 2551bc15386SPeter Tyser * arguments can be used only inside the functions (gcc limitation) 2561bc15386SPeter Tyser */ 2572d5db193SMasahiro Yamada #if GCC_VERSION < 30400 2581bc15386SPeter Tyser static 2591bc15386SPeter Tyser #endif /* GCC_VERSION */ 2601bc15386SPeter Tyser void __attribute__((unused)) dummy(void) 2611bc15386SPeter Tyser { 2621bc15386SPeter Tyser #include <_exports.h> 2631bc15386SPeter Tyser } 2641bc15386SPeter Tyser 265716cc8ccSSimon Glass #include <asm/sections.h> 2661bc15386SPeter Tyser 26754841ab5SWolfgang Denk void app_startup(char * const *argv) 2681bc15386SPeter Tyser { 269716cc8ccSSimon Glass char *cp = __bss_start; 2701bc15386SPeter Tyser 2711bc15386SPeter Tyser /* Zero out BSS */ 272716cc8ccSSimon Glass while (cp < _end) 2731bc15386SPeter Tyser *cp++ = 0; 2741bc15386SPeter Tyser 275fea25720SGraeme Russ #if defined(CONFIG_X86) 2761bc15386SPeter Tyser /* x86 does not have a dedicated register for passing global_data */ 2771bc15386SPeter Tyser global_data = (gd_t *)argv[-1]; 2781bc15386SPeter Tyser jt = global_data->jt; 2791bc15386SPeter Tyser #endif 2801bc15386SPeter Tyser } 2811bc15386SPeter Tyser 2821bc15386SPeter Tyser #undef EXPORT_FUNC 283