1*0910d0bcSMike Partington #include <common.h> 21bc15386SPeter Tyser #include <exports.h> 31bc15386SPeter Tyser 41bc15386SPeter Tyser #ifndef GCC_VERSION 51bc15386SPeter Tyser #define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) 61bc15386SPeter Tyser #endif /* GCC_VERSION */ 71bc15386SPeter Tyser 8fea25720SGraeme Russ #if defined(CONFIG_X86) 91bc15386SPeter Tyser /* 101bc15386SPeter Tyser * x86 does not have a dedicated register to store the pointer to 111bc15386SPeter Tyser * the global_data. Thus the jump table address is stored in a 121bc15386SPeter Tyser * global variable, but such approach does not allow for execution 131bc15386SPeter Tyser * from flash memory. The global_data address is passed as argv[-1] 141bc15386SPeter Tyser * to the application program. 151bc15386SPeter Tyser */ 161bc15386SPeter Tyser static void **jt; 171bc15386SPeter Tyser gd_t *global_data; 181bc15386SPeter Tyser 191bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 201bc15386SPeter Tyser asm volatile ( \ 211bc15386SPeter Tyser " .globl " #x "\n" \ 221bc15386SPeter Tyser #x ":\n" \ 231bc15386SPeter Tyser " movl %0, %%eax\n" \ 241bc15386SPeter Tyser " movl jt, %%ecx\n" \ 251bc15386SPeter Tyser " jmp *(%%ecx, %%eax)\n" \ 261bc15386SPeter Tyser : : "i"(XF_ ## x * sizeof(void *)) : "eax", "ecx"); 271bc15386SPeter Tyser #elif defined(CONFIG_PPC) 281bc15386SPeter Tyser /* 291bc15386SPeter Tyser * r2 holds the pointer to the global_data, r11 is a call-clobbered 301bc15386SPeter Tyser * register 311bc15386SPeter Tyser */ 321bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 331bc15386SPeter Tyser asm volatile ( \ 341bc15386SPeter Tyser " .globl " #x "\n" \ 351bc15386SPeter Tyser #x ":\n" \ 361bc15386SPeter Tyser " lwz %%r11, %0(%%r2)\n" \ 371bc15386SPeter Tyser " lwz %%r11, %1(%%r11)\n" \ 381bc15386SPeter Tyser " mtctr %%r11\n" \ 391bc15386SPeter Tyser " bctr\n" \ 401bc15386SPeter Tyser : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r11"); 411bc15386SPeter Tyser #elif defined(CONFIG_ARM) 421bc15386SPeter Tyser /* 431bc15386SPeter Tyser * r8 holds the pointer to the global_data, ip is a call-clobbered 441bc15386SPeter Tyser * register 451bc15386SPeter Tyser */ 461bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 471bc15386SPeter Tyser asm volatile ( \ 481bc15386SPeter Tyser " .globl " #x "\n" \ 491bc15386SPeter Tyser #x ":\n" \ 501bc15386SPeter Tyser " ldr ip, [r8, %0]\n" \ 511bc15386SPeter Tyser " ldr pc, [ip, %1]\n" \ 521bc15386SPeter Tyser : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "ip"); 531bc15386SPeter Tyser #elif defined(CONFIG_MIPS) 541bc15386SPeter Tyser /* 551bc15386SPeter Tyser * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call- 561bc15386SPeter Tyser * clobbered register that is also used to set gp ($26). Note that the 571bc15386SPeter Tyser * jr instruction also executes the instruction immediately following 581bc15386SPeter Tyser * it; however, GCC/mips generates an additional `nop' after each asm 591bc15386SPeter Tyser * statement 601bc15386SPeter Tyser */ 611bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 621bc15386SPeter Tyser asm volatile ( \ 631bc15386SPeter Tyser " .globl " #x "\n" \ 641bc15386SPeter Tyser #x ":\n" \ 651bc15386SPeter Tyser " lw $25, %0($26)\n" \ 661bc15386SPeter Tyser " lw $25, %1($25)\n" \ 671bc15386SPeter Tyser " jr $25\n" \ 681bc15386SPeter Tyser : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "t9"); 691bc15386SPeter Tyser #elif defined(CONFIG_NIOS2) 701bc15386SPeter Tyser /* 710df01fd3SThomas Chou * gp holds the pointer to the global_data, r8 is call-clobbered 721bc15386SPeter Tyser */ 731bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 741bc15386SPeter Tyser asm volatile ( \ 751bc15386SPeter Tyser " .globl " #x "\n" \ 761bc15386SPeter Tyser #x ":\n" \ 771bc15386SPeter Tyser " movhi r8, %%hi(%0)\n" \ 781bc15386SPeter Tyser " ori r8, r0, %%lo(%0)\n" \ 790df01fd3SThomas Chou " add r8, r8, gp\n" \ 801bc15386SPeter Tyser " ldw r8, 0(r8)\n" \ 811bc15386SPeter Tyser " ldw r8, %1(r8)\n" \ 821bc15386SPeter Tyser " jmp r8\n" \ 830df01fd3SThomas Chou : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "gp"); 841bc15386SPeter Tyser #elif defined(CONFIG_M68K) 851bc15386SPeter Tyser /* 861bc15386SPeter Tyser * d7 holds the pointer to the global_data, a0 is a call-clobbered 871bc15386SPeter Tyser * register 881bc15386SPeter Tyser */ 891bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 901bc15386SPeter Tyser asm volatile ( \ 911bc15386SPeter Tyser " .globl " #x "\n" \ 921bc15386SPeter Tyser #x ":\n" \ 931bc15386SPeter Tyser " move.l %%d7, %%a0\n" \ 941bc15386SPeter Tyser " adda.l %0, %%a0\n" \ 951bc15386SPeter Tyser " move.l (%%a0), %%a0\n" \ 961bc15386SPeter Tyser " adda.l %1, %%a0\n" \ 971bc15386SPeter Tyser " move.l (%%a0), %%a0\n" \ 981bc15386SPeter Tyser " jmp (%%a0)\n" \ 991bc15386SPeter Tyser : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "a0"); 1001bc15386SPeter Tyser #elif defined(CONFIG_MICROBLAZE) 1011bc15386SPeter Tyser /* 1021bc15386SPeter Tyser * r31 holds the pointer to the global_data. r5 is a call-clobbered. 1031bc15386SPeter Tyser */ 1041bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 1051bc15386SPeter Tyser asm volatile ( \ 1061bc15386SPeter Tyser " .globl " #x "\n" \ 1071bc15386SPeter Tyser #x ":\n" \ 1081bc15386SPeter Tyser " lwi r5, r31, %0\n" \ 1091bc15386SPeter Tyser " lwi r5, r5, %1\n" \ 1101bc15386SPeter Tyser " bra r5\n" \ 1111bc15386SPeter Tyser : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r5"); 1121bc15386SPeter Tyser #elif defined(CONFIG_BLACKFIN) 1131bc15386SPeter Tyser /* 114c4db335cSRobin Getz * P3 holds the pointer to the global_data, P0 is a call-clobbered 1151bc15386SPeter Tyser * register 1161bc15386SPeter Tyser */ 1171bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 1181bc15386SPeter Tyser asm volatile ( \ 1191bc15386SPeter Tyser " .globl _" #x "\n_" \ 1201bc15386SPeter Tyser #x ":\n" \ 121c4db335cSRobin Getz " P0 = [P3 + %0]\n" \ 1221bc15386SPeter Tyser " P0 = [P0 + %1]\n" \ 1231bc15386SPeter Tyser " JUMP (P0)\n" \ 1241bc15386SPeter Tyser : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "P0"); 1251bc15386SPeter Tyser #elif defined(CONFIG_AVR32) 1261bc15386SPeter Tyser /* 1271bc15386SPeter Tyser * r6 holds the pointer to the global_data. r8 is call clobbered. 1281bc15386SPeter Tyser */ 1291bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 1301bc15386SPeter Tyser asm volatile( \ 1311bc15386SPeter Tyser " .globl\t" #x "\n" \ 1321bc15386SPeter Tyser #x ":\n" \ 1331bc15386SPeter Tyser " ld.w r8, r6[%0]\n" \ 1341bc15386SPeter Tyser " ld.w pc, r8[%1]\n" \ 1351bc15386SPeter Tyser : \ 1361bc15386SPeter Tyser : "i"(offsetof(gd_t, jt)), "i"(XF_ ##x) \ 1371bc15386SPeter Tyser : "r8"); 1381bc15386SPeter Tyser #elif defined(CONFIG_SH) 1391bc15386SPeter Tyser /* 1401bc15386SPeter Tyser * r13 holds the pointer to the global_data. r1 is a call clobbered. 1411bc15386SPeter Tyser */ 1421bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 1431bc15386SPeter Tyser asm volatile ( \ 1441bc15386SPeter Tyser " .align 2\n" \ 1451bc15386SPeter Tyser " .globl " #x "\n" \ 1461bc15386SPeter Tyser #x ":\n" \ 1471bc15386SPeter Tyser " mov r13, r1\n" \ 1481bc15386SPeter Tyser " add %0, r1\n" \ 1491bc15386SPeter Tyser " mov.l @r1, r2\n" \ 1501bc15386SPeter Tyser " add %1, r2\n" \ 1511bc15386SPeter Tyser " mov.l @r2, r1\n" \ 1521bc15386SPeter Tyser " jmp @r1\n" \ 1531bc15386SPeter Tyser " nop\n" \ 1541bc15386SPeter Tyser " nop\n" \ 1551bc15386SPeter Tyser : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r1", "r2"); 1561bc15386SPeter Tyser #elif defined(CONFIG_SPARC) 1571bc15386SPeter Tyser /* 1581bc15386SPeter Tyser * g7 holds the pointer to the global_data. g1 is call clobbered. 1591bc15386SPeter Tyser */ 1601bc15386SPeter Tyser #define EXPORT_FUNC(x) \ 1611bc15386SPeter Tyser asm volatile( \ 1621bc15386SPeter Tyser " .globl\t" #x "\n" \ 1631bc15386SPeter Tyser #x ":\n" \ 1641bc15386SPeter Tyser " set %0, %%g1\n" \ 1651bc15386SPeter Tyser " or %%g1, %%g7, %%g1\n" \ 1661bc15386SPeter Tyser " ld [%%g1], %%g1\n" \ 1671bc15386SPeter Tyser " ld [%%g1 + %1], %%g1\n" \ 1682c0c58b9SSergey Mironov " jmp %%g1\n" \ 1691bc15386SPeter Tyser " nop\n" \ 1702c0c58b9SSergey Mironov : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "g1" ); 17172c73ddeSMacpaul Lin #elif defined(CONFIG_NDS32) 17272c73ddeSMacpaul Lin /* 17372c73ddeSMacpaul Lin * r16 holds the pointer to the global_data. gp is call clobbered. 17472c73ddeSMacpaul Lin * not support reduced register (16 GPR). 17572c73ddeSMacpaul Lin */ 17672c73ddeSMacpaul Lin #define EXPORT_FUNC(x) \ 17772c73ddeSMacpaul Lin asm volatile ( \ 17872c73ddeSMacpaul Lin " .globl " #x "\n" \ 17972c73ddeSMacpaul Lin #x ":\n" \ 18072c73ddeSMacpaul Lin " lwi $r16, [$gp + (%0)]\n" \ 18172c73ddeSMacpaul Lin " lwi $r16, [$r16 + (%1)]\n" \ 18272c73ddeSMacpaul Lin " jr $r16\n" \ 18372c73ddeSMacpaul Lin : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "$r16"); 1841bc15386SPeter Tyser #else 18572c73ddeSMacpaul Lin /*" addi $sp, $sp, -24\n" \ 18672c73ddeSMacpaul Lin " br $r16\n" \*/ 18772c73ddeSMacpaul Lin 1881bc15386SPeter Tyser #error stubs definition missing for this architecture 1891bc15386SPeter Tyser #endif 1901bc15386SPeter Tyser 1911bc15386SPeter Tyser /* This function is necessary to prevent the compiler from 1921bc15386SPeter Tyser * generating prologue/epilogue, preparing stack frame etc. 1931bc15386SPeter Tyser * The stub functions are special, they do not use the stack 1941bc15386SPeter Tyser * frame passed to them, but pass it intact to the actual 1951bc15386SPeter Tyser * implementation. On the other hand, asm() statements with 1961bc15386SPeter Tyser * arguments can be used only inside the functions (gcc limitation) 1971bc15386SPeter Tyser */ 1981bc15386SPeter Tyser #if GCC_VERSION < 3004 1991bc15386SPeter Tyser static 2001bc15386SPeter Tyser #endif /* GCC_VERSION */ 2011bc15386SPeter Tyser void __attribute__((unused)) dummy(void) 2021bc15386SPeter Tyser { 2031bc15386SPeter Tyser #include <_exports.h> 2041bc15386SPeter Tyser } 2051bc15386SPeter Tyser 2067ec830d5SWolfgang Denk extern unsigned long __bss_start, _end; 2071bc15386SPeter Tyser 20854841ab5SWolfgang Denk void app_startup(char * const *argv) 2091bc15386SPeter Tyser { 2101bc15386SPeter Tyser unsigned char * cp = (unsigned char *) &__bss_start; 2111bc15386SPeter Tyser 2121bc15386SPeter Tyser /* Zero out BSS */ 2137ec830d5SWolfgang Denk while (cp < (unsigned char *)&_end) { 2141bc15386SPeter Tyser *cp++ = 0; 2151bc15386SPeter Tyser } 2161bc15386SPeter Tyser 217fea25720SGraeme Russ #if defined(CONFIG_X86) 2181bc15386SPeter Tyser /* x86 does not have a dedicated register for passing global_data */ 2191bc15386SPeter Tyser global_data = (gd_t *)argv[-1]; 2201bc15386SPeter Tyser jt = global_data->jt; 2211bc15386SPeter Tyser #endif 2221bc15386SPeter Tyser } 2231bc15386SPeter Tyser 2241bc15386SPeter Tyser #undef EXPORT_FUNC 225