chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / ports / sysdeps / mach / hurd / mips / init-first.c
1 /* Initialization code run first thing by the ELF startup code.  For Mips/Hurd.
2    Copyright (C) 1996,1997,1998,2000,01,02,03 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <hurd.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include "hurdstartup.h"
25 #include "set-hooks.h"
26 #include "hurdmalloc.h"         /* XXX */
27
28 extern void __mach_init (void);
29 extern void __init_misc (int, char **, char **);
30 #ifdef USE_NONOPTION_FLAGS
31 extern void __getopt_clean_environment (char **);
32 #endif
33 #ifndef SHARED
34 extern void _dl_non_dynamic_init (void) internal_function;
35 #endif
36 extern void __libc_global_ctors (void);
37
38 unsigned int __hurd_threadvar_max;
39 unsigned long int __hurd_threadvar_stack_offset;
40 unsigned long int __hurd_threadvar_stack_mask;
41
42 int __libc_multiple_libcs attribute_hidden = 1;
43
44 int __libc_argc attribute_hidden;
45 char **__libc_argv attribute_hidden;
46
47 void *(*_cthread_init_routine) (void); /* Returns new SP to use.  */
48 void (*_cthread_exit_routine) (int status) __attribute__ ((__noreturn__));
49
50
51 /* Things that want to be run before _hurd_init or much anything else.
52    Importantly, these are called before anything tries to use malloc.  */
53 DEFINE_HOOK (_hurd_preinit_hook, (void));
54
55 static void
56 init1 (int argc, char *arg0, ...)
57 {
58   char **argv = &arg0;
59   char **envp = &argv[argc + 1];
60   struct hurd_startup_data *d;
61
62   __libc_argc = argc;
63   __libc_argv = argv;
64   __environ = envp;
65   while (*envp)
66     ++envp;
67   d = (void *) ++envp;
68
69   /* If we are the bootstrap task started by the kernel,
70      then after the environment pointers there is no Hurd
71      data block; the argument strings start there.  */
72   if ((void *) d != argv[0])
73     {
74       _hurd_init_dtable = d->dtable;
75       _hurd_init_dtablesize = d->dtablesize;
76
77       {
78         /* Check if the stack we are now on is different from
79            the one described by _hurd_stack_{base,size}.  */
80
81         char dummy;
82         const vm_address_t newsp = (vm_address_t) &dummy;
83
84         if (d->stack_size != 0 && (newsp < d->stack_base ||
85                                    newsp - d->stack_base > d->stack_size))
86           /* The new stack pointer does not intersect with the
87              stack the exec server set up for us, so free that stack.  */
88           __vm_deallocate (__mach_task_self (), d->stack_base, d->stack_size);
89       }
90     }
91
92   if (__hurd_threadvar_stack_mask == 0)
93     {
94       /* We are not using cthreads, so we will have just a single allocated
95          area for the per-thread variables of the main user thread.  */
96       unsigned long int i;
97       __hurd_threadvar_stack_offset
98         = (unsigned long int) malloc (__hurd_threadvar_max *
99                                       sizeof (unsigned long int));
100       if (__hurd_threadvar_stack_offset == 0)
101         __libc_fatal ("Can't allocate single-threaded per-thread variables.");
102       for (i = 0; i < __hurd_threadvar_max; ++i)
103         ((unsigned long int *) __hurd_threadvar_stack_offset)[i] = 0;
104     }
105
106   if ((void *) d != argv[0] && (d->portarray || d->intarray))
107     /* Initialize library data structures, start signal processing, etc.  */
108     _hurd_init (d->flags, argv,
109                 d->portarray, d->portarraysize,
110                 d->intarray, d->intarraysize);
111
112 #ifndef SHARED
113   _dl_non_dynamic_init ();
114 #endif
115   __init_misc (argc, argv, __environ);
116
117 #ifdef USE_NONOPTION_FLAGS
118   /* This is a hack to make the special getopt in GNU libc working.  */
119   __getopt_clean_environment (envp);
120 #endif
121
122 #ifdef SHARED
123   __libc_global_ctors ();
124 #endif
125
126   (void) &init1;
127 }
128
129 static void *
130 __init (int *data)
131 {
132   int argc = *data;
133   char **argv = (void *) (data + 1);
134   char **envp = &argv[argc + 1];
135   struct hurd_startup_data *d;
136
137   __environ = envp;
138   while (*envp)
139     ++envp;
140   d = (void *) ++envp;
141
142   /* The user might have defined a value for this, to get more variables.
143      Otherwise it will be zero on startup.  We must make sure it is set
144      properly before before cthreads initialization, so cthreads can know
145      how much space to leave for thread variables.  */
146   if (__hurd_threadvar_max < _HURD_THREADVAR_MAX)
147     __hurd_threadvar_max = _HURD_THREADVAR_MAX;
148
149
150   /* After possibly switching stacks, call `init1' (above) with the user
151      code as the return address, and the argument data immediately above
152      that on the stack.  */
153
154   if (_cthread_init_routine)
155     {
156       /* Initialize cthreads, which will allocate us a new stack to run on.  */
157       void *newsp = (*_cthread_init_routine) ();
158       struct hurd_startup_data *od;
159
160       /* Copy the argdata from the old stack to the new one.  */
161       newsp = memcpy (newsp - ((char *) &d[1] - (char *) data), data,
162                       (char *) d - (char *) data);
163
164       /* Set up the Hurd startup data block immediately following
165          the argument and environment pointers on the new stack.  */
166       od = (newsp + ((char *) d - (char *) data));
167       if ((void *) argv[0] == d)
168         /* We were started up by the kernel with arguments on the stack.
169            There is no Hurd startup data, so zero the block.  */
170         memset (od, 0, sizeof *od);
171       else
172         /* Copy the Hurd startup data block to the new stack.  */
173         *od = *d;
174
175       /* Push the user code address on the top of the new stack.  It will
176          be the return address for `init1'; we will jump there with NEWSP
177          as the stack pointer.  */
178       return newsp;
179     }
180
181   /* The argument data is just above the stack frame we will unwind by
182      returning.  */
183   return (void *) data;
184
185   (void) &__init;
186 }
187
188 #ifdef SHARED
189 /* This function is called to initialize the shared C library.
190    It is called just before the user _start code from mips/elf/start.S,
191    with the stack set up as that code gets it.  */
192
193 /* NOTE!  The linker notices the magical name `_init' and sets the DT_INIT
194    pointer in the dynamic section based solely on that.  It is convention
195    for this function to be in the `.init' section, but the symbol name is
196    the only thing that really matters!!  */
197 /*void _init (int argc, ...) __attribute__ ((unused, section (".init")));*/
198
199 #if __mips64
200 asm ("\
201         .section .init,\"ax\",@progbits\n\
202         .align 3\n\
203         .globl _init\n\
204         .type _init,@function\n\
205         .ent _init\n\
206 _init:\n\
207         .set noreorder\n\
208         .cpload $25\n\
209         .set reorder\n\
210         dsubu $29, 8*8\n\
211         .cprestore 6*8\n\
212         sd $16, 4*8($29)\n\
213         sd $31, 5*8($29)\n\
214         jal preinit\n\
215         sd $28, 6*8($29)\n\
216         move $16, $29 # Save the old stack pointer to s0 ($16)\n\
217         daddu $4, $29, 4*8\n\
218         jal __init\n\
219         # Restore saved registers from the old stack.\n\
220         ld $28, 6*8($16)\n\
221         ld $31, 5*8($16)\n\
222         ld $16, 4*8($16)\n\
223         move $29, $2 # set new sp to SP\n\
224 call_init1:\n\
225         ld $4, 0($29)\n\
226         ld $5, 1*8($29)\n\
227         ld $6, 2*8($29)\n\
228         ld $7, 3*8($29)\n\
229         dla $25, init1\n\
230         jr $25\n\
231         .end _init\n\
232         .text\n\
233 ");
234 #else
235 asm ("\
236         .section .init,\"ax\",@progbits\n\
237         .align 2\n\
238         .globl _init\n\
239         .type _init,@function\n\
240         .ent _init\n\
241 _init:\n\
242         .set noreorder\n\
243         .cpload $25\n\
244         .set reorder\n\
245         subu $29, 32\n\
246         .cprestore 24\n\
247         sw $16, 16($29)\n\
248         sw $31, 20($29)\n\
249         jal preinit\n\
250         sw $28, 24($29)\n\
251         move $16, $29 # Save the old stack pointer to s0 ($16)\n\
252         addu $4, $29, 32\n\
253         jal __init\n\
254         # Restore saved registers from the old stack.\n\
255         lw $28, 24($16)\n\
256         lw $31, 20($16)\n\
257         lw $16, 16($16)\n\
258         move $29, $2 # set new sp to SP\n\
259 call_init1:\n\
260         lw $4, 0($29)\n\
261         lw $5, 4($29)\n\
262         lw $6, 8($29)\n\
263         lw $7, 12($29)\n\
264         la $25, init1\n\
265         jr $25\n\
266         .end _init\n\
267         .text\n\
268 ");
269 #endif
270
271 static void
272 preinit (void)
273 {
274   /* Initialize data structures so we can do RPCs.  */
275   __mach_init ();
276
277   RUN_HOOK (_hurd_preinit_hook, ());
278
279   (void) &preinit;
280 }
281
282 void __libc_init_first (int argc, ...)
283 {
284 }
285 #endif
286
287 #ifndef SHARED
288 /* An assembler code wrapping c function __init.  */
289 #ifdef __mips64
290 asm ("\
291         .text\n\
292         .align 3\n\
293 init:\n\
294         dsubu $29, 8*8\n\
295         sd $16, 4*8($29)\n\
296         sd $31, 5*8($29)\n\
297         move $16, $29\n\
298         jal __init\n\
299         ld $31, 5*8($16)\n\
300         ld $16, 4*8($16)\n\
301         move $29, $2 # set new sp to SP\n\
302 call_init1:\n\
303         ld $4, 0($29)\n\
304         ld $5, 1*8($29)\n\
305         ld $6, 2*8($29)\n\
306         ld $7, 3*8($29)\n\
307         dla $25, init1\n\
308         jr $25\n\
309 ");
310 #else
311 asm ("\
312         .text\n\
313         .align 2\n\
314 init:\n\
315         subu $29, 32\n\
316         sw $16, 16($29)\n\
317         sw $31, 20($29)\n\
318         move $16, $29\n\
319         jal __init\n\
320         lw $31, 20($16)\n\
321         lw $16, 16($16)\n\
322         move $29, $2 # set new sp to SP\n\
323 call_init1:\n\
324         lw $4, 0($29)\n\
325         lw $5, 4($29)\n\
326         lw $6, 8($29)\n\
327         lw $7, 12($29)\n\
328         la $25, init1\n\
329         jr $25\n\
330 ");
331 #endif
332
333 /* An assembler code wrapping c function ___libc_init_first.
334    ___libc_init_first does an RPC call to flush cache to put doinit
335    function on the stack, so we should call __mach_init first in
336    this wrap. */
337 #ifdef __mips64
338 asm ("\
339         .text\n\
340         .align 3\n\
341         .globl __libc_init_first\n\
342 __libc_init_first:\n\
343         dsubu $29, 8\n\
344         sd $31, 0($29)\n\
345         jal __mach_init\n\
346         ld $4, 0($29)\n\
347         ld $5, 1*8($29)\n\
348         ld $6, 2*8($29)\n\
349         ld $7, 3*8($29)\n\
350         j ___libc_init_first\n\
351 ");
352 #else
353 asm ("\
354         .text\n\
355         .align 2\n\
356         .globl __libc_init_first\n\
357 __libc_init_first:\n\
358         subu $29, 4\n\
359         sw $31, 0($29)\n\
360         jal __mach_init\n\
361         lw $4, 0($29)\n\
362         lw $5, 4($29)\n\
363         lw $6, 8($29)\n\
364         lw $7, 12($29)\n\
365         j ___libc_init_first\n\
366 ");
367 #endif
368
369 static void
370 ___libc_init_first (int return_addr, int argc, ...)
371 {
372   void doinit (int *data)
373     {
374 #if 0
375       /* This function gets called with the argument data at TOS.  */
376       void doinit1 (int argc, ...)
377         {
378           init (&argc);
379         }
380 #endif
381       extern void init (int *data);
382
383       /* Push the user return address after the argument data, and then
384          jump to `doinit1' (above), so it is as if __libc_init_first's
385          caller had called `init' with the argument data already on the
386          stack.  */
387       *--data = return_addr;
388
389 #ifdef __mips64
390       asm volatile ("ld $31, 0(%0)\n" /* Load the original return address.  */
391                     "daddu $29, %0, 8\n" /* Switch to new outermost stack.  */
392                     "move $4, $29\n"
393                     "jr %1" : : "r" (data), "r" (&init));
394 #else
395       asm volatile ("lw $31, 0(%0)\n" /* Load the original return address.  */
396                     "addu $29, %0, 4\n" /* Switch to new outermost stack.  */
397                     "move $4, $29\n"
398                     "jr %1" : : "r" (data), "r" (&init));
399 #endif
400       /* NOTREACHED */
401     }
402
403 #if 0
404   /* Initialize data structures so we can do RPCs.  */
405   __mach_init ();
406 #endif
407
408   RUN_HOOK (_hurd_preinit_hook, ());
409
410   _hurd_startup ((void **) &argc, &doinit);
411
412   (void) &___libc_init_first;
413 }
414 #endif