123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /* Copyright (C) 2010 Texas Instruments Incorporated
- * Contributed by Mark Salter <msalter@redhat.com>
- *
- * Borrowed heavily from frv arch:
- * Copyright (C) 2003 Red Hat, Inc.
- *
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
- #undef DL_START
- #define DL_START(X) \
- static void * __attribute_used__ \
- _dl_start (unsigned placeholder, \
- struct elf32_dsbt_loadmap *dl_boot_progmap, \
- struct elf32_dsbt_loadmap *dl_boot_ldsomap, \
- Elf32_Dyn *dl_boot_ldso_dyn_pointer, \
- X)
- /*
- * On entry, the kernel has set up the stack thusly:
- *
- * 0(sp) pad0
- * 4(sp) pad1
- * 8(sp) argc
- * 12(sp) argv[0]
- * ...
- * (4*(argc+3))(sp) NULL
- * (4*(argc+4))(sp) envp[0]
- * ...
- * NULL
- *
- * Register values are unspecified, except:
- *
- * B4 --> executable loadmap address
- * A6 --> interpreter loadmap address
- * B6 --> dynamic section address
- *
- * NB: DSBT index is always 0 for the executable
- * and 1 for the interpreter
- */
- __asm__(" .text\n"
- ".globl _start\n"
- ".hidden _start\n"
- "_start:\n"
- /* Find interpreter DSBT base in dynamic section */
- " MV .S2 B6,B2\n"
- " || ADD .D1X B6,4,A2\n"
- " LDW .D2T2 *B2++[2],B0\n"
- " || LDW .D1T1 *A2++[2],A0\n"
- " MVKL .S2 " __stringify(DT_C6000_DSBT_BASE) ",B7\n"
- " MVKH .S2 " __stringify(DT_C6000_DSBT_BASE) ",B7\n"
- " NOP\n"
- " NOP\n"
- /*
- * B0 now holds dynamic tag and A0 holds tag value.
- * Loop through looking for DSBT base tag
- */
- "0:\n"
- " [B0] CMPEQ .L2 B0,B7,B1\n"
- " || [!B0] MVK .S2 1,B1\n"
- " [!B1] BNOP .S1 0b,5\n"
- " ||[!B1] LDW .D2T2 *B2++[2],B0\n"
- " ||[!B1] LDW .D1T1 *A2++[2],A0\n"
- /*
- * DSBT base in A0 needs to be relocated.
- * Search through our loadmap to find where it got loaded.
- *
- * struct elf32_dsbt_loadmap {
- * Elf32_Half version;
- * Elf32_Half nsegs;
- * struct {
- * Elf32_Addr addr;
- * Elf32_Addr p_vaddr;
- * Elf32_Word p_memsz;
- * } segments[];
- * }
- *
- */
- " MV .S1 A6,A1\n"
- " [!A1] MV .S1X B4,A1\n"
- " ADD .D1 A1,2,A3\n"
- " LDHU .D1T2 *A3++[1],B0\n" /* nsegs */
- " LDW .D1T1 *A3++[1],A10\n" /* addr */
- " LDW .D1T1 *A3++[1],A11\n" /* p_vaddr */
- " LDW .D1T1 *A3++[1],A12\n" /* p_memsz */
- " NOP\n"
- " NOP\n"
- /*
- * Here we have:
- * B0 -> number of segments to search.
- * A3 -> pointer to next segment to check
- * A10 -> segment load address
- * A11 -> ELF segment virt address
- * A12 -> ELF segment size
- */
- "0:\n"
- " [!B0] B .S2 0f\n"
- " SUB .D2 B0,1,B0\n"
- " CMPLTU .L1 A0,A11,A13\n"
- " || SUB .S1 A12,1,A12\n"
- " ADD .D1 A11,A12,A12\n"
- " CMPGTU .L1 A0,A12,A14\n"
- " OR .L1 A13,A14,A2\n"
- " [A2] B .S2 0b\n"
- " || [!A2] SUB .L1 A0,A11,A0\n"
- " [B0] LDW .D1T1 *A3++[1],A10\n" /* addr */
- " || [!A2] ADD .L1 A0,A10,A0\n"
- " [B0] LDW .D1T1 *A3++[1],A11\n" /* p_vaddr */
- " [B0] LDW .D1T1 *A3++[1],A12\n" /* p_memsz */
- " MV .S2X A0,B14\n"
- " NOP\n"
- "0:\n"
- " B .S2 _dl_start\n"
- " STW .D2T2 B14, *+B14[1]\n"
- " ADD .D1X B15,8,A8\n"
- " ADDKPC .S2 ret_from_dl,B3,2\n"
- "ret_from_dl:\n"
- " B .S2X A4\n"
- " || LDW .D2T2 *+B14[0],B14\n"
- " ADDKPC .S2 __dl_fini,B0,0\n"
- " MV .S1X B0,A4\n"
- " NOP\n"
- " NOP\n"
- " NOP\n"
- "__dl_fini:\n"
- " LDW .D2T2 *+B14[1],B14\n"
- " NOP 4\n"
- " LDW .D2T1 *+B14($GOT(_dl_fini)), A0\n"
- " NOP 4\n"
- " BNOP .S2X A0, 5\n");
- __asm__(" .text\n"
- "__c6x_cache_sync:\n"
- " MVK .S2 330,B0\n"
- " SWE\n"
- " NOP\n"
- " BNOP .S2 B3,5\n"
- " NOP\n"
- " NOP\n"
- " NOP\n"
- " NOP\n"
- "\n"
- );
- /*
- * Get a pointer to the argv array. On many platforms this can be just
- * the address of the first argument, on other platforms we need to
- * do something a little more subtle here.
- */
- #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS) + 1)
- struct elf32_dsbt_loadmap;
- /*
- * Here is a macro to perform a relocation. This is only used when
- * bootstrapping the dynamic loader. RELP is the relocation that we
- * are performing, REL is the pointer to the address we are relocating.
- * SYMBOL is the symbol involved in the relocation, and LOAD is the
- * load address.
- */
- #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \
- switch(ELF_R_TYPE((RELP)->r_info)){ \
- case R_C6000_ABS_L16: \
- { \
- unsigned int opcode = *(REL); \
- unsigned int v = (SYMBOL) + (RELP)->r_addend; \
- opcode &= ~0x7fff80; \
- opcode |= ((v & 0xffff) << 7); \
- *(REL) = opcode; \
- } \
- break; \
- case R_C6000_ABS_H16: \
- { \
- unsigned int opcode = *(REL); \
- unsigned int v = (SYMBOL) + (RELP)->r_addend; \
- opcode &= ~0x7fff80; \
- opcode |= ((v >> 9) & 0x7fff80); \
- *(REL) = opcode; \
- } \
- break; \
- case R_C6000_ABS32: \
- *(REL) = (SYMBOL) + (RELP)->r_addend; \
- break; \
- default: \
- _dl_exit(1); \
- }
- extern void __c6x_cache_sync(unsigned long start, unsigned long end)
- attribute_hidden;
|