xref: /netbsd/sys/arch/emips/stand/common/start.S (revision bbfb5d7a)
1/*	$NetBSD: start.S,v 1.4 2021/12/03 10:49:25 andvar Exp $	*/
2
3/*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code was written by Alessandro Forin and Neil Pittman
8 * at Microsoft Research and contributed to The NetBSD Foundation
9 * by Microsoft Corporation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33	/* Trivial support for printing stuff on the serial line from C pgms.
34     */
35#include <mips/asm.h>
36#include <mips/cpuregs.h>
37#define __ASSEMBLER__ 1
38#include <machine/emipsreg.h>
39
40/* Offsets in the CXTINFO structure
41 */
42#define TS_AT (1 * 4)
43#define TS_V0 (2 * 4)
44#define TS_V1 (3 * 4)
45#define TS_A0 (4 * 4)
46#define TS_A1 (5 * 4)
47#define TS_A2 (6 * 4)
48#define TS_A3 (7 * 4)
49#define TS_T0 (8 * 4)
50#define TS_T1 (9 * 4)
51#define TS_T2 (10 * 4)
52#define TS_T3 (11 * 4)
53#define TS_T4 (12 * 4)
54#define TS_T5 (13 * 4)
55#define TS_T6 (14 * 4)
56#define TS_T7 (15 * 4)
57#define TS_S0 (16 * 4)
58#define TS_S1 (17 * 4)
59#define TS_S2 (18 * 4)
60#define TS_S3 (19 * 4)
61#define TS_S4 (20 * 4)
62#define TS_S5 (21 * 4)
63#define TS_S6 (22 * 4)
64#define TS_S7 (23 * 4)
65#define TS_T8 (24 * 4)
66#define TS_T9 (25 * 4)
67#define TS_K0 (26 * 4)
68#define TS_K1 (27 * 4)
69#define TS_GP (28 * 4)
70#define TS_SP (29 * 4)
71#define TS_FP (30 * 4)
72#define fp s8
73#define TS_RA (31 * 4)
74
75#define TS_PC (32 * 4)
76#define TS_SR (33 * 4)
77#define TS_HI (34 * 4)
78#define TS_LO (35 * 4)
79#define TS_EC (36 * 4)
80#define SIZEOF_CXTINFO (37*4)
81
82/* PROM_MODE means the user plans to keep this code around while running an OS.
83 * So we act kind of like PROM code (BIOS?), but we live in RAM.
84 * So we need to safeguard ourselves against corruptions, some unavoidable.
85 * Like the overriding of the exception vectors, right where our "start" code is.
86 */
87
88        IMPORT(main,4)
89        IMPORT(_end,4)
90
91        .set noreorder
92
93EXPORT(start)
94    bgezal zero,_C_LABEL(real_start)
95    nop
96
97
98/* Does not handle the exception, really.
99 * But to test interrupts should be enough
100 */
101     .org 0x00000080
102NESTED_NOPROFILE(ExceptionHandler,SIZEOF_CXTINFO,$31)
103    la     k1, UserInterruptHandler
104    lw     k1,0(k1)
105    bne    k1,zero,Dispatch
106    mfc0   k0, MIPS_COP_0_EXC_PC
107    j      k0
108    nop /* do not! pop status */
109
110EXPORT(UserInterruptHandler)
111    .word 0
112
113EXPORT(Dispatch)
114	/* Save state on stack */
115	addiu   sp, sp, -SIZEOF_CXTINFO
116	/* save registers */
117    .set noat
118	sw      AT, TS_AT(sp)
119    .set at
120	sw      v0, TS_V0(sp)
121	sw      v1, TS_V1(sp)
122	sw      a0, TS_A0(sp)
123	sw      a1, TS_A1(sp)
124	sw      a2, TS_A2(sp)
125	sw      a3, TS_A3(sp)
126	sw      t0, TS_T0(sp)
127	sw      t1, TS_T1(sp)
128	sw      t2, TS_T2(sp)
129	sw      t3, TS_T3(sp)
130	sw      t4, TS_T4(sp)
131	sw      t5, TS_T5(sp)
132	sw      t6, TS_T6(sp)
133	sw      t7, TS_T7(sp)
134	sw      s0, TS_S0(sp)
135	sw      s1, TS_S1(sp)
136	sw      s2, TS_S2(sp)
137	sw      s3, TS_S3(sp)
138	sw      s4, TS_S4(sp)
139	sw      s5, TS_S5(sp)
140	sw      s6, TS_S6(sp)
141	sw      s7, TS_S7(sp)
142	sw      t8, TS_T8(sp)
143	sw      t9, TS_T9(sp)
144	sw      k0, TS_K0(sp)
145	sw      k1, TS_K1(sp)
146	sw      gp, TS_GP(sp)
147	/* sp: later */
148	sw      fp, TS_FP(sp)
149	sw      ra, TS_RA(sp)
150
151    mfc0    a0, MIPS_COP_0_STATUS
152    mflo    t0
153    mfhi    t1
154	sw      a0, TS_SR(sp)
155	sw      t0, TS_LO(sp)
156	sw      t1, TS_HI(sp)
157	sw      k0, TS_PC(sp)
158
159	/* Save original stack */
160    move    a0,sp
161	addiu   t0, sp, SIZEOF_CXTINFO
162    jalr    k1
163	sw      t0, TS_SP(sp)
164
165    /* Returned value is new PCXINFO */
166    move    a0,v0
167
168	/* First load most registers */
169    .set noat
170	lw       AT, TS_AT(a0)
171	lw       v0, TS_V0(a0)
172	lw       v1, TS_V1(a0)
173	/* a0 later */
174	lw       a1, TS_A1(a0)
175	lw       a2, TS_A2(a0)
176	lw       a3, TS_A3(a0)
177	lw       t0, TS_T0(a0)
178	lw       t1, TS_T1(a0)
179	lw       t2, TS_T2(a0)
180	lw       t3, TS_T3(a0)
181	lw       t4, TS_T4(a0)
182	lw       t5, TS_T5(a0)
183	lw       t6, TS_T6(a0)
184	lw       t7, TS_T7(a0)
185	lw       s0, TS_S0(a0)
186	lw       s1, TS_S1(a0)
187	lw       s2, TS_S2(a0)
188	lw       s3, TS_S3(a0)
189	lw       s4, TS_S4(a0)
190	lw       s5, TS_S5(a0)
191	lw       s6, TS_S6(a0)
192	lw       s7, TS_S7(a0)
193	lw       t8, TS_T8(a0)
194	lw       t9, TS_T9(a0)
195    /* k0,k1 not restored */
196	lw       gp, TS_GP(a0)
197	/* sp later */
198	lw       fp, TS_FP(a0)
199	lw       ra, TS_RA(a0)
200
201    lw       k1, TS_HI(a0)
202    lw       k0, TS_LO(a0)
203    mthi     k1
204    mtlo     k0
205    lw       k1, TS_SR(a0)
206    mtc0     k1, MIPS_COP_0_STATUS
207     /* NB: After this instruction we cannot take any interrupts or traps
208      */
209	lw	sp, TS_SP(a0)
210
211	/* Put pc into k0 */
212	lw	k0, TS_PC(a0)
213	lw	a0, TS_A0(a0)
214	j	k0
215    rfe
216    .set at
217
218END(ExceptionHandler)
219
220     .org 0x00000200
221EXPORT(real_start)
222	.ent _C_LABEL(real_start)
223
224#ifdef SECONDARY_BOOTBLOCK
225    /*
226     * If this is the program that goes into FLASH we must copy ourselves down to RAM.
227     * FLASH default on the MLx is at 0xf0000000, DRAM at 0.
228     */
229    addi    a0,ra,-8         /* Compensate for the first two instructions */
230
231    /* Get the address(relative) of TextStart
232     */
233    bgezal  zero, _C_LABEL(MipsStart2) /* Always jumps */
234    nop
235
236    /* All of the static data, since we are at it.
237     */
238TextStart:                                /* + 0 */
239    /* Text start at final link address */
240    .int    start
241
242DataEnd:                                  /* + 4 */
243    /* Data end == bss start */
244    .int    _edata
245
246BssEnd:                                   /* + 8 */
247    /* Bss end */
248    .int    _end
249
250RelocToRAM:                               /* *+12 */
251    .int    InRAM
252
253MipsStart2:
254
255    /* Source = a0, Dst = t2 */
256    lw      t2, 0(ra)     /* _C_LABEL(TextStart) */
257
258    /* EndPtr = t3 */
259     /* in bdelay slot */
260
261    /* If a0 != t2 then we are running in Flash but should run in RAM
262     * In that case copy .text. Otherwise skip to .bss.
263     */
264    beq     a0,t2,ZroLoop-4
265    lw      t3, 4(ra)    /* _C_LABEL(DataEnd)   */
266
267CpyLoop:
268    /* loop copying 2 words at a time */
269    lw      t4,0(a0)
270    lw      t5,4(a0)
271    addiu   a0,a0,8
272    sw      t4,0(t2)
273    addiu   t2,t2,8
274    sltu    t1,t2,t3
275    bne     t1,zero,CpyLoop
276    sw      t5,-4(t2)
277
278    /* zero the bss
279     */
280    lw      t4, 8(ra)   /* _C_LABEL(BssEnd)  */
281ZroLoop:
282    sltu    t1,t3,t4
283    sw      zero,0(t3)
284    bne     t1,zero,ZroLoop
285    addiu   t3,t3,4
286
287    /* Jump to RAM copy (below)
288     */
289    lw      t1, 12(ra)   /* _C_LABEL(RelocToRAM) */
290    jr      t1
291    nop
292
293    /*
294     * Execute from here after copying out of FLASH into RAM
295     */
296InRAM:
297
298#endif /*  SECONDARY_BOOTBLOCK */
299
300    /* Get a stack
301     */
302#ifdef __GP_SUPPORT__
303    la      gp, _C_LABEL (_gp)
304#endif
305    la    sp,_end
306	addiu sp,sp,(8*1024)          /* BUGBUG arbitrary */
307
308    /* Jump to main
309     */
310    jal   main
311    add   a0,sp,zero
312
313    /* Load failed, reset the processor and jump back to the origins.
314     */
315EXPORT(_rtt)    /* ahem */
316    li     t0,0x1260ff80  /* NB: On new builds this is a SYS-RESET as well */
317    mtc0   t0,MIPS_COP_0_STATUS
318
319    lui    t0,(BRAM_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */
320	jr     t0
321    nop
322
323EXPORT(Stop)
324	b     Stop
325    nop
326
327END(real_start)
328
329        .set noreorder
330        .set noat
331        .set nomacro
332
333/* void Delay(UINT32 count)
334 */
335LEAF(Delay)
336    bne    a0,zero,_C_LABEL(Delay)
337    subu   a0,1
338    j      ra
339    nop
340END(Delay)
341
342/* UINT32 GetPsr(void)
343 * Returns the PSR (coprocessor 0 status)
344 */
345LEAF(GetPsr)
346    mfc0   v0, MIPS_COP_0_STATUS
347    j      ra
348    nop
349END(GetPsr)
350
351/* void SetPsr(UINT32 Psr)
352 * Sets the PSR (coprocessor 0 status)
353 */
354LEAF(SetPsr)
355    mtc0   a0,MIPS_COP_0_STATUS
356    j      ra
357    nop
358END(SetPsr)
359
360/* UINT32 GetCause(void)
361 * Returns the Cause register (coprocessor 0)
362 */
363LEAF(GetCause)
364    mfc0   v0,MIPS_COP_0_CAUSE
365    j      ra
366    nop
367END(GetCause)
368
369/* UINT32 GetEpc(void)
370 * Returns the Epc register (coprocessor 0)
371 */
372LEAF(GetEpc)
373    mfc0   v0,MIPS_COP_0_EXC_PC
374    j      ra
375    nop
376END(GetEpc)
377
378
379/* int PutWord(UINT32 Word);
380 * Returns: 0 if ok, -1 otherwise
381 */
382NESTED(PutWord,12,$31)
383    subu   sp,sp,12
384    sw     s0,8(sp)
385    sw     s1,4(sp)
386    sw     ra,0(sp)
387
388    or     s1,a0,zero
389    /* Spit all nibbles
390     */
391    li     s0,8
392PutWordLoop:
393    srl    a0,s1,32-4
394    li     t0,10
395    sltu   t1,a0,t0
396    bnez   t1,$Digit
397    li     a1,'0'
398    subu   a0,a0,t0
399    li     a1,'a'
400$Digit:
401    sll    s1,s1,4
402    jal    PutChar
403    add    a0,a0,a1
404
405    subu   s0,s0,1
406    bne    v0,zero,PutWordDone /* printed ok? */
407    li     v0,-1
408
409    /* done yet? */
410    bne    s0,zero,PutWordLoop
411    nop
412
413    /* done
414     */
415    li     v0,0
416PutWordDone:
417    lw     ra,0(sp)
418    lw     s1,4(sp)
419    lw     s0,8(sp)
420    jr     ra
421    addiu  sp,sp,12
422
423END(PutWord)
424
425/* int Puts(char *String);
426 * Returns: 0 if ok, -1 otherwise
427 */
428NESTED(Puts,8,$31)
429    subu   sp,sp,8
430    sw     s0,4(sp)
431    sw     ra,0(sp)
432
433    or     s0,a0,zero
434    /* Spit all chars until zero
435     */
436PutsLoop:
437    lbu    a0,0(s0)
438    addiu  s0,s0,1
439    beq    a0,zero,PutsDoneOk
440    nop
441    jal    PutChar
442    nop
443    beq    v0,zero,PutsLoop
444    nop
445
446    /* Timed out
447     */
448    b      PutsDone
449    li     v0,-1
450
451    /* done
452     */
453PutsDoneOk:
454    li     v0,0
455PutsDone:
456    lw     ra,0(sp)
457    lw     s0,4(sp)
458    jr     ra
459    addiu  sp,sp,8
460
461END(Puts)
462
463
464/* int GetChar(void);
465 * Returns: a non-negative value if ok, -1 otherwise
466 */
467LEAF(GetChar)
468    lui    t0,(USART_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */
469    lui    t1,1000          /* n*65k spins max */
470RxNotReady:
471    lw     t4,USARTST(t0)       /* ChannelStatus */
472    andi   t4,t4,USI_RXRDY
473    bgtz   t4,$GotByte
474    subu   t1,t1,1
475    /* still ok to spin? */
476    bgtz   t1,RxNotReady
477    nop
478    /* Timed out
479     */
480    jr     ra
481    li     v0,-1
482
483    /* Gottabyte
484     */
485$GotByte:
486    lw     v0,USARTRX(t0)        /* RxData */
487    jr     ra
488    andi   v0,0xff
489END(GetChar)
490
491/* int PutChar(UINT8 v);
492 * Returns: 0 if ok, -1 otherwise
493 */
494LEAF(PutChar)
495    lui    t0,(USART_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */
496    lui    t1,1000          /* n*65k spins max */
497    li     v0,0
498TxNotReady:
499    lw     t4,USARTST(t0)       /* ChannelStatus */
500    andi   t4,t4,USI_TXRDY
501    bgtz   t4,TxReady
502    subu   t1,t1,1
503    /* still ok to spin? */
504    bgtz   t1,TxNotReady
505    nop
506    /* Timed out
507     */
508    jr     ra
509    li     v0,-1
510
511    /* Send it
512     */
513TxReady:
514    jr     ra
515    sw     a0,USARTTX(t0)
516
517END(PutChar)
518
519/* Second arg is a function to call with the first arg:
520 * void switch_stack_and_call(void *arg, void (*function)(void *));
521 */
522LEAF(switch_stack_and_call)
523    /* Get a stack and jump. It would be a very bad idea to return but..
524     */
525    lui   sp,%hi(_end)
526    addiu sp,%lo(_end)
527    jr    a1
528	addiu sp,sp,(2*1024)          /* BUGBUG arbitrary */
529
530END(switch_stack_and_call)
531
532