1 /* Copyright (C) 2010 Texas Instruments Incorporated
2 * Contributed by Mark Salter <msalter@redhat.com>
4 * Borrowed heavily from frv arch:
5 * Copyright (C) 2003 Red Hat, Inc.
7 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
11 static void * __attribute_used__ \
12 _dl_start (unsigned placeholder, \
13 struct elf32_dsbt_loadmap *dl_boot_progmap, \
14 struct elf32_dsbt_loadmap *dl_boot_ldsomap, \
15 Elf32_Dyn *dl_boot_ldso_dyn_pointer, \
19 * On entry, the kernel has set up the stack thusly:
26 * (4*(argc+3))(sp) NULL
27 * (4*(argc+4))(sp) envp[0]
31 * Register values are unspecified, except:
33 * B4 --> executable loadmap address
34 * A6 --> interpreter loadmap address
35 * B6 --> dynamic section address
37 * NB: DSBT index is always 0 for the executable
38 * and 1 for the interpreter
45 /* Find interpreter DSBT base in dynamic section */
47 " || ADD .D1X B6,4,A2\n"
48 " LDW .D2T2 *B2++[2],B0\n"
49 " || LDW .D1T1 *A2++[2],A0\n"
50 " MVKL .S2 " __stringify(DT_C6000_DSBT_BASE) ",B7\n"
51 " MVKH .S2 " __stringify(DT_C6000_DSBT_BASE) ",B7\n"
55 * B0 now holds dynamic tag and A0 holds tag value.
56 * Loop through looking for DSBT base tag
59 " [B0] CMPEQ .L2 B0,B7,B1\n"
60 " || [!B0] MVK .S2 1,B1\n"
61 " [!B1] BNOP .S1 0b,5\n"
62 " ||[!B1] LDW .D2T2 *B2++[2],B0\n"
63 " ||[!B1] LDW .D1T1 *A2++[2],A0\n"
65 * DSBT base in A0 needs to be relocated.
66 * Search through our loadmap to find where it got loaded.
68 * struct elf32_dsbt_loadmap {
80 " [!A1] MV .S1X B4,A1\n"
82 " LDHU .D1T2 *A3++[1],B0\n" /* nsegs */
83 " LDW .D1T1 *A3++[1],A10\n" /* addr */
84 " LDW .D1T1 *A3++[1],A11\n" /* p_vaddr */
85 " LDW .D1T1 *A3++[1],A12\n" /* p_memsz */
90 * B0 -> number of segments to search.
91 * A3 -> pointer to next segment to check
92 * A10 -> segment load address
93 * A11 -> ELF segment virt address
94 * A12 -> ELF segment size
99 " CMPLTU .L1 A0,A11,A13\n"
100 " || SUB .S1 A12,1,A12\n"
101 " ADD .D1 A11,A12,A12\n"
102 " CMPGTU .L1 A0,A12,A14\n"
103 " OR .L1 A13,A14,A2\n"
105 " || [!A2] SUB .L1 A0,A11,A0\n"
106 " [B0] LDW .D1T1 *A3++[1],A10\n" /* addr */
107 " || [!A2] ADD .L1 A0,A10,A0\n"
108 " [B0] LDW .D1T1 *A3++[1],A11\n" /* p_vaddr */
109 " [B0] LDW .D1T1 *A3++[1],A12\n" /* p_memsz */
114 " STW .D2T2 B14, *+B14[1]\n"
115 " ADD .D1X B15,8,A8\n"
116 " ADDKPC .S2 ret_from_dl,B3,2\n"
119 " || LDW .D2T2 *+B14[0],B14\n"
120 " ADDKPC .S2 __dl_fini,B0,0\n"
126 " LDW .D2T2 *+B14[1],B14\n"
128 " LDW .D2T1 *+B14($GOT(_dl_fini)), A0\n"
130 " BNOP .S2X A0, 5\n");
133 "__c6x_cache_sync:\n"
146 * Get a pointer to the argv array. On many platforms this can be just
147 * the address of the first argument, on other platforms we need to
148 * do something a little more subtle here.
150 #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS) + 1)
152 struct elf32_dsbt_loadmap;
155 * Here is a macro to perform a relocation. This is only used when
156 * bootstrapping the dynamic loader. RELP is the relocation that we
157 * are performing, REL is the pointer to the address we are relocating.
158 * SYMBOL is the symbol involved in the relocation, and LOAD is the
161 #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \
162 switch(ELF_R_TYPE((RELP)->r_info)){ \
163 case R_C6000_ABS_L16: \
165 unsigned int opcode = *(REL); \
166 unsigned int v = (SYMBOL) + (RELP)->r_addend; \
167 opcode &= ~0x7fff80; \
168 opcode |= ((v & 0xffff) << 7); \
172 case R_C6000_ABS_H16: \
174 unsigned int opcode = *(REL); \
175 unsigned int v = (SYMBOL) + (RELP)->r_addend; \
176 opcode &= ~0x7fff80; \
177 opcode |= ((v >> 9) & 0x7fff80); \
181 case R_C6000_ABS32: \
182 *(REL) = (SYMBOL) + (RELP)->r_addend; \
188 extern void __c6x_cache_sync(unsigned long start, unsigned long end)