1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  CPU init module				File: init_mips.S
5    *
6    *  This module contains the vectors and lowest-level CPU startup
7    *  functions for CFE.
8    *
9    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
16    *  This software is furnished under license and may be used and
17    *  copied only in accordance with the following terms and
18    *  conditions.  Subject to these conditions, you may download,
19    *  copy, install, use, modify and distribute modified or unmodified
20    *  copies of this software in source and/or binary form.  No title
21    *  or ownership is transferred hereby.
22    *
23    *  1) Any source code used, modified or distributed must reproduce
24    *     and retain this copyright notice and list of conditions
25    *     as they appear in the source file.
26    *
27    *  2) No right is granted to use any trade name, trademark, or
28    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
29    *     name may not be used to endorse or promote products derived
30    *     from this software without the prior written permission of
31    *     Broadcom Corporation.
32    *
33    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45    *     THE POSSIBILITY OF SUCH DAMAGE.
46    ********************************************************************* */
47
48
49#include "sbmips.h"
50#include "exception.h"
51
52#include "bsp_config.h"
53#include "cpu_config.h"
54
55#ifdef _CFE_
56#include "cfe_devfuncs.h"
57#else
58
59#if (CFG_BIENDIAN) && defined(__MIPSEB)
60#define CFE_EPTSEAL_REV 0x31454643
61#endif
62#define CFE_EPTSEAL 0x43464531
63
64#define cfe_command_restart 0
65#endif
66
67#if CFG_VAPI		    /* haul in SB1250-specfic stuff only for VAPI */
68#include "sb1250_defs.h"
69#include "sb1250_regs.h"
70#include "sb1250_scd.h"
71#endif
72
73/*  *********************************************************************
74    *  Macros
75    ********************************************************************* */
76
77#include "mipsmacros.h"
78
79
80/*  *********************************************************************
81    *  SETLEDS(a,b,c,d)
82    *  SETLEDS1(a,b,c,d)
83    *
84    *  Sets the on-board LED display (if present).  Two variants
85    *  of this routine are provided.  If you're running KSEG1,
86    *  call the SETLEDS1 variant, else call SETLEDS.
87    *
88    *  Input parameters:
89    *  	   a,b,c,d - four ASCII characters (literal constants)
90    *
91    *  Return value:
92    *  	   a0,k1,ra trashed
93    ********************************************************************* */
94
95#define SETLEDS(a,b,c,d)                     \
96	li     a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ;    \
97	CALLINIT_KSEG0(init_table,R_INIT_SETLEDS)
98
99#define SETLEDS1(a,b,c,d)                     \
100	li     a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ;    \
101	CALLINIT_KSEG1(init_table,R_INIT_SETLEDS)
102
103/*  *********************************************************************
104    *  Other constants
105    ********************************************************************* */
106
107/*
108 * This is the size of the stack, rounded to KByte boundaries.
109 */
110
111#ifndef CFG_STACK_SIZE
112#error "CFG_STACK_SIZE not defined"
113#else
114#define STACK_SIZE	((CFG_STACK_SIZE+1023) & ~1023)
115#endif
116
117#ifdef __MIPSEB
118#define TEXTSECTION	0x2e746578		# ".tex", big-endian
119#else
120#define TEXTSECTION	0x7865742e		# ".tex", little-endian
121#endif
122
123/*
124 * Duplicates from cfe_iocb.h -- warning!
125 */
126
127#define CFE_CACHE_FLUSH_D	1
128#define CFE_CACHE_INVAL_I	2
129#define CFE_CACHE_INVAL_D	4
130#define CFE_CACHE_INVAL_L2	8
131#define CFE_CACHE_FLUSH_L2	16
132#define CFE_CACHE_INVAL_RANGE	32
133#define CFE_CACHE_FLUSH_RANGE	64
134
135
136/*
137 * To make life easier reading this code, define "KSEGBASE"
138 * to either K0BASE or K1BASE depending on whether we're running
139 * uncached.
140 */
141
142#if CFG_RUNFROMKSEG0
143#define KSEGBASE	K0BASE
144#else
145#define KSEGBASE	K1BASE
146#endif
147
148
149/*  *********************************************************************
150    *  Names of registers used in this module
151    ********************************************************************* */
152
153#define RELOCOFFSET	s8			/* $30 (fp) */
154#define TEXTOFFSET      t9			/* $25 (t9) */
155#define MEMTOP		t8			/* $24 (t8) */
156#define TEXTBASE	s7			/* $23 (s7) */
157
158		.sdata
159
160#include "initdata.h"		/* declare variables we use here */
161
162#if CFG_MULTI_CPUS
163		.globl	cfe_spinlock
164cfe_spinlock:	.word	0
165#endif
166
167		.extern	_ftext
168		.extern	_etext
169		.extern	_fdata
170		.extern	_edata
171		.extern	_fbss
172		.extern	_end
173
174/*  *********************************************************************
175    *  uninitialized data
176    ********************************************************************* */
177
178		.bss
179
180		.comm	__junk,4
181
182/*  *********************************************************************
183    *  Exception Vectors
184    ********************************************************************* */
185
186		.text
187
188		.set noreorder
189
190/*
191 * If we're building a bi-endian version, this is the base
192 * address that we can expect to find the little-endian version
193 * of the firmware.
194 *
195 * Warning: If you change this, you must also change
196 * the linker script (arch/mips/common/src/cfe_rom_reloc_cached_biendian.lds)
197 * and the mkflashimage program (hosttools/mkflashimage.c)
198 */
199
200#define BIENDIAN_LE_BASE	0xBFD00000
201
202/*
203 * Declare the actual vectors.  This expands to code that
204 * must be at the very beginning of the text segment.
205 */
206
207DECLARE_VECTOR(0x0000,vec_reset,cpu_reset)
208DECLARE_VECTOR(0x0200,vec_tlbfill,cpu_tlbfill)
209DECLARE_XVECTOR(0x0280,vec_xtlbfill,cpu_xtlbfill,XTYPE_XTLBFILL)
210DECLARE_VECTOR(0x0300,vec_cacheerr,cpu_cacheerr)
211DECLARE_XVECTOR(0x0380,vec_exception,cpu_exception,XTYPE_EXCEPTION)
212DECLARE_XVECTOR(0x0400,vec_interrupt,cpu_interrupt,XTYPE_INTERRUPT)
213DECLARE_XVECTOR(0x0480,vec_ejtag,cpu_ejtag,XTYPE_EJTAG)
214
215
216/*
217 * New location of CFE seal.  Will eventually phase out the seal at
218 * offset 0x508
219 */
220		.org	0x4E0
221cfe_seal:	.word	CFE_EPTSEAL
222		.word	CFE_EPTSEAL
223
224#if (CFG_BIENDIAN) && defined(__MIPSEB)
225		.org    0x4E8
226cfe_seal_rev:	.word	CFE_EPTSEAL_REV
227		.word	CFE_EPTSEAL_REV
228#endif
229
230		.set reorder
231
232/*  *********************************************************************
233    *  CFE Entry Point (used by OS boot loaders and such)
234    ********************************************************************* */
235
236		.set  noreorder
237
238DECLARE_VECTOR(0x0500,vec_apientry,cpu_apientry)
239#if !(CFG_BIENDIAN)
240		.org	0x508
241		.word   CFE_EPTSEAL
242		.word	CFE_EPTSEAL
243#endif
244
245/*  *********************************************************************
246    *  Verification APIs (if present)   [SB1250-specific]
247    ********************************************************************* */
248
249#if CFG_VAPI
250#if CFG_EMBEDDED_PIC
251#error "CFG_VAPI is not compatible with relocatable code"
252#endif
253#include "vapi.h"
254/*
255 * Vector should be 16 bytes long
256 */
257#define VAPI_VECTOR(l,x) \
258		.extern x ; \
259		.org (l & 0xFFFF) ; \
260		j       x ; \
261		nop ;  \
262		.word   VAPI_EPTSEAL ; \
263		.word   VAPI_EPTSEAL
264
265VAPI_VECTOR(VAPI_FUNC_EXIT,vapi_exit)
266VAPI_VECTOR(VAPI_FUNC_DUMPGPRS,vapi_dumpgprs)
267VAPI_VECTOR(VAPI_FUNC_SETLOG,vapi_setlog)
268VAPI_VECTOR(VAPI_FUNC_LOGVALUE,vapi_logsingle)
269VAPI_VECTOR(VAPI_FUNC_LOGDATA,vapi_logdata)
270VAPI_VECTOR(VAPI_FUNC_LOGTRACE,vapi_logtrace)
271VAPI_VECTOR(VAPI_FUNC_LOGSOC,vapi_savesoc)
272VAPI_VECTOR(VAPI_FUNC_LOGGPRS,vapi_loggprs)
273VAPI_VECTOR(VAPI_FUNC_DUMPSTRING,vapi_puts)
274VAPI_VECTOR(VAPI_FUNC_SETLEDS,vapi_setleds)
275VAPI_VECTOR(VAPI_FUNC_LOGFPRS,vapi_logfprs)
276#endif
277
278
279		.set   reorder
280
281/*  *********************************************************************
282    *  Some offsets depend on our current configuration
283    ********************************************************************* */
284
285#if CFG_EMBEDDED_PIC
286#define RUNTIME_RELOC_START	__runtime_reloc_start
287#define RUNTIME_RELOC_STOP	__runtime_reloc_stop
288#else
289#define RUNTIME_RELOC_START	0
290#define RUNTIME_RELOC_STOP	0
291#endif
292
293
294/*  *********************************************************************
295    *  Segment Table.
296    *
297    *  Addresses of data segments and of certain routines we're going
298    *  to call from KSEG1.  These are here mostly for the embedded
299    *  PIC case, since we can't count on the 'la' instruction to
300    *  do the expected thing (the assembler expands it into a macro
301    *  for doing GP-relative stuff, and the code is NOT GP-relative.
302    *  So, we (relocatably) get the offset of this table and then
303    *  index within it.
304    *
305    *  Pointer values in this segment will be relative to KSEG0 for
306    *  cached versions of CFE, so we need to OR in K1BASE in the
307    *  case of calling to a uncached address.
308    *
309    *  The LOADREL macro handles most of the nastiness here.
310    ********************************************************************* */
311
312
313#include "segtable.h"
314
315#if CFG_VAPI
316		.org	0x600			# move past exception vectors
317#else
318		.org	0x580			# move past exception vectors
319#endif
320
321#if CFG_EMBEDDED_NVRAM
322		.org	0x1000
323		.globl	embedded_nvram
324embedded_nvram:	.fill	0x400,4,~(0x48534c46)
325#endif
326
327		.globl segment_table
328segment_table:
329		_LONG_	_etext			# [  0] End of text (R_SEG_ETEXT)
330		_LONG_	_fdata			# [  1] Beginning of data (R_SEG_FDATA)
331		_LONG_	_edata			# [  2] End of data (R_SEG_EDATA)
332		_LONG_	_end			# [  3] End of BSS (R_SEG_END)
333		_LONG_	_ftext			# [  4] Beginning of text (R_SEG_FTEXT)
334		_LONG_	_fbss			# [  5] Beginning of BSS (R_SEG_FBSS)
335		_LONG_	_gp			# [  6] Global Pointer (R_SEG_GP)
336		_LONG_  RUNTIME_RELOC_START	# [  7] Beginning of reloc entries
337		_LONG_  RUNTIME_RELOC_STOP	# [  8] End of reloc entries
338		_LONG_	cpu_apientry		# [  9] R_SEG_APIENTRY
339
340/*  *********************************************************************
341    *  Init Table.
342    *
343    *  This is like segment_table except it contains pointers to
344    *  routines used during initialization.  It serves both as a
345    *  table for doing PIC stuff and also to separate out
346    *  machine-specific init routines.
347    *
348    *  The CALLINIT_xxx macros are used to call routines in this table.
349    ********************************************************************* */
350
351
352		.globl  init_table
353init_table:
354		_LONG_  board_earlyinit         # [  0] R_INIT_EARLYINIT
355		_LONG_  board_setleds           # [  1] R_INIT_SETLEDS
356		_LONG_  board_draminfo		# [  2] R_INIT_DRAMINFO
357		_LONG_	CPUCFG_CPUINIT		# [  3] R_INIT_CPUINIT
358		_LONG_  CPUCFG_ALTCPU_START1	# [  4] R_INIT_ALTCPU_START1
359		_LONG_  CPUCFG_ALTCPU_START2	# [  5] R_INIT_ALTCPU_START2
360		_LONG_  CPUCFG_ALTCPU_RESET     # [  6] R_INIT_ALTCPU_RESET
361		_LONG_  CPUCFG_CPURESTART	# [  7] R_INIT_CPURESTART
362		_LONG_  CPUCFG_DRAMINIT		# [  8] R_INIT_DRAMINIT
363		_LONG_  CPUCFG_CACHEOPS		# [  9] R_INIT_CACHEOPS
364		_LONG_  CPUCFG_TLBHANDLER       # [ 10] R_INIT_TLBHANDLER
365		_LONG_	cfe_main		# [ 11] R_INIT_CMDSTART
366		_LONG_	cfe_command_restart	# [ 12] R_INIT_CMDRESTART
367		_LONG_  cfe_doxreq		# [ 13] R_INIT_DOXREQ
368
369
370#if !CFG_MINIMAL_SIZE
371		.globl  diag_table
372diag_table:	_LONG_  CPUCFG_DIAG_TEST1	# [ 0 ] R_DIAG_TEST1
373		_LONG_  CPUCFG_DIAG_TEST2	# [ 1 ] R_DIAG_TEST2
374#endif
375
376/*  *********************************************************************
377    *  CPU Startup Code
378    ********************************************************************* */
379
380cpu_reset:
381
382	/*
383	 * Start with GP as zero.  Nobody should touch
384	 * this or set it to any other value until we're ready
385	 * to use it.  This is used to tell when we should start
386	 * using relocated references in the init table,
387	 * so beware!  (see CALLINIT_RELOC in mipsmacros.h)
388	 */
389
390		move	gp,zero			# start with no GP.
391
392#if CFG_VAPI
393	/*
394	 * VAPI works by using the SCD to reset just the core.
395	 * Look for a special signature in the mailbox register
396	 * on CPU0 - if present, jump to the start of the diag.
397	 * Of course, you need a real 12500 to do this.
398	 */
399
400		li	k0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CPU))
401		ld	k0,0(k0)
402		dli	k1,VAPI_MAGIC_NUMBER_MC
403		beq	k0,k1,vapi_runmc
404		dli	k1,VAPI_MAGIC_NUMBER_UNC
405		beq	k0,k1,vapi_rununc
406		dli	k1,VAPI_MAGIC_NUMBER
407		bne	k0,k1,vapi_skip
408
409	/*
410	 * The only CP0 init we do is to set K0 to cacheable
411	 */
412
413		mfc0	k0,C0_CONFIG		# get current CONFIG register
414		srl	k0,k0,3			# strip out K0 bits
415		sll	k0,k0,3			# k0 bits now zero
416		or	k0,k0,K_CFG_K0COH_COHERENT # K0 is cacheable.
417		mtc0	k0,C0_CONFIG
418
419	/*
420	 * Set any required defeature bits (for VAPI diagnostics only)
421	 * they get cleared by the soft reset.
422	 */
423
424		jal	sb1250_reset_defeature	/* in sb1250_l1cache.S */
425
426	/*
427	 * Jump to the diagnostic.  Two variants, one for cached
428	 * and one for uncached.
429	 */
430
431		li	k0,VAPI_DIAG_ENTRY
432		j	k0
433
434vapi_rununc:	li	k0,VAPI_DIAG_ENTRY_UNC
435		j	k0
436
437vapi_runmc:	li	k0,VAPI_DIAG_ENTRY_MC
438		j	k0
439
440vapi_skip:
441#endif
442
443	/*
444	 * Test the CAUSE and STATUS registers for why we
445	 * are here.  Cold reset, Warm reset, and NMI all
446	 * use this vector.
447	 */
448
449
450
451	/*
452	 * Test to see if we're on the secondary CPU.  If so,
453	 * go do the initialization for that CPU.
454	 */
455
456#if CFG_MULTI_CPUS
457		CALLINIT_KSEG1(init_table,R_INIT_ALTCPU_RESET)
458		/* does not return if on CPU1 */
459#endif
460
461#------------------------------------------------------------------------------
462
463	/*
464	 * Do low-level board initialization.  This is our first
465	 * chance to customize the startup sequence.
466	 */
467
468		CALLINIT_KSEG1(init_table,R_INIT_EARLYINIT)
469
470		SETLEDS1('H','E','L','O')
471
472		CALLINIT_KSEG1(init_table,R_INIT_CPUINIT)
473
474	/*
475	 * Run some diagnostics
476	 */
477
478#if !CFG_MINIMAL_SIZE
479		SETLEDS1('T','S','T','1')
480
481		CALLINIT_KSEG1(diag_table,R_DIAG_TEST1)
482#endif
483
484
485#------------------------------------------------------------------------------
486#if CFG_MULTI_CPUS
487	/*
488	 * Spin up secondary CPU core(s)
489	 */
490
491		CALLINIT_KSEG1(init_table,R_INIT_ALTCPU_START1)
492#endif
493
494	/*
495	 * Now, switch from KSEG1 to KSEG0
496	 */
497
498
499#if CFG_RUNFROMKSEG0
500		bal	cpu_kseg0_switch
501#endif
502
503#------------------------------------------------------------------------------
504	/*
505	 * Now running on cpu0 in K0SEG.
506	 */
507
508#if CFG_INIT_DRAM
509		SETLEDS('D','R','A','M')
510
511		CALLINIT_KSEG0(init_table,R_INIT_DRAMINFO)
512
513		move   a0,v0		# pass these params
514		CALLINIT_KSEG0(init_table,R_INIT_DRAMINIT)
515		srl	k0,v0,10	# board_draminit returns memsize in bytes
516#else
517		li	k0,CFG_DRAM_SIZE
518#endif
519
520#ifdef CFE_CAPMEM
521		li	k0,CFE_CAPMEM
522#endif
523
524		/* Check if we are already in RAM */
525		bal	1f
526		nop
5271:		li	t0,0x1fffffff
528		and	t0,t0,ra
529		li	t1,0x1fc00000
530		blt	t0,t1,zbss
531		nop
532
533		SETLEDS('C','O','P','Y')
534
535#if !CFG_EMBEDDED_PIC
536#if !CFG_XIP
537		/* Copy self to RAM */
538		LOADREL(a0,_ftext)
539		la	a1,_ftext
540#else
541		/* Copy data only to RAM */
542		LOADREL(a0,_etext)
543		la	a1,_fdata
544#endif
545		la	a2,_edata
546		sub	a2,a2,a1
5471:		LR	t0,0(a0)
548		SR	t0,0(a1)
549		add	a0,4
550		add	a1,4
551		sub	a2,4
552		bnez	a2,1b
553		nop
554
555zbss:
556		/* Zero BSS */
557		SETLEDS('Z','B','S','S')
558
559		la	a0,_fbss
560		la	a1,_end
561		sub	a1,a1,a0
562
5631:		SR	zero,0(a0)
564		add	a0,4
565		sub	a1,4
566		bnez	a1,1b
567		nop
568
569		SETLEDS(' ','D','$','F')
570
571		/* Flush the D cache */
572		CALLINIT_KSEG0(cacheops_table,_TBLIDX(0))
573
574		SETLEDS(' ','I','$','I')
575
576		/* and invalidate the I cache */
577		CALLINIT_KSEG0(cacheops_table,_TBLIDX(1))
578
579		SETLEDS(' ','J','S','R')
580
581		/* Jump to self in RAM  */
582		la	a0,have_ram
583		jr	a0
584		nop
585
586		.globl  cacheops_table
587cacheops_table:	_LONG_  bcmcore_l1cache_flush_d	# [ 0 ] DCACHE_FULSH
588		_LONG_  bcmcore_l1cache_inval_i	# [ 1 ] ICACHE_INVAL
589#endif
590
591#------------------------------------------------------------------------------
592
593#if CFG_BOOTRAM
594		b      have_ram			# No RAM is ok if using emulator RAM
595#endif
596
597		bne    k0,zero,have_ram
598
599		SETLEDS('R','A','M','X')	# die here if no ram
600
601die1:		b      die1
602
603have_ram:
604
605	 /*
606	  * If this is the 64-bit version, turn on the KX bit
607	  * to allow 64-bit accesses.
608	  */
609
610#ifdef __long64
611		mfc0	t0,C0_SR
612		or	t0,t0,M_SR_KX
613		mtc0	t0,C0_SR
614#endif
615
616#------------------------------------------------------------------------------
617	/*
618	 * K0 contains the RAM size (and therefore the top of RAM
619	 * offset).  Start there, and subtract the amount of memory
620	 * we expect to use.  If we have more than 256MB of
621	 * physical memory, work backwards from the 256MB
622	 * boundary.
623	 */
624
625__CalcMemTop:   li	MEMTOP,0x40000		# 256MB boundary
626		bgt	k0,MEMTOP,1f		# use 256MB if k0 is greater
627		move	MEMTOP,k0		# otherwise keep top
6281:		sll	MEMTOP,10		# make into byte amount
629
630
631#if CFG_EMBEDDED_PIC
632	/*
633	 * Calculate the data relocation amount.  Store in FP
634	 * for now.  We'll call this register RELOCOFFSET.
635	 *
636	 * Also calculate a similar offset for relocating code
637	 * if we're doing that.  Call this TEXTOFFSET (t9).
638	 */
639
640		LOADREL(a0,segment_table)	# we'll need this.
641
642		LR	t1,R_SEG_ETEXT(a0)
643		LR	t0,R_SEG_FTEXT(a0)
644		sub	t1,t1,t0		# T1 = text size
645		sub	t3,MEMTOP,t1		# reserve room for code
646		li	t2,~31			# round down to cache-line boundary
647		and	t3,t2
648		move	TEXTBASE,t3		# TEXTBASE is current mem top
649		sub	TEXTBASE,64		# Reserve top 64 bytes
650
651/*
652 * If you're debugging the relocation stuff, you can uncomment this
653 * line to force CFE to be relocated to a specific address.  Sure
654 * makes life easier when setting breakpoints!
655 *
656 *		li	TEXTBASE,0x3C00000
657 */
658
659		li	t2,KSEGBASE
660		add	TEXTBASE,t2		# offset is in K0SEG.
661		sub	TEXTOFFSET,TEXTBASE,t0	# TEXTOFFSET is distance to move
662
663__RelocOffset:
664
665		li	t0,((CFG_HEAP_SIZE*1024)+STACK_SIZE) # t0 = size of heap + stack
666		LR	t1,R_SEG_END(a0)
667		LR	t2,R_SEG_FDATA(a0)
668		sub	t1,t2			# t1 = data + bss
669		add	t0,t1			# t0 = total
670		li	t1,31			# round to 32-byte boundary
671		add	t0,t1
672		not	t1
673		and	t0,t1			# t0 = total size rounded up
674
675		sub	t1,TEXTBASE,t0		# t1 = TEXTBASE - total size
676
677	/*
678	 * t1 now contains the place where we would like to put our
679	 * data segment, BSS, and heap.  Calculate the difference between that
680	 * and where our data segment currently resides.
681	 */
682
683		LR	t0,R_SEG_FDATA(a0)		# beginning of data
684		subu	RELOCOFFSET,t1,t0	# offset = distance to move segment
685
686		li	t0,31			# round *down* to a cache line
687		not	t0
688		and	RELOCOFFSET,t0
689#else /* */
690		li	RELOCOFFSET,0		# not relocating, no offset
691		li	TEXTOFFSET,0
692#endif
693
694	/*
695	 * DRAM is now running, and we're alive in cacheable memory
696	 * on cpu0 in K0SEG.  Set up GP.
697	 */
698
699		LOADREL(a0,segment_table)
700		LR	gp,R_SEG_GP(a0)
701		add	gp,RELOCOFFSET
702
703#if CFG_EMBEDDED_PIC
704#------------------------------------------------------------------------------
705	/*
706	 * Zero BSS
707	 */
708
709		SETLEDS('Z','B','S','S')
710
711		LOADREL(a0,segment_table)
712__ZeroBss:
713
714		LR	v0,R_SEG_FBSS(a0)
715		LR	v1,R_SEG_END(a0)
716		ADD	v0,RELOCOFFSET		# Relocate to actual data segment
717		ADD	v1,RELOCOFFSET
718
7191:		SR	zero,0(v0)		# Zero one cacheline at a time
720		SR	zero,(REGSIZE*1)(v0)
721		SR	zero,(REGSIZE*2)(v0)
722		SR	zero,(REGSIZE*3)(v0)
723		add	v0,REGSIZE*4
724		blt	v0,v1,1b
725
726#------------------------------------------------------------------------------
727	/*
728	 * Copy code
729	 */
730
731		SETLEDS('C','O','D','E')
732
733		LOADREL(a0,segment_table)
734__CopyCode:
735
736		move	t1,TEXTBASE		# destination address
737
738		LR	t2,R_SEG_FTEXT(a0)		# Source address
739		LR	t3,R_SEG_ETEXT(a0)
740
7411:		LR	t4,0(t2)	# read one cache line
742		LR	t5,(REGSIZE*1)(t2)
743		LR	t6,(REGSIZE*2)(t2)
744		LR	t7,(REGSIZE*3)(t2)
745		SR	t4,0(t1)	# write one cache line
746		SR	t5,(REGSIZE*1)(t1)
747		SR	t6,(REGSIZE*2)(t1)
748		SR	t7,(REGSIZE*3)(t1)
749		add	t1,REGSIZE*4
750		add	t2,REGSIZE*4
751		bltu	t2,t3,1b
752#endif
753
754#------------------------------------------------------------------------------
755	/*
756	 * Copy initialized data
757	 */
758
759#if CFG_BOOTRAM == 0
760
761		SETLEDS('D','A','T','A')
762
763		LOADREL(a0,segment_table)
764
765__CopyData:
766		LR	t1,R_SEG_ETEXT(a0)
767		li	t0,15
768		add	t1,t0
769		not	t0
770		and	t1,t0		# t1 = _etext rounded up to 16-byte boundary
771
772		LR	t2,R_SEG_FDATA(a0)
773		LR	t3,R_SEG_EDATA(a0)
774		ADD	t2,RELOCOFFSET	# Relocate to actual data segment
775		ADD	t3,RELOCOFFSET
776
7771:		LR	t4,0(t1)	# read one cache line
778		LR	t5,(REGSIZE*1)(t1)
779		LR	t6,(REGSIZE*2)(t1)
780		LR	t7,(REGSIZE*3)(t1)
781		SR	t4,0(t2)	# write one cache line
782		SR	t5,(REGSIZE*1)(t2)
783		SR	t6,(REGSIZE*2)(t2)
784		SR	t7,(REGSIZE*3)(t2)
785		add	t1,(REGSIZE*4)
786		add	t2,(REGSIZE*4)
787		bltu	t2,t3,1b
788
789#endif
790
791#------------------------------------------------------------------------------
792
793#if CFG_EMBEDDED_PIC
794
795	/*
796	 * Walk through relocation table and do the data segment
797	 * fixups.  Each entry in this table is in the following
798	 * format:
799	 *
800	 *    <offset> <segment-name>
801	 *    4 bytes   8 bytes
802	 *
803	 * The 'offset' represents the distance into the segment where
804	 * a fixup needs to be applied, and the 'segment-name'
805	 * is the name of the section where the offset is located.
806	 * The basic idea is that you would expect that code and
807	 * data are moved by different amounts, so places where
808	 * the data segment references the text segment you need
809	 * apply the offset that the text segment was moved, not data.
810	 */
811
812__RelocAll:
813		SETLEDS('R','E','L','O')
814
815		LOADREL(a0,segment_table)
816
817		LR	a1,R_SEG_FDATA(a0)		# beginning of data segment
818		add	a1,RELOCOFFSET		# relocate it.
819
820		LR	v0,R_SEG_RELOCSTART(a0)	# relocs start here
821		LR	v1,R_SEG_RELOCEND(a0)	# and end here
822		li	t2,TEXTSECTION		# marker for text sections
823
824	#
825	# The bottom bit in the offset will be set if we want to
826	# handle a MIPS_64 relocation.   Of course, this bit is not really
827	# part of the relocation offset.
828	#
829		li	t4,1			# Make the mask that we
830		not	t4			# need to mask off bottom bit
831
832reloclp:	lw	t0,4(v0)		# Get section name
833		beq	t0,t2,textreloc		# skip if for text section
834
835# - - - - -  - - - - -  - - - - -  - - - - -  - - - - -  - - - - -  - - - - -  - - - - -
836
837		lw	t0,0(v0)		# T0 = relocation offset
838		and	t1,t0,1			# test MIPS_64 reloc bit (t1=0 for 32-bit)
839		and	t0,t4			# clear MIPS_64 reloc bit
840		add	t0,a1			# Add offset to start of data segment
841
842		beq	t1,zero,reloc32		# go if doing a 32-bit reloc
843
844reloc64:	ld	t1,(t0)			# Get word from data segment
845		add	t1,RELOCOFFSET		# Add relocation offset
846		sd	t1,(t0)			# Put it back
847		b	skipreloc		# next...
848
849reloc32:	lw	t1,(t0)			# Get word from data segment
850		add	t1,RELOCOFFSET		# Add relocation offset
851		sw	t1,(t0)			# Put it back
852		b	skipreloc
853
854# - - - - -  - - - - -  - - - - -  - - - - -  - - - - -  - - - - -  - - - - -  - - - - -
855
856textreloc:
857		lw	t0,0(v0)		# T0 = relocation offset
858		and	t1,t0,1			# test MIPS_64 reloc bit (t1=0 for 32-bit)
859		and	t0,t4			# clear MIPS_64 reloc bit
860		add	t0,a1			# Add offset to start of data segment
861
862		beq	t1,zero,treloc32	# go if doing a 32-bit reloc
863
864treloc64:	ld	t1,(t0)			# Get word from data segment
865		add	t1,TEXTOFFSET		# Add relocation offset
866		sd	t1,(t0)			# Put it back
867		b	skipreloc		# next...
868
869treloc32:	lw	t1,(t0)			# Get word from data segment
870		add	t1,TEXTOFFSET		# Add relocation offset
871		sw	t1,(t0)			# Put it back
872		b	skipreloc
873
874skipreloc:	add	v0,12			# Go to next relocation entry
875		blt	v0,v1,reloclp
876#endif
877
878
879#------------------------------------------------------------------------------
880
881#if CFG_EMBEDDED_PIC
882	/*
883	 * Flush the cache, then switch to relocated code
884	 * We need to flush the cache since we just moved the code and
885	 * it may still live in our L1 DCache.  We also need to
886	 * flush L2, since there are some rare times we run
887	 * uncached from DRAM, like when we start/stop a CPU.
888	 *
889	 * In the case of running completely uncached, don't flush the
890	 * cache.  It should not have any dirty lines in it, but you
891	 * never know...
892	 */
893
894__GoRelo:
895
896#if CFG_RUNFROMKSEG0
897		SETLEDS('L','1','2','F')
898
899		li	a0,CFE_CACHE_FLUSH_D | CFE_CACHE_FLUSH_L2
900		CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS)
901		li	a0,CFE_CACHE_INVAL_I
902		CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS)
903#endif /* CFG_RUNFROMKSEG0 */
904
905	 	LOADREL(t0,gorelo)		# get offset of next instr
906		add	t0,TEXTOFFSET		# add in our relocation
907		j	t0			# and go there
908gorelo:		nop
909
910#endif
911	/*
912	 * Remember total amount of memory.  This is *still* in k0
913	 * after all this time.  Hopefully.
914	 */
915
916__MemVars:
917		SR	k0,mem_totalsize
918		SR	RELOCOFFSET,mem_datareloc
919
920		move	v0,zero
921
922		LOADREL(a0,segment_table)	# trashed by l2 cache flush
923#if CFG_EMBEDDED_PIC
924		LR	v0,R_SEG_FDATA(a0)
925		ADD	v0,RELOCOFFSET
926#else
927		LR	v0,R_SEG_FTEXT(a0)
928		ADD	v0,TEXTOFFSET
929#endif
930		LR	v1,R_SEG_END(a0)
931		ADD	v1,RELOCOFFSET
932
933		SR	v0,mem_bottomofmem
934		SR	v1,mem_heapstart
935
936#if CFG_EMBEDDED_PIC
937		move	t0,MEMTOP		# relocated code means top of memory
938		add	t0,KSEGBASE		# is *after* code.
939		SR	t0,mem_topofmem
940
941//		SR	gp,-8(t0)		# Store handle at top of memory
942//		SR	zero,-16(t0)		# Zero out the other handles
943//		SR	zero,-24(t0)		# in our special place.
944//		SR	zero,-32(t0)		#
945//		SR	zero,-48(t0)		#
946//		SR	zero,-64(t0)		#
947#else
948		add	v1,(CFG_HEAP_SIZE*1024)	# Otherwise
949		add	v1,STACK_SIZE
950		SR	v1,mem_topofmem
951#endif
952
953		SR	TEXTOFFSET,mem_textreloc
954
955		/* At this point it's safe to use the CALLINIT_RELOC macro */
956
957
958		LR	t1,R_SEG_FTEXT(a0)
959		LR	t0,R_SEG_ETEXT(a0)
960		sub	t0,t0,t1
961		SR	t0,mem_textsize
962		add	t1,TEXTOFFSET
963		SR	t1,mem_textbase
964
965
966#------------------------------------------------------------------------------
967
968#if CFG_MULTI_CPUS
969	/*
970	 * Let secondary CPU(s) run their idle loops.  Set the
971	 * mailbox register to our relocation factor so we can read
972	 * it out of the mailbox register and relocate GP properly.
973	 */
974
975		move	a0,RELOCOFFSET
976		CALLINIT_RELOC(init_table,R_INIT_ALTCPU_START2)
977#endif
978
979#ifdef _SB1250_PASS1_WORKAROUNDS_
980	/*
981	 * Okay, it's safe now to be coherent.
982	 * Flush the D cache to invalidate all the lines we have,
983	 * then change the config register back.
984	 */
985		li	a0,CFE_CACHE_FLUSH_D
986		CALLINIT_RELOC(init_table,R_INIT_CACHEOPS)
987		SETCCAMODE(v0,K_CFG_K0COH_COHERENT) /* cacheable coherent */
988#endif
989
990	/*
991	 * Stash away some config register stuff
992	 */
993
994		mfc0	v0,C0_PRID
995		SR	v0,cpu_prid
996
997
998#------------------------------------------------------------------------------
999
1000	/*
1001	 * Set up the "C" stack and jump to the main routine.
1002	 */
1003
1004		SETLEDS('M','A','I','N')
1005
1006		LR	sp,mem_heapstart
1007		ADD	sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8)
1008		li	a0,0			# call as "cfe_main(0,0)"
1009		li	a1,0
1010
1011		CALLINIT_RELOC(init_table,R_INIT_CMDSTART)  # should not return
1012
1013
1014	/*
1015	 * Terminate the simulator.
1016	 */
1017
1018crash_sim:      li $2,1
1019		li $4,0
1020		syscall	0xCA
1021		b	cpu_reset
1022
1023
1024
1025#ifdef _CFE_
1026/*  *********************************************************************
1027    *  CFE_WARMSTART
1028    *
1029    *  Restart the command interpreter
1030    *
1031    *  Input parameters:
1032    *      A0 - command status
1033    *  	   nothing (GP has already been set up for us)
1034    *
1035    *  Return value:
1036    *  	   nothing
1037    ********************************************************************* */
1038
1039LEAF(cfe_warmstart)
1040
1041		SR	a0,0(sp)		# store on old stack
1042		LOADREL(v0,init_table)
1043		LR	v0,R_INIT_CPURESTART(v0)
1044#if CFG_EMBEDDED_PIC
1045		LR	t0,mem_textreloc	# relocate table entry
1046		ADD	v0,v0,t0
1047#endif
1048
1049		jal	v0			# had better not trash GP or K1
1050
1051	 /*
1052	  * If this is the 64-bit version, turn on the KX bit
1053	  * to allow 64-bit accesses.  Do after calling the cpu
1054	  * init routine, but before touching the stack, which
1055	  * *could* be a 64-bit address.
1056	  */
1057
1058#ifdef __long64
1059		mfc0	t0,C0_SR
1060		or	t0,t0,M_SR_KX
1061		mtc0	t0,C0_SR
1062		HAZARD
1063#endif
1064
1065		LR	a0,0(sp)
1066
1067		LR	sp,mem_heapstart
1068		ADD	sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8)
1069
1070	/*
1071	 * If someone called the API to do a warm start, clear the
1072	 * spin lock, since the call will never return.
1073	 */
1074
1075#if CFG_MULTI_CPUS
1076		SPIN_UNLOCK(cfe_spinlock,t0)
1077#endif
1078
1079		CALLINIT_RELOC(init_table,R_INIT_CMDRESTART)  # should not return
1080
1081END(cfe_warmstart)
1082#endif
1083
1084/*  *********************************************************************
1085    *  CFE_FLUSHCACHE
1086    *
1087    *  Perform certain cache operations
1088    *
1089    *  Input parameters:
1090    *  	   a0 - flags (CFE_CACHE_xxx flags, or zero for a default)
1091    *      a1,a2 - start/end of range for "range invalidate" operations
1092    *      (not used otherwise)
1093    *
1094    *  Return value:
1095    *  	   nothing
1096    ********************************************************************* */
1097
1098LEAF(_cfe_flushcache)
1099
1100		sub	sp,56
1101		SR	ra,0(sp)
1102		SR	a0,8(sp)
1103		SR	s0,16(sp)
1104		SR	v1,24(sp)
1105		SR	s1,32(sp)
1106		SR	s2,40(sp)
1107		SR	s3,48(sp)
1108		SR	s4,56(sp)
1109
1110
1111		CALLINIT_RELOC(init_table,R_INIT_CACHEOPS)
1112
1113		LR	s4,56(sp)
1114		LR	s3,48(sp)
1115		LR	s2,40(sp)
1116		LR	s1,32(sp)
1117		LR	v1,24(sp)
1118		LR	s0,16(sp)
1119		LR	a0,8(sp)
1120		LR	ra,0(sp)
1121		add	sp,56
1122		j	ra
1123
1124END(_cfe_flushcache)
1125
1126
1127/*  *********************************************************************
1128    *  CFE_LAUNCH
1129    *
1130    *  Start the user program.  The program is passed a handle
1131    *  that must be passed back when calling the firmware.
1132    *
1133    *  Parameters passed to the called program are as follows:
1134    *
1135    *      a0 - CFE handle
1136    *      a1 - entry vector
1137    *      a2 - reserved, will be 0
1138    *      a3 - entrypoint signature.
1139    *
1140    *  Input parameters:
1141    *  	   a0 - entry vector
1142    *
1143    *  Return value:
1144    *  	   does not return
1145    ********************************************************************* */
1146
1147LEAF(cfe_launch)
1148
1149		sub	sp,8
1150		SR	a0,0(sp)
1151
1152
1153	/*
1154	 * Mask all interrupts.
1155	 */
1156		mfc0	v0,C0_SR		# Get current interrupt flag
1157		li	v1,M_SR_IE		# master interrupt control
1158		not	v1			# disable interrupts
1159		and	v0,v1			# SR now has IE=0
1160		mtc0	v0,C0_SR		# put back into CP0
1161
1162
1163	/*
1164	 * Flush the D-Cache, since the program we loaded is "data".
1165	 * Invalidate the I-Cache, so that addresses in the program
1166	 * region will miss and need to be filled from the data we
1167	 * just flushed above.
1168	 */
1169
1170		li	a0,CFE_CACHE_FLUSH_D|CFE_CACHE_INVAL_I
1171		CALLINIT_RELOC(init_table,R_INIT_CACHEOPS)
1172
1173
1174	/*
1175	 * Set things up for launching the program.  Pass the
1176	 * handle in A0 - apps need to remember that and pass it
1177	 * back.
1178	 */
1179
1180		j	RunProgram
1181
1182END(cfe_launch)
1183
1184	/*
1185	 * This is a nice place to set a breakpoint.
1186	 */
1187LEAF(RunProgram)
1188
1189		LOADREL(a2,segment_table)
1190		LR	a2,R_SEG_APIENTRY(a2) # A2 = code entry
1191
1192#if CFG_EMBEDDED_PIC
1193		LR	t1,mem_textreloc	# relocate table entry
1194		ADD	a2,a2,t1
1195#endif
1196		move	t0,a0		#
1197		move	a1,zero		# A1 = 0
1198		move	a0,gp		# A0 = handle
1199		li	a3,CFE_EPTSEAL  # A3 = entrypoint signature
1200		LR	t0,0(sp)	# entry point
1201
1202		j	t0		# go for it.
1203END(RunProgram)
1204
1205
1206
1207
1208/*  *********************************************************************
1209    *  CFE_LEDS
1210    *
1211    *  Set the on-board LEDs.
1212    *
1213    *  Input parameters:
1214    *  	   a0 - LEDs
1215    *
1216    *  Return value:
1217    *  	   nothing
1218    ********************************************************************* */
1219
1220LEAF(cfe_leds)
1221
1222#if CFG_EMBEDDED_PIC
1223		move	t1,ra			# LOADREL trashes ra!
1224		LOADREL(t0,init_table)
1225		move	ra,t1
1226		LR	t0,R_INIT_SETLEDS(t0)
1227		jr	t0
1228#else
1229		j	board_setleds		# jump to BSP routine
1230#endif
1231
1232END(cfe_leds)
1233
1234/*  *********************************************************************
1235    *  TLB Fill Exeption Handler
1236    ********************************************************************* */
1237
1238cpu_tlbfill:
1239		move	k0,ra			# Save, we're about to trash
1240		LOADREL(k1,init_table)		# Load offset of init table
1241		LR	k1,R_INIT_TLBHANDLER(k1) # Get entry from table
1242		move	ra,k0			# restore trashed ra
1243		j	k1			# Dispatch to handler
1244
1245/*  *********************************************************************
1246    *  XTLB Fill Exception Handler
1247    ********************************************************************* */
1248
1249cpu_xtlbfill:
1250		j	_exc_entry
1251
1252/*  *********************************************************************
1253    *  Cache Error Exception Handler
1254    ********************************************************************* */
1255
1256cpu_cacheerr:
1257
1258#if defined(_CSWARM_) || defined(_SWARM_) || defined(_BCM91120C_) || defined(_PTSWARM_)
1259#define LED_CHAR0	(32+8*3)
1260#define LED_CHAR1	(32+8*2)
1261#define LED_CHAR2	(32+8*1)
1262#define LED_CHAR3	(32+8*0)
1263#if defined(_PTSWARM_)
1264		li    k0,0xBB0A0000	     /* address of LEDs */
1265#else
1266		li    k0,0xB00A0000	     /* address of LEDs */
1267#endif
1268		li    k1,'C'
1269		sb    k1,LED_CHAR0(k0)
1270		li    k1,'e'
1271		sb    k1,LED_CHAR1(k0)
1272		li    k1,'r'
1273		sb    k1,LED_CHAR2(k0)
1274		li    k1,'2'
1275		sb    k1,LED_CHAR3(k0)
1276
1277		SETLEDS1('C','e','r','2')
1278#endif
1279
1280cpu_cache_death:	b	cpu_cache_death
1281
1282
1283
1284/*  *********************************************************************
1285    *  General Exception Handler
1286    ********************************************************************* */
1287
1288cpu_exception:
1289		j	_exc_entry
1290
1291
1292/*  *********************************************************************
1293    *  General Interrupt Handler
1294    ********************************************************************* */
1295
1296cpu_interrupt:
1297		j	_exc_entry
1298
1299
1300/*  *********************************************************************
1301    *  EJTAG Debug Exception Handler
1302    ********************************************************************* */
1303
1304cpu_ejtag:
1305		.set push
1306		.set mips64
1307		deret
1308		.set pop
1309		j	cpu_reset
1310
1311/*  *********************************************************************
1312    *  cpu_apientry(handle,iocb)
1313    *
1314    *  API entry point for external apps.
1315    *
1316    *  Input parameters:
1317    *  	   a0 - firmware handle (used to determine the location of
1318    *  	        our relocated data)
1319    *  	   a1 - pointer to IOCB to execute
1320    *
1321    *  Return value:
1322    *  	   v0 - return code, 0 if ok
1323    ********************************************************************* */
1324
1325#define _regidx(x)    ((x)*8)
1326
1327#define CAE_SRSAVE     _regidx(0)
1328#define CAE_GPSAVE     _regidx(1)
1329#define CAE_RASAVE     _regidx(2)
1330#define CAE_S0SAVE     _regidx(3)
1331#define CAE_S1SAVE     _regidx(4)
1332#define CAE_S2SAVE     _regidx(5)
1333#define CAE_S3SAVE     _regidx(6)
1334#define CAE_S4SAVE     _regidx(7)
1335#define CAE_S5SAVE     _regidx(8)
1336#define CAE_S6SAVE     _regidx(9)
1337#define CAE_S7SAVE     _regidx(10)
1338#define CAE_K0SAVE     _regidx(11)
1339#define CAE_K1SAVE     _regidx(12)
1340
1341#define CAE_STKSIZE    _regidx(13)
1342
1343LEAF(cpu_apientry)
1344
1345		sub	sp,CAE_STKSIZE		# Make room for our stuff
1346
1347		mfc0	v0,C0_SR		# Get current interrupt flag
1348		SR	v0,CAE_SRSAVE(sp)	# save on stack
1349		li	t0,M_SR_IE		# master interrupt control
1350		not	t0			# disable interrupts
1351		and	v0,t0			# SR now has IE=0
1352#ifdef __long64
1353		or	v0,M_SR_KX
1354#endif
1355		mtc0	v0,C0_SR		# put back into CP0
1356		HAZARD
1357
1358		SR	gp,CAE_GPSAVE(sp)	# save GP
1359		SR	ra,CAE_RASAVE(sp)	# and old RA
1360
1361		SR	s0,CAE_S0SAVE(sp)
1362		SR	s1,CAE_S1SAVE(sp)
1363		SR	s2,CAE_S2SAVE(sp)
1364		SR	s3,CAE_S3SAVE(sp)
1365		SR	s4,CAE_S4SAVE(sp)
1366		SR	s5,CAE_S5SAVE(sp)
1367		SR	s6,CAE_S6SAVE(sp)
1368		SR	s7,CAE_S7SAVE(sp)
1369		SR	k0,CAE_K0SAVE(sp)
1370		SR	k1,CAE_K1SAVE(sp)
1371
1372		move	gp,a0			# set up new GP
1373		move	a0,a1			# A0 points at IOCB
1374
1375#if CFG_RUNFROMKSEG0
1376		bal	cpu_kseg0_switch	# switch to kseg0 if not already there
1377#endif
1378
1379#if CFG_MULTI_CPUS
1380		SPIN_LOCK(cfe_spinlock,t0,t1)
1381#endif
1382
1383		CALLINIT_RELOC(init_table,R_INIT_DOXREQ)
1384
1385#if CFG_MULTI_CPUS
1386		SPIN_UNLOCK(cfe_spinlock,t0)
1387#endif
1388
1389		#
1390		# Restore the saved registers.
1391		#
1392
1393		LR	k1,CAE_K1SAVE(sp)
1394		LR	k0,CAE_K0SAVE(sp)
1395		LR	s7,CAE_S7SAVE(sp)
1396		LR	s6,CAE_S6SAVE(sp)
1397		LR	s5,CAE_S5SAVE(sp)
1398		LR	s4,CAE_S4SAVE(sp)
1399		LR	s3,CAE_S3SAVE(sp)
1400		LR	s2,CAE_S2SAVE(sp)
1401		LR	s1,CAE_S1SAVE(sp)
1402		LR	s0,CAE_S0SAVE(sp)
1403
1404		LR	ra,CAE_RASAVE(sp)	# unwind the stack
1405		LR	gp,CAE_GPSAVE(sp)
1406
1407		LR	t0,CAE_SRSAVE(sp)	# old interrupt mask
1408
1409		add	sp,CAE_STKSIZE		# restore old stack pointer
1410
1411		mtc0	t0,C0_SR		# restore interrupts
1412		HAZARD
1413		j	ra
1414		nop
1415
1416END(cpu_apientry)
1417
1418
1419/*  *********************************************************************
1420    *  CPU_KSEG0_SWITCH
1421    *
1422    *  Hack the return address so we will come back in KSEG0
1423    *
1424    *  Input parameters:
1425    *  	   nothing
1426    *
1427    *  Return value:
1428    *  	   nothing
1429    ********************************************************************* */
1430
1431LEAF(cpu_kseg0_switch)
1432
1433		and	ra,(K0SIZE-1)
1434		or	ra,K0BASE
1435		jr	ra
1436
1437END(cpu_kseg0_switch)
1438
1439
1440
1441
1442/*  *********************************************************************
1443    *  _GETSTATUS()
1444    *
1445    *  Read the STATUS register into v0
1446    *
1447    *  Input parameters:
1448    *  	   nothing
1449    *
1450    *  Return value:
1451    *  	   v0 - Status register
1452    ********************************************************************* */
1453
1454LEAF(_getstatus)
1455
1456		mfc0	v0,C0_SR
1457		j	ra
1458END(_getstatus)
1459
1460/*  *********************************************************************
1461    *  _SETSTATUS()
1462    *
1463    *  Set the STATUS register to the value in a0
1464    *
1465    *  Input parameters:
1466    *  	   nothing
1467    *
1468    *  Return value:
1469    *  	   v0 - Status register
1470    ********************************************************************* */
1471
1472LEAF(_setstatus)
1473
1474		mtc0	a0,C0_SR
1475		j	ra
1476END(_setstatus)
1477
1478
1479/*  *********************************************************************
1480    *  _GETCAUSE()
1481    *
1482    *  Read the CAUSE register into v0
1483    *
1484    *  Input parameters:
1485    *  	   nothing
1486    *
1487    *  Return value:
1488    *  	   v0 - Cause register
1489    ********************************************************************* */
1490
1491LEAF(_getcause)
1492
1493		mfc0	v0,C0_CAUSE
1494		j	ra
1495END(_getcause)
1496
1497
1498/*  *********************************************************************
1499    *  _GETTICKS()
1500    *
1501    *  Read the COUNT register into v0
1502    *
1503    *  Input parameters:
1504    *  	   nothing
1505    *
1506    *  Return value:
1507    *  	   v0 - count register
1508    ********************************************************************* */
1509
1510LEAF(_getticks)
1511
1512		mfc0	v0,C0_COUNT
1513		j	ra
1514END(_getticks)
1515
1516
1517/*  *********************************************************************
1518    *  _SETALARM(ticks)
1519    *
1520    *  Set the C0_Compare register from a0
1521    *
1522    *  Input parameters:
1523    *  	   a0 - compare register
1524    *
1525    *  Return value:
1526    *  	   none
1527    ********************************************************************* */
1528
1529LEAF(_setalarm)
1530
1531		mtc0	a0,C0_COMPARE
1532		j	ra
1533END(_setalarm)
1534
1535
1536/*  *********************************************************************
1537    *  _SETCONTEXT()
1538    *
1539    *  Set the CONTEXT register.
1540    *
1541    *  Input parameters:
1542    *  	   a0 - context
1543    *
1544    *  Return value:
1545    *  	   nothing
1546    ********************************************************************* */
1547
1548LEAF(_setcontext)
1549
1550		mtc0	a0,C0_CTEXT
1551		j	ra
1552END(_setcontext)
1553
1554/*  *********************************************************************
1555    *  _GETSEGTBL()
1556    *
1557    *  Return the address of the segment table.  We use this
1558    *  to display the startup messages.
1559    *
1560    *  You can't just address the table from C because it lives
1561    *  in the text segment.
1562    *
1563    *  Input parameters:
1564    *  	   nothing
1565    *
1566    *  Return value:
1567    *      address of table
1568    ********************************************************************* */
1569
1570
1571LEAF(_getsegtbl)
1572		move	t0,ra
1573		LOADREL(v0,segment_table)
1574		move	ra,t0
1575		j	ra
1576END(_getsegtbl)
1577
1578
1579/*  *********************************************************************
1580    *  _wbflush()
1581    *
1582    *  Flush the write buffer.  This is probably not necessary
1583    *  on SiByte CPUs, but we have it for completeness.
1584    *
1585    *  Input parameters:
1586    *  	   nothing
1587    *
1588    *  Return value:
1589    *  	   nothing
1590    ********************************************************************* */
1591
1592LEAF(_wbflush)
1593
1594		sync			/* drain the buffers */
1595		la	t0,__junk	/* do an uncached read to force it out */
1596		or	t0,K1BASE
1597		lw	zero,0(t0)
1598		j	ra
1599
1600END(_wbflush)
1601
1602
1603/*  *********************************************************************
1604    *  End
1605    ********************************************************************* */
1606
1607
1608