1/*
2 * crt0.S -- startup file for MIPS.
3 *
4 * Copyright (c) 1995, 1996, 1997, 2001 Cygnus Support
5 *
6 * The authors hereby grant permission to use, copy, modify, distribute,
7 * and license this software and its documentation for any purpose, provided
8 * that existing copyright notices are retained in all copies and that this
9 * notice is included verbatim in any distributions. No written agreement,
10 * license, or royalty fee is required for any of the authorized uses.
11 * Modifications to this software may be copyrighted by their authors
12 * and need not follow the licensing terms described here, provided that
13 * the new terms are clearly indicated on the first page of each file where
14 * they apply.
15 */
16
17/* This file does not use any floating-point ABI.  */
18	.gnu_attribute 4,0
19
20#ifdef __mips16
21/* This file contains 32 bit assembly code.  */
22	.set nomips16
23#endif
24
25#include "regs.S"
26#include "abiflags.S"
27
28/*
29 * Set up some room for a stack. We just grab a chunk of memory.
30 */
31#define STACK_SIZE  0x4000
32#define GLOBAL_SIZE 0x2000
33
34#define STARTUP_STACK_SIZE	0x0100
35
36/* This is for referencing addresses that are not in the .sdata or
37   .sbss section under embedded-pic, or before we've set up gp.  */
38#ifdef __mips_embedded_pic
39# ifdef __mips64
40#  define LA(t,x) la t,x-PICBASE ; daddu t,s0,t
41# else
42#  define LA(t,x) la t,x-PICBASE ; addu t,s0,t
43# endif
44#else /* __mips_embedded_pic */
45# define LA(t,x) la t,x
46#endif /* __mips_embedded_pic */
47
48	.comm	__memsize, 12
49	.comm	__lstack, STARTUP_STACK_SIZE
50
51	.text
52	.align	2
53
54/* Without the following nop, GDB thinks _start is a data variable.
55 * This is probably a bug in GDB in handling a symbol that is at the
56 * start of the .text section.
57 */
58	nop
59
60	.globl	hardware_hazard_hook .text
61	.globl	_start
62	.ent	_start
63_start:
64#ifdef __mips_embedded_pic
65#define PICBASE start_PICBASE
66	.set	noreorder
67	PICBASE = .+8
68        bal	PICBASE
69	nop
70	move	s0,$31
71	.set	reorder
72#endif
73#if __mips<3
74#  define STATUS_MASK (SR_CU1|SR_PE)
75#else
76/* Post-mips2 has no SR_PE bit.  */
77#  ifdef __mips64
78/* Turn on 64-bit addressing and additional float regs.  */
79#    define STATUS_MASK (SR_CU1|SR_FR|SR_KX|SR_SX|SR_UX)
80#  else
81#    if __mips_fpr==32
82#      define STATUS_MASK (SR_CU1)
83#    else
84/* Turn on additional float regs.  */
85#      define STATUS_MASK (SR_CU1|SR_FR)
86#    endif
87#  endif
88#endif
89
90	/* Clear Cause register.  */
91	mtc0	zero,C0_CAUSE
92	nop
93
94	/* Read MIPS_abiflags structure and set status/config registers
95	   accordingly.  */
96	.weak	__MIPS_abiflags_start
97	.weak	__MIPS_abiflags_end
98	LA	(t0,__MIPS_abiflags_start)
99	LA	(t1,__MIPS_abiflags_end)
100	addiu	t1,t1,-24
101	move	v0,zero			/* Mask for C0_SR.  */
102
103	/* Branch to 1f is the .MIPS.abiflags section is not 24 bytes.  This
104	   indicates it is either missing or corrupt.  */
105	bne	t0,t1,1f
106
107	/* Check isa_level.  */
108	lbu	t1,ABIFlags_isa_level(t0)
109	sltu	v1,t1,3			/* Is MIPS < 3?  */
110	xori	t1,t1,64		/* Is MIPS64?  */
111	beq	v1,zero,4f
112	li	v1,SR_PE
113	or	v0,v0,v1		/* Enable soft reset.  */
1144:
115	li	v1,(SR_KX|SR_SX|SR_UX)
116	bne	t1,zero,5f
117	or	v0,v0,v1		/* Enable extended addressing.  */
1185:
119	/* Check fp_abi.  */
120	lbu	t1,ABIFlags_fp_abi(t0)
121	xori	t1,t1,Val_GNU_MIPS_ABI_FP_SOFT
122	li	v1,SR_CU1
123	beq	t1,zero,2f		/* Skip MSA and cpr1_size checks.  */
124	or	v0,v0,v1		/* Enable co-processor 1.  */
125
126	/* Check cpr1_size.  */
127	lbu	t1,ABIFlags_cpr1_size(t0)
128	xori	t1,t1,AFL_REG_64
129	li	v1,SR_FR
130	bne	t1,zero,3f
131	or	v0,v0,v1		/* Enable 64-bit FPU registers.  */
1323:
133	/* Check ases.  */
134	lw	t1,ABIFlags_ases(t0)
135	andi	t1,t1,AFL_ASE_MSA
136	li	v1,SR_FR
137	beq	t1,zero,2f
138	or	v0,v0,v1		/* Enable 64-bit FPU registers.  */
139	li	v1,SR_MSA
140	.set	push
141	.set	mips32
142	mtc0	v1,C0_CONFIG,5		/* Enable MSA.  */
143	.set	pop
144	b	2f
145
1461:
147	/* MIPS_abiflags structure is not available.  Set status/config
148	   registers based on flags defined by compiler.  */
149#ifdef __mips_soft_float
150	li	v0,(STATUS_MASK-(STATUS_MASK & SR_CU1))
151#else
152	li	v0,STATUS_MASK
153#endif
154
1552:
156	/* Set C0_SR,  */
157	mtc0	v0,C0_SR
158	nop
159
160	/* Avoid hazard from C0_SR changes.  */
161	LA	(t0, hardware_hazard_hook)
162	beq	t0,zero,2f
163	jalr	t0
1642:
165
166
167/* Fix high bits, if any, of the PC so that exception handling doesn't get
168   confused.  */
169	LA (v0, 3f)
170	jr	v0
1713:
172	LA (gp, _gp)				# set the global data pointer
173	.end _start
174
175/*
176 * zero out the bss section.
177 */
178	.globl	__memsize
179	.globl	get_mem_info .text
180	.globl	__stack
181	.globl	__global
182	.ent	zerobss
183zerobss:
184	LA (v0, _fbss)
185	LA (v1, _end)
186	beq	v0,v1,2f
1871:
188	addiu	v0,v0,4
189	sw	zero,-4(v0)
190	bne	v0,v1,1b
1912:
192	la	t0, __lstack			# make a small stack so we
193	addiu	sp, t0, STARTUP_STACK_SIZE	# can run some C code
194	la	a0, __memsize			# get the usable memory size
195	jal	get_mem_info
196
197	/* setup the stack pointer */
198	LA (t0, __stack)			# is __stack set ?
199	bne	t0,zero,4f
200
201	/* NOTE: a0[0] contains the amount of memory available, and
202	         not the last memory address. */
203	la	a0, __memsize
204	lw	t0,0(a0)			# last address of memory available
205	la	t1,K0BASE			# cached kernel memory
206	addu	t0,t0,t1			# get the end of memory address
207	/* Allocate 32 bytes for the register parameters.  Allocate 16
208	   bytes for a null argv and envp.  Round the result up to 64
209	   bytes to preserve alignment.  */
210	subu	t0,t0,64
2114:
212	move	sp,t0				# set stack pointer
213	.end	zerobss
214
215/*
216 * initialize target specific stuff. Only execute these
217 * functions it they exist.
218 */
219	.globl	hardware_init_hook .text
220	.globl	software_init_hook .text
221	.type	_fini,@function
222	.type	_init,@function
223	.globl	atexit .text
224	.globl	exit .text
225	.ent	init
226init:
227	LA (t9, hardware_init_hook)		# init the hardware if needed
228	beq	t9,zero,6f
229	jalr	t9
2306:
231	LA (t9, software_init_hook)		# init the hardware if needed
232	beq	t9,zero,7f
233	jalr	t9
2347:
235	LA (a0, _fini)
236	jal	atexit
237
238#ifdef GCRT0
239	.globl	_ftext
240	.globl	_extext
241	LA (a0, _ftext)
242	LA (a1, _etext)
243	jal	monstartup
244#endif
245
246
247	jal	_init				# run global constructors
248
249	addiu	a1,sp,32			# argv = sp + 32
250	addiu	a2,sp,40			# envp = sp + 40
251#if __mips64
252	sd	zero,(a1)			# argv[argc] = 0
253	sd	zero,(a2)			# envp[0] = 0
254#else
255	sw	zero,(a1)
256	sw	zero,(a2)
257#endif
258	move	a0,zero				# set argc to 0
259	jal	main				# call the program start function
260
261	# fall through to the "exit" routine
262	move	a0,v0				# pass through the exit code
263	jal	exit				# call libc exit to run the G++
264						# destructors
265	.end	init
266
267
268/* Assume the PICBASE set up above is no longer valid below here.  */
269#ifdef __mips_embedded_pic
270#undef PICBASE
271#endif
272
273/*
274 * _exit -- Exit from the application. Normally we cause a user trap
275 *          to return to the ROM monitor for another run. NOTE: This is
276 *	    the only other routine we provide in the crt0.o object, since
277 *          it may be tied to the "_start" routine. It also allows
278 *          executables that contain a complete world to be linked with
279 *          just the crt0.o object.
280 */
281	.globl	hardware_exit_hook .text
282	.globl	_exit
283	.ent _exit
284_exit:
2857:
286#ifdef __mips_embedded_pic
287	/* Need to reinit PICBASE, since we might be called via exit()
288	   rather than via a return path which would restore old s0.  */
289#define PICBASE exit_PICBASE
290	.set	noreorder
291	PICBASE = .+8
292	bal	PICBASE
293	nop
294	move	s0,$31
295	.set	reorder
296#endif
297#ifdef GCRT0
298	LA (t0, _mcleanup)
299	jalr	t0
300#endif
301	LA (t0, hardware_exit_hook)
302	beq	t0,zero,1f
303	jalr	t0
3041:
305
306	# break instruction can cope with 0xfffff, but GAS limits the range:
307	break	1023
308	b	7b				# but loop back just in-case
309	.end _exit
310
311/* Assume the PICBASE set up above is no longer valid below here.  */
312#ifdef __mips_embedded_pic
313#undef PICBASE
314#endif
315
316/* EOF crt0.S */
317