]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/ldso/ldso/c6x/dl-startup.h
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / ldso / ldso / c6x / dl-startup.h
1 /* Copyright (C) 2010 Texas Instruments Incorporated
2  * Contributed by Mark Salter <msalter@redhat.com>
3  *
4  * Borrowed heavily from frv arch:
5  * Copyright (C) 2003 Red Hat, Inc.
6  * 
7  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
8  */
9 #undef DL_START
10 #define DL_START(X)   \
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,        \
16            X)
17
18 /*
19  * On entry, the kernel has set up the stack thusly:
20  *
21  *      0(sp)                   pad0
22  *      4(sp)                   pad1
23  *      8(sp)                   argc
24  *      12(sp)                  argv[0]
25  *      ...
26  *      (4*(argc+3))(sp)        NULL
27  *      (4*(argc+4))(sp)        envp[0]
28  *      ...
29  *                              NULL
30  *
31  * Register values are unspecified, except:
32  *
33  *      B4  --> executable loadmap address
34  *      A6  --> interpreter loadmap address
35  *      B6  --> dynamic section address
36  *
37  * NB: DSBT index is always 0 for the executable
38  *     and 1 for the interpreter
39  */
40
41 __asm__("       .text\n"
42         ".globl _start\n"
43         ".hidden _start\n"
44         "_start:\n"
45         /* Find interpreter DSBT base in dynamic section */
46         "          MV .S2               B6,B2\n"
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"
52         "          NOP\n"
53         "          NOP\n"
54         /*
55          * B0 now holds dynamic tag and A0 holds tag value.
56          * Loop through looking for DSBT base tag
57          */
58         "0:\n"
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"
64         /*
65          * DSBT base in A0 needs to be relocated.
66          * Search through our loadmap to find where it got loaded.
67          *
68          * struct elf32_dsbt_loadmap {
69          *     Elf32_Half version;
70          *     Elf32_Half nsegs;
71          *     struct {
72          *         Elf32_Addr addr;
73          *         Elf32_Addr p_vaddr;
74          *         Elf32_Word p_memsz;
75          *     } segments[];
76          * }
77          *
78          */
79         "          MV .S1               A6,A1\n"
80         " [!A1]    MV .S1X              B4,A1\n"
81         "          ADD .D1              A1,2,A3\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 */
86         "          NOP\n"
87         "          NOP\n"
88         /*
89          * Here we have:
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
95          */
96         "0:\n"
97         " [!B0]    B .S2                0f\n"
98         "          SUB .D2              B0,1,B0\n"
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"
104         " [A2]     B .S2                0b\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 */
110         "          MV  .S2X             A0,B14\n"
111         "          NOP\n"
112         "0:\n"
113         "          B .S2                _dl_start\n"
114         "          STW .D2T2            B14, *+B14[1]\n"
115         "          ADD .D1X             B15,8,A8\n"
116         "          ADDKPC .S2           ret_from_dl,B3,2\n"
117         "ret_from_dl:\n"
118         "          B .S2X               A4\n"
119         " ||       LDW .D2T2            *+B14[0],B14\n"
120         "          ADDKPC .S2           __dl_fini,B0,0\n"
121         "          MV .S1X              B0,A4\n"
122         "          NOP\n"
123         "          NOP\n"
124         "          NOP\n"
125         "__dl_fini:\n"
126         "          LDW .D2T2            *+B14[1],B14\n"
127         "          NOP          4\n"
128         "          LDW .D2T1            *+B14($GOT(_dl_fini)), A0\n"
129         "          NOP          4\n"
130         "          BNOP .S2X            A0, 5\n");
131
132 __asm__("       .text\n"
133         "__c6x_cache_sync:\n"
134         "          MVK .S2              330,B0\n"
135         "          SWE\n"
136         "          NOP\n"
137         "          BNOP .S2             B3,5\n"
138         "          NOP\n"
139         "          NOP\n"
140         "          NOP\n"
141         "          NOP\n"
142         "\n"
143 );
144
145 /*
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.
149  */
150 #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*) ARGS) + 1)
151
152 struct elf32_dsbt_loadmap;
153
154 /*
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
159  * load address.
160  */
161 #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \
162         switch(ELF_R_TYPE((RELP)->r_info)){                             \
163         case R_C6000_ABS_L16:                                           \
164             {                                                           \
165                     unsigned int opcode = *(REL);                       \
166                     unsigned int v = (SYMBOL) + (RELP)->r_addend;       \
167                     opcode &= ~0x7fff80;                                \
168                     opcode |= ((v & 0xffff) << 7);                      \
169                     *(REL) = opcode;                                    \
170             }                                                           \
171             break;                                                      \
172         case R_C6000_ABS_H16:                                           \
173             {                                                           \
174                     unsigned int opcode = *(REL);                       \
175                     unsigned int v = (SYMBOL) + (RELP)->r_addend;       \
176                     opcode &= ~0x7fff80;                                \
177                     opcode |= ((v >> 9) & 0x7fff80);                    \
178                     *(REL) = opcode;                                    \
179             }                                                           \
180             break;                                                      \
181         case R_C6000_ABS32:                                             \
182             *(REL) = (SYMBOL) + (RELP)->r_addend;                       \
183             break;                                                      \
184         default:                                                        \
185           _dl_exit(1);                                                  \
186         }
187
188 extern void __c6x_cache_sync(unsigned long start, unsigned long end)
189   attribute_hidden;