xref: /plan9-contrib/sys/src/boot/vt5/l.s (revision 98a68993d685eb89080b5d73dba0a8f0a226848c)
1/* virtex5 ppc440x5 machine assist */
2#include	"mem.h"
3
4#define MICROBOOT	1	/* if defined, see microboot.s for startup */
5
6/*
7 * Special Purpose Registers of interest here (440 versions)
8 */
9#define SPR_CCR0	0x3b3		/* Core Configuration Register 0 */
10#define SPR_CCR1	0x378	/* core configuration register 1 */
11#define SPR_DAC1	0x13c		/* Data Address Compare 1 */
12#define SPR_DAC2	0x13d		/* Data Address Compare 2 */
13#define SPR_DBCR0	0x134		/* Debug Control Register 0 */
14#define SPR_DBCR1	0x135		/* Debug Control Register 1 */
15#define SPR_DBCR2	0x136		/* Debug Control Register 2 */
16#define SPR_DBSR	0x130		/* Debug Status Register */
17#define SPR_DVC1	0x13e		/* Data Value Compare 1 */
18#define SPR_DVC2	0x13f		/* Data Value Compare 2 */
19#define SPR_DEAR	0x3D		/* Data Error Address Register */
20#define SPR_ESR	0x3E		/* Exception Syndrome Register */
21#define SPR_IAC1	0x138		/* Instruction Address Compare 1 */
22#define SPR_IAC2	0x139		/* Instruction Address Compare 2 */
23#define SPR_IAC3	0x13a		/* Instruction Address Compare 3 */
24#define SPR_IAC4	0x13b		/* Instruction Address Compare 4 */
25#define SPR_PID		0x30		/* Process ID (not the same as 405) */
26#define SPR_PVR		0x11f		/* Processor Version Register */
27
28#define SPR_SPRG0	0x110		/* SPR General 0 */
29#define SPR_SPRG1	0x111		/* SPR General 1 */
30#define SPR_SPRG2	0x112		/* SPR General 2 */
31#define SPR_SPRG3	0x113		/* SPR General 3 */
32
33/* beware that these registers differ in R/W ability on 440 compared to 405 */
34#define SPR_SPRG4R		0x104	/* SPR general 4; user/supervisor R */
35#define SPR_SPRG5R		0x105	/* SPR general 5; user/supervisor R */
36#define SPR_SPRG6R		0x106	/* SPR general 6; user/supervisor R */
37#define SPR_SPRG7R		0x107	/* SPR general 7; user/supervisor R */
38#define SPR_SPRG4W	0x114		/* SPR General 4; supervisor W */
39#define SPR_SPRG5W	0x115		/* SPR General 5; supervisor W  */
40#define SPR_SPRG6W	0x116		/* SPR General 6; supervisor W  */
41#define SPR_SPRG7W	0x117		/* SPR General 7; supervisor W */
42
43#define SPR_SRR0	0x01a		/* Save/Restore Register 0 */
44#define SPR_SRR1	0x01b		/* Save/Restore Register 1 */
45#define SPR_CSRR0	0x03a		/* Critical Save/Restore Register 0 */
46#define SPR_CSRR1	0x03b		/* Critical Save/Restore Register 1 */
47#define SPR_TBL		0x11c		/* Time Base Lower */
48#define SPR_TBU		0x11d		/* Time Base Upper */
49#define	SPR_PIR		0x11e		/* Processor Identity Register */
50
51#define SPR_TCR	0x154	/* timer control */
52#define SPR_TSR	0x150	/* timer status */
53#define SPR_MMUCR	0x3B2	/* mmu control */
54#define SPR_DNV0	0x390	/* data cache normal victim 0-3 */
55#define SPR_DNV1	0x391
56#define SPR_DNV2	0x392
57#define SPR_DNV3	0x393
58#define SPR_DTV0	0x394	/* data cache transient victim 0-3 */
59#define SPR_DTV1	0x395
60#define SPR_DTV2	0x396
61#define SPR_DTV3	0x397
62#define SPR_DVLIM	0x398	/* data cache victim limit */
63#define SPR_INV0	0x370	/* instruction cache normal victim 0-3 */
64#define SPR_INV1	0x371
65#define SPR_INV2	0x372
66#define SPR_INV3	0x374
67#define SPR_ITV0	0x374	/* instruction cache transient victim 0-3 */
68#define SPR_ITV1	0x375
69#define SPR_ITV2	0x376
70#define SPR_ITV3	0x377
71#define SPR_IVOR(n)	(0x190+(n))	/* interrupt vector offset registers 0-15 */
72#define SPR_IVPR	0x03F	/* instruction vector prefix register */
73#define SPR_IVLIM	0x399	/* instruction cache victim limit */
74
75#define SPR_MCSRR0	0x23A	/* 440GX only */
76#define SPR_MCSRR1	0x23B
77#define SPR_MCSR	0x23C
78
79#define SPR_DEC		0x16	/* on 440 they've gone back to using DEC instead of PIT  ... */
80#define SPR_DECAR	0x36	/* ... with the auto-reload register now visible */
81
82/* 440 */
83
84/* use of SPRG registers in save/restore */
85#define	SAVER0	SPR_SPRG0
86#define	SAVER1	SPR_SPRG1
87#define	SAVELR	SPR_SPRG2
88#define	SAVEXX	SPR_SPRG3
89
90/* special instruction definitions */
91#define	BDNZ	BC	16,0,
92#define	BDNE	BC	0,2,
93
94#define	TBRL	268	/* read time base lower in MFTB */
95#define	TBRU	269	/* read time base upper in MFTB */
96#define	MFTB(tbr,d)	WORD	$((31<<26)|((d)<<21)|((tbr&0x1f)<<16)|(((tbr>>5)&0x1f)<<11)|(371<<1))
97
98//#define TLBIA		WORD	$((31<<26)|(370<<1))	// not in 440
99#define	TLBSYNC		WORD	$((31<<26)|(566<<1))
100
101/* 400 models; perhaps others */
102#define	ICCCI(a,b)	WORD	$((31<<26)|((a)<<16)|((b)<<11)|(966<<1))
103#define	DCCCI(a,b)	WORD	$((31<<26)|((a)<<16)|((b)<<11)|(454<<1))
104/* these follow the source -> dest ordering */
105#define	DCREAD(s,t)	WORD	$((31<<26)|((t)<<21)|((s)<<11)|(486<<1))
106#define	DCRF(n)	((((n)>>5)&0x1F)|(((n)&0x1F)<<5))
107#define	MTDCR(s,n)	WORD	$((31<<26)|((s)<<21)|(DCRF(n)<<11)|(451<<1))
108#define	MFDCR(n,t)	WORD	$((31<<26)|((t)<<21)|(DCRF(n)<<11)|(323<<1))
109#define	MSYNC		WORD	$((31<<26)|(598<<1))
110#define	TLBRELO(a,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|(2<<11)|(946<<1))
111#define	TLBREMD(a,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|(1<<11)|(946<<1))
112#define	TLBREHI(a,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|(0<<11)|(946<<1))
113#define	TLBWELO(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(2<<11)|(978<<1))
114#define	TLBWEMD(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(1<<11)|(978<<1))
115#define	TLBWEHI(s,a)	WORD	$((31<<26)|((s)<<21)|((a)<<16)|(0<<11)|(978<<1))
116#define	TLBSXF(a,b,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|((b)<<11)|(914<<1))
117#define	TLBSXCC(a,b,t)	WORD	$((31<<26)|((t)<<21)|((a)<<16)|((b)<<11)|(914<<1)|1)
118/* these are useless because there aren't CE/CEI equivalents for critical interrupts */
119//#define	WRTMSR_EE(s)	WORD	$((31<<26)|((s)<<21)|(131<<1))
120//#define	WRTMSR_EEI(e)	WORD	$((31<<26)|((e)<<15)|(163<<1))
121
122/* on some models mtmsr doesn't synchronise enough (eg, 603e) */
123#define	MSRSYNC	MSYNC; ISYNC
124
125/*
126 * on the 4xx series, the prefetcher madly fetches across RFI, sys call,
127 * and others; use BR 0(PC) to stop.
128 */
129#define	RFI		WORD $((19<<26)|(50<<1)); BR 0(PC)
130// #define	RFCI	WORD	$((19<<26)|(51<<1)); BR 0(PC)
131
132/*
133 * print progress character iff on cpu0.
134 * steps on R7 and R8, needs SB set and TLB entry for i/o registers set.
135 */
136#define STEP(c, zero, notzero) \
137	MOVW	SPR(SPR_PIR), R7; \
138	CMP	R7, R0; \
139	BEQ	zero; \
140	CMP	R7, $017; \
141	BNE	notzero; \
142zero:	MOVW	$(Uartlite+4), R7; \
143	MOVW	$(c), R8; \
144	MOVW	R8, 0(R7); \
145notzero: SYNC
146
147//#define STEP(c, z, nz)
148#define PROG(n)	MOVW $(n), R18		/* pre-uart progress indicator */
149
150#define	UREGSPACE	(UREGSIZE+8)
151
152	NOSCHED
153
154TEXT start<>(SB), 1, $-4
155PROG(1)
156	/* except during trap handling, R0 is zero from now on */
157	MOVW	$0, R0
158
159	/*
160	 * setup MSR
161	 * turn off interrupts (clear ME, CE)
162	 * use 0x000 as exception prefix
163	 * enable kernel vm (clear IS, DS)
164	 * clear, then enable machine checks
165	 */
166	MOVW	$~0, R3
167	MOVW	R3, SPR(SPR_MCSR)	/* clear all bits */
168	MSRSYNC
169	MOVW	R0, SPR(SPR_ESR)
170	MSRSYNC
171PROG(2)
172	MOVW	$MSR_ME, R3
173	MOVW	R3, MSR
174	MSRSYNC
175	MOVW	R0, CR
176
177	/* setup SB for pre mmu */
178	MOVW	$setSB(SB), R2
179
180	MOVW	$19, R19
181	MOVW	$20, R20
182	MOVW	$21, R21
183	MOVW	$22, R22
184	MOVW	$23, R23
185	MOVW	$24, R24
186PROG(3)
187#ifndef MICROBOOT
188	/*
189	 * Invalidate the caches.
190	 */
191	ICCCI(0, 2)  /* errata cpu_121 reveals that EA is used; we'll use SB */
192	DCCCI(0, 2)		/* dcache must not be in use */
193	MSYNC
194#endif
195	MOVW	R0, SPR(SPR_DBCR0)
196	MOVW	R0, SPR(SPR_DBCR1)
197	MOVW	R0, SPR(SPR_DBCR2)
198	ISYNC
199	MOVW	$~0, R3
200	MOVW	R3, SPR(SPR_DBSR)
201
202	/*
203	 * CCR0:
204	 *	recover from data parity = 1
205	 *	disable gathering = 0
206	 *	disable trace broadcast = 1
207	 *	force load/store alignment = 0 (was 1)
208	 *	0: fill 1+0 speculative lines on icache miss
209	 * CCR1:
210	 *	normal parity, normal cache operation
211	 *	cpu timer advances with tick of CPU input clock (not timer clock)   TO DO?
212	 */
213#ifndef MICROBOOT
214	MOVW	$((1<<30)|(0<<21)|(1<<15)|(0<<8)|(0<<2)), R3
215	MOVW	R3, SPR(SPR_CCR0)
216	MOVW	$(0<<7), R3	/* TCS=0 */
217	MOVW	R3, SPR(SPR_CCR1)
218#endif
219	/* clear i/d cache regions */
220	MOVW	R0, SPR(SPR_INV0)
221	MOVW	R0, SPR(SPR_INV1)
222	MOVW	R0, SPR(SPR_INV2)
223	MOVW	R0, SPR(SPR_INV3)
224	MOVW	R0, SPR(SPR_DNV0)
225	MOVW	R0, SPR(SPR_DNV1)
226	MOVW	R0, SPR(SPR_DNV2)
227	MOVW	R0, SPR(SPR_DNV3)
228
229	/* set i/d cache limits (all normal) */
230	MOVW	$((0<<22)|(63<<11)|(0<<0)), R3	/* TFLOOR=0, TCEILING=63 ways, NFLOOR = 0 */
231	MOVW	R3, SPR(SPR_DVLIM)
232	MOVW	R3, SPR(SPR_IVLIM)
233
234PROG(4)
235	/*
236	 * set other system configuration values
237	 */
238	MOVW	R0, SPR(SPR_TBL)
239	MOVW	R0, SPR(SPR_TBU)
240	MOVW	R0, SPR(SPR_DEC)
241	MOVW	$~0, R3
242	MOVW	R3, SPR(SPR_TSR)
243	MOVW	R0, SPR(SPR_TCR)
244	ISYNC
245
246	/*
247	 * on the 440, the mmu is always on; kernelmmu just adds tlb entries.
248	 * ppc440x5 cpu core manual §3.1 has the story about shadow
249	 * tlbs and the like at reset.
250	 */
251PROG(5)
252	BL	kernelmmu(SB)
253	/* now running with MMU initialised & in kernel address space */
254
255	TLBWEHI(0,0)
256	TLBWEMD(0,0)
257	TLBWELO(0,0)
258
259	MOVW	$setSB(SB), R2
260	/* it's now safe to print */
261STEP('\r', zerobootcr, notbootcr)
262STEP('\n', zerobootnl, notbootnl)
263STEP('P',  zerobootP,  notbootP)
264
265	/* make the vectors match the old values */
266	MOVW	$PHYSSRAM, R3
267	MOVW	R3, SPR(SPR_IVPR)	/* vector prefix at PHYSSRAM */
268	MOVW	$INT_CI, R3
269	MOVW	R3, SPR(SPR_IVOR(0))
270	MOVW	$INT_MCHECK, R3
271	MOVW	R3, SPR(SPR_IVOR(1))
272	MOVW	$INT_DSI, R3
273	MOVW	R3, SPR(SPR_IVOR(2))
274	MOVW	$INT_ISI, R3
275	MOVW	R3, SPR(SPR_IVOR(3))
276	MOVW	$INT_EI, R3
277	MOVW	R3, SPR(SPR_IVOR(4))
278	MOVW	$INT_ALIGN, R3
279	MOVW	R3, SPR(SPR_IVOR(5))
280	MOVW	$INT_PROG, R3
281	MOVW	R3, SPR(SPR_IVOR(6))
282	MOVW	$INT_FPU, R3
283	MOVW	R3, SPR(SPR_IVOR(7))	/* reserved (FPU?) */
284	MOVW	$INT_SYSCALL, R3
285	MOVW	R3, SPR(SPR_IVOR(8))	/* system call */
286	MOVW	$INT_TRACE, R3
287	MOVW	R3, SPR(SPR_IVOR(9))	/* reserved (trace?) */
288	MOVW	$INT_PIT, R3
289	MOVW	R3, SPR(SPR_IVOR(10))	/* decrementer */
290	MOVW	$INT_FIT, R3
291	MOVW	R3, SPR(SPR_IVOR(11))	/* fixed interval  */
292	MOVW	$INT_WDT, R3
293	MOVW	R3, SPR(SPR_IVOR(12))	/* watchdog */
294	MOVW	$INT_DMISS,	R3
295	MOVW	R3, SPR(SPR_IVOR(13))	/* data TLB */
296	MOVW	$INT_IMISS,	R3
297	MOVW	R3, SPR(SPR_IVOR(14))	/* instruction TLB */
298	MOVW	$INT_DEBUG,  R3
299	MOVW	R3, SPR(SPR_IVOR(15))	/* debug */
300STEP('l', zerobootl, notbootl)
301
302	/*
303	 * Set up SB, vector space (16KiB, 64KiB aligned),
304	 * extern registers (m->, up->) and stack.
305	 * Mach (and stack) will be cleared along with the
306	 * rest of BSS below if this is CPU#0.
307	 * Memstart is the first free memory location
308	 * after the kernel.
309	 */
310	/* set R2 to correct value */
311	MOVW	$setSB(SB), R2
312
313	/* invalidate the caches again to flush any addresses below KZERO */
314	ICCCI(0, 2)  /* errata cpu_121 reveals that EA is used; we'll use SB */
315	ISYNC
316
317	MOVW	SPR(SPR_PIR), R7
318	CMP	R7, $017
319	BNE	notcpu0b
320	MOVW	R0, R7
321notcpu0b:
322	CMP	R0, R7
323	BNE	notcpu0
324
325	/* set up Mach */
326	/* for cpu0 */
327	MOVW	$mach0(SB), R(MACH)
328	/* put stack in sram below microboot temporarily */
329	MOVW	$0xfffffe00, R1
330//	ADD	$(MACHSIZE-8), R(MACH), R1	/* set stack */
331
332//	SUB	$4, R(MACH), R3
333//	ADD	$4, R1, R4
334//clrmach:
335//	MOVWU	R0, 4(R3)
336//	CMP	R3, R4
337//	BNE	clrmach
338
339STEP('a', zeroboota, notboota)
340
341	MOVW	$PHYSSRAM, R6			/* vectors at bottom of sram */
342	MOVW	R0, R(USER)			/* up-> */
343	MOVW	R0, 0(R(MACH))
344
345_CPU0:						/* boot processor */
346	MOVW	$edata-4(SB), R3
347	MOVW	R1, R4				/* stop before microboot */
348_clrbss:					/* clear BSS */
349	MOVWU	R0, 4(R3)
350	CMP	R3, R4
351	BNE	_clrbss
352
353STEP('n', zerobootn, notbootn)
354//	MOVW	R4, memstart(SB)	/* start of unused memory */
355	MOVW	R0, memstart(SB)	/* start of unused memory: dram */
356	MOVW	R6, vectorbase(SB) /* 64KiB aligned vector base, for trapinit */
357
358STEP(' ', zerobootsp, notbootsp)
359	BL	main(SB)
360	BR	0(PC)   		/* paranoia -- not reached */
361
362notcpu0:
363	MOVW	$mach0(SB), R(MACH)
364	ADD	$(MACHSIZE-8), R(MACH)	/* cpu1 */
365	/* put stack in sram below microboot & cpu0's stack temporarily */
366	MOVW	$0xfffffb00, R1
367
368	/* give cpu0 time to set things up */
369	MOVW	$(10*1024*1024), R3
370spin:
371	SUB	$1, R3
372	CMP	R0, R3
373	BNE	spin
374
375	BL	main(SB)
376	BR	0(PC)   		/* paranoia -- not reached */
377
378
379GLOBL	mach0(SB), $(MAXMACH*BY2PG)
380
381TEXT	kernelmmu(SB), 1, $-4
382PROG(6)
383#ifndef MICROBOOT
384	/* make following TLB entries shared, TID=PID=0 */
385	MOVW	R0, SPR(SPR_PID)
386
387	/*
388	 * allocate cache on store miss, disable U1 as transient,
389	 * disable U2 as SWOA, no dcbf or icbi exception, tlbsx search 0.
390	 */
391	MOVW	R0, SPR(SPR_MMUCR)
392	ISYNC
393#endif
394
395	/* map various things 1:1 */
396	MOVW	$tlbtab(SB), R4
397	MOVW	$tlbtabe(SB), R5
398	MOVW	$(3*4), R6	/* sizeof a tlb entry */
399//	ADD	R6, R4		/* skip first 2 TLB entries in tlbtab */
400//	ADD	R6, R4		/* skip first 2 TLB entries in tlbtab */
401	SUB	R4, R5
402	DIVW	R6, R5		/* R5 gets # of tlb entries in table */
403	SUB	$4, R4		/* back up before MOVWU */
404	MOVW	R5, CTR
405	MOVW	$63, R3
406//	SUB	$2, R3		/* skip first 2 TLB entries in TLB (#62-63) */
407	SYNC
408	ISYNC
409PROG(7)
410ltlb:
411	MOVWU	4(R4), R5	/* TLBHI */
412	TLBWEHI(5,3)
413	MOVWU	4(R4), R5	/* TLBMD */
414	TLBWEMD(5,3)
415	MOVWU	4(R4), R5	/* TLBLO */
416	TLBWELO(5,3)
417	SUB	$1, R3
418	BDNZ	ltlb
419PROG(8)
420	/* clear all remaining entries to remove any aliasing from boot */
421#ifndef MICROBOOT
422	CMP	R3, R0
423	BEQ	cltlbe
424	MOVW	R0, R5
425cltlb:
426	/* can't use 0 (R0) as first operand */
427	TLBWEHI(5,3)
428	TLBWEMD(5,3)
429	TLBWELO(5,3)
430	SUB	$1, R3
431	CMP	R3, $0
432	BGE	cltlb
433cltlbe:
434#endif
435	SYNC
436	ISYNC			/* switch to new TLBs */
437PROG(9)
438#ifdef MICROBOOT
439	RETURN
440#else
441	/*
442	 * this is no longer true; the microboot has done this:
443	 * we're currently relying on the shadow I/D TLBs.  to switch to
444	 * the new TLBs, we need a synchronising instruction.
445	 */
446	MOVW	LR, R4
447	MOVW	R4, SPR(SPR_SRR0)
448	MOVW	MSR, R4
449	MOVW	R4, SPR(SPR_SRR1)
450	/*
451	 * resume in kernel mode in caller; R3 has the index of the first
452	 * unneeded TLB entry
453	 */
454	RFI
455#endif
456
457TEXT	tlbinval(SB), 1, $-4
458	TLBWEHI(0, 3)
459	TLBWEMD(0, 3)
460	TLBWELO(0, 3)
461	ISYNC
462	RETURN
463
464TEXT	splhi(SB), 1, $-4
465	MOVW	MSR, R3
466	RLWNM	$0, R3, $~MSR_EE, R4
467	RLWNM	$0, R4, $~MSR_CE, R4
468	MOVW	R4, MSR
469	MSRSYNC
470	MOVW	LR, R31
471	MOVW	R31, 4(R(MACH))	/* save PC in m->splpc */
472	RETURN
473
474TEXT	splx(SB), 1, $-4
475	MOVW	LR, R31
476	MOVW	R31, 4(R(MACH))	/* save PC in m->splpc */
477	/* fall though */
478
479TEXT	splxpc(SB), 1, $-4
480	MOVW	MSR, R4
481	RLWMI	$0, R3, $MSR_EE, R4
482	RLWMI	$0, R3, $MSR_CE, R4
483	MOVW	R4, MSR
484	MSRSYNC
485	RETURN
486
487TEXT	spllo(SB), 1, $-4
488	MOVW	MSR, R3
489	OR	$MSR_EE, R3, R4
490	OR	$MSR_CE, R4
491	MOVW	R4, MSR
492	MSRSYNC
493	RETURN
494
495TEXT	spldone(SB), 1, $-4
496	RETURN
497
498TEXT	islo(SB), 1, $-4
499	MOVW	MSR, R3
500	MOVW	$(MSR_EE|MSR_CE), R4
501	AND	R4, R3
502	RETURN
503
504/* invalidate region of i-cache */
505TEXT	icflush(SB), 1, $-4	/* icflush(virtaddr, count) */
506	MOVW	n+4(FP), R4
507	RLWNM	$0, R3, $~(ICACHELINESZ-1), R5
508	SUB	R5, R3
509	ADD	R3, R4
510	ADD	$(ICACHELINESZ-1), R4
511	SRAW	$ICACHELINELOG, R4
512	MOVW	R4, CTR
513icf0:	ICBI	(R5)
514	ADD	$ICACHELINESZ, R5
515	BDNZ	icf0
516	ISYNC
517	RETURN
518
519TEXT	sync(SB), 1, $0
520	SYNC
521	RETURN
522
523TEXT	isync(SB), 1, $0
524	ISYNC
525	RETURN
526
527/* write-back then invalidate region of d-cache */
528TEXT	dcflush(SB), 1, $-4	/* dcflush(virtaddr, count) */
529	MOVW	n+4(FP), R4
530	RLWNM	$0, R3, $~(DCACHELINESZ-1), R5
531	CMP	R4, $0
532	BLE	dcf1
533	SYNC
534	SUB	R5, R3
535	ADD	R3, R4
536	ADD	$(DCACHELINESZ-1), R4
537	SRAW	$DCACHELINELOG, R4
538	MOVW	R4, CTR
539dcf0:	DCBF	(R5)
540	ADD	$DCACHELINESZ, R5
541	BDNZ	dcf0
542dcf1:
543	SYNC
544	RETURN
545
546TEXT	cacheson(SB), 1, $-4
547	MOVW	$1, R3			/* return value: true iff caches on */
548	RETURN
549
550TEXT	cachesinvalidate(SB), 1, $-4
551	ICCCI(0, 2) /* errata cpu_121 reveals that EA is used; we'll use SB */
552	DCCCI(0, 2) /* dcache must not be in use (or just needs to be clean?) */
553	MSYNC
554	RETURN
555
556TEXT	getpit(SB), 1, $0
557	MOVW	SPR(SPR_DEC), R3	/* they've moved it back to DEC */
558	RETURN
559
560TEXT	putpit(SB), 1, $0
561	MOVW	R3, SPR(SPR_DEC)
562	MOVW	R3, SPR(SPR_DECAR)
563	RETURN
564
565TEXT	putpid(SB), 1, $0
566	MOVW	R3, SPR(SPR_PID)
567	MOVW	SPR(SPR_MMUCR), R4
568	RLWMI	$0, R3, $0xFF, R4
569	MOVW	R4, SPR(SPR_MMUCR)
570	RETURN
571
572TEXT	getpid(SB), 1, $0
573	MOVW	SPR(SPR_PID), R3
574	RETURN
575
576TEXT	getpir(SB), 1, $-4
577	MOVW	SPR(SPR_PIR), R3
578	CMP	R3, $017
579	BNE	normal
580	MOVW	R0, R3
581normal:
582	RETURN
583
584TEXT	putstid(SB), 1, $0
585	MOVW	SPR(SPR_MMUCR), R4
586	RLWMI	$0, R3, $0xFF, R4
587	MOVW	R4, SPR(SPR_MMUCR)
588	RETURN
589
590TEXT	getstid(SB), 1, $0
591	MOVW	SPR(SPR_MMUCR), R3
592	RLWNM	$0, R3, $0xFF, R3
593	RETURN
594
595TEXT	gettbl(SB), 1, $0
596	MFTB(TBRL, 3)
597	RETURN
598
599TEXT	gettbu(SB), 1, $0
600	MFTB(TBRU, 3)
601	RETURN
602
603TEXT	gettsr(SB), 1, $0
604	MOVW	SPR(SPR_TSR), R3
605	RETURN
606
607TEXT	puttsr(SB), 1, $0
608	MOVW	R3, SPR(SPR_TSR)
609	RETURN
610
611TEXT	puttcr(SB), 1, $0
612	MOVW	R3, SPR(SPR_TCR)
613	RETURN
614
615TEXT	getpvr(SB), 1, $0
616	MOVW	SPR(SPR_PVR), R3
617	RETURN
618
619TEXT	getmsr(SB), 1, $0
620	MOVW	MSR, R3
621	RETURN
622
623TEXT	putmsr(SB), 1, $0
624	SYNC
625	MOVW	R3, MSR
626	MSRSYNC
627	RETURN
628
629TEXT	getmcsr(SB), 1, $0
630	MOVW	SPR(SPR_MCSR), R3
631	RETURN
632
633TEXT	putmcsr(SB), 1, $-4
634	MOVW	R3, SPR(SPR_MCSR)
635	RETURN
636
637TEXT	getesr(SB), 1, $0
638	MOVW	SPR(SPR_ESR), R3
639	RETURN
640
641TEXT	putesr(SB), 1, $0
642	MOVW	R3, SPR(SPR_ESR)
643	RETURN
644
645TEXT	putevpr(SB), 1, $0
646	MOVW	R3, SPR(SPR_IVPR)
647	RETURN
648
649TEXT getccr0(SB), 1, $-4
650	MOVW	SPR(SPR_CCR0), R3
651	RETURN
652
653TEXT	setsp(SB), 1, $0
654	MOVW	R3, R1
655	RETURN
656
657TEXT	getsp(SB), 1, $0
658	MOVW	R1, R3
659	RETURN
660
661TEXT	getdear(SB), 1, $0
662	MOVW	SPR(SPR_DEAR), R3
663	RETURN
664
665TEXT	tas32(SB), 1, $0
666	SYNC
667	MOVW	R3, R4
668	MOVW	$0xdead,R5
669tas1:
670	DCBF	(R4)	/* fix for 603x bug */
671	LWAR	(R4), R3
672	CMP	R3, $0
673	BNE	tas0
674	STWCCC	R5, (R4)
675	BNE	tas1
676tas0:
677	SYNC
678	ISYNC
679	RETURN
680
681TEXT	eieio(SB), 1, $0
682	EIEIO
683	RETURN
684
685TEXT	syncall(SB), 1, $0
686	SYNC
687	ISYNC
688	RETURN
689
690TEXT	_xinc(SB), 1, $0	/* void _xinc(long *); */
691	MOVW	R3, R4
692xincloop:
693	DCBF	(R4)		/* fix for 603x bug */
694	LWAR	(R4), R3
695	ADD	$1, R3
696	STWCCC	R3, (R4)
697	BNE	xincloop
698	RETURN
699
700TEXT	_xdec(SB), 1, $0	/* long _xdec(long *); */
701	MOVW	R3, R4
702xdecloop:
703	DCBF	(R4)		/* fix for 603x bug */
704	LWAR	(R4), R3
705	ADD	$-1, R3
706	STWCCC	R3, (R4)
707	BNE	xdecloop
708	RETURN
709
710TEXT cas32(SB), 1, $0			/* int cas32(void*, u32int, u32int) */
711	MOVW	R3, R4			/* addr */
712	MOVW	old+4(FP), R5
713	MOVW	new+8(FP), R6
714	DCBF	(R4)			/* fix for 603x bug? */
715	LWAR	(R4), R3
716	CMP	R3, R5
717	BNE	 fail
718	STWCCC	R6, (R4)
719	BNE	 fail
720	MOVW	 $1, R3
721	RETURN
722fail:
723	MOVW	 $0, R3
724	RETURN
725
726TEXT	tlbwrx(SB), 1, $-4
727	MOVW	hi+4(FP), R5
728	MOVW	mid+8(FP), R6
729	MOVW	lo+12(FP), R7
730	MSYNC
731	TLBWEHI(5, 3)
732	TLBWEMD(6, 3)
733	TLBWELO(7, 3)
734	ISYNC
735	RETURN
736
737TEXT	tlbrehi(SB), 1, $-4
738	TLBREHI(3, 3)
739	RETURN
740
741TEXT	tlbremd(SB), 1, $-4
742	TLBREMD(3, 3)
743	RETURN
744
745TEXT	tlbrelo(SB), 1, $-4
746	TLBRELO(3, 3)
747	RETURN
748
749TEXT	tlbsxcc(SB), 1, $-4
750	TLBSXCC(0, 3, 3)
751	BEQ	tlbsxcc0
752	MOVW	$-1, R3	/* not found */
753tlbsxcc0:
754	RETURN
755
756TEXT	gotopc(SB), 1, $0
757	MOVW	R3, CTR
758	MOVW	LR, R31	/* for trace back */
759	BR	(CTR)
760
761
762/*
763 * following Book E, traps thankfully leave the mmu on.
764 * the following code has been executed at the exception
765 * vector location already:
766 *	MOVW R0, SPR(SAVER0)
767 *	MOVW LR, R0
768 *	MOVW R0, SPR(SAVELR)
769 *	BL	trapvec(SB)
770 */
771TEXT	trapvec(SB), 1, $-4
772	MOVW	LR, R0
773	MOVW	R0, SPR(SAVEXX)	/* save ivoff--interrupt vector offset */
774/* entry point for critical interrupts, machine checks, and faults */
775trapcommon:
776	MOVW	R1, SPR(SAVER1)		/* save stack pointer */
777	/* did we come from user space? */
778	MOVW	SPR(SPR_SRR1), R0
779	MOVW	CR, R1
780	MOVW	R0, CR
781	BC	4,17,ktrap		/* if MSR[PR]=0, we are in kernel space */
782
783	/* switch to kernel stack */
784	MOVW	R1, CR
785
786	MOVW	SPR(SPR_SPRG7R), R1 /* up->kstack+KSTACK-UREGSPACE, set in touser and sysrforkret */
787
788	BL	saveureg(SB)
789	MOVW	$mach0(SB), R(MACH)
790	MOVW	8(R(MACH)), R(USER)
791	BL	trap(SB)
792	BR	restoreureg
793
794ktrap:
795	MOVW	R1, CR
796	MOVW	SPR(SAVER1), R1
797	SUB	$UREGSPACE, R1	/* push onto current kernel stack */
798	BL	saveureg(SB)
799	BL	trap(SB)
800
801restoreureg:
802	MOVMW	48(R1), R2	/* r2:r31 */
803	/* defer R1 */
804	MOVW	40(R1), R0
805	MOVW	R0, SPR(SAVER0)
806	MOVW	36(R1), R0
807	MOVW	R0, CTR
808	MOVW	32(R1), R0
809	MOVW	R0, XER
810	MOVW	28(R1), R0
811	MOVW	R0, CR	/* CR */
812	MOVW	24(R1), R0
813	MOVW	R0, LR
814	MOVW	20(R1), R0
815	MOVW	R0, SPR(SPR_SPRG7W)	/* kstack for traps from user space */
816	MOVW	16(R1), R0
817	MOVW	R0, SPR(SPR_SRR0)	/* old PC */
818	MOVW	12(R1), R0
819	RLWNM	$0, R0, $~MSR_WE, R0	/* remove wait state */
820	MOVW	R0, SPR(SPR_SRR1)	/* old MSR */
821	/* cause, skip */
822	MOVW	44(R1), R1	/* old SP */
823	MOVW	SPR(SAVER0), R0
824	RFI
825
826/*
827 * critical trap/interrupt.
828 * the only one we can take is machine check, synchronously, and
829 * outside any other trap handler.
830 * [MSR_ME not cleared => handler may be interrupted by machine check]
831 */
832TEXT	trapcritvec(SB), 1, $-4
833	MOVW	LR, R0
834	MOVW	R0, SPR(SAVEXX)
835	MOVW	SPR(SPR_CSRR0), R0		/* PC or excepting insn */
836	MOVW	R0, SPR(SPR_SRR0)
837	MOVW	SPR(SPR_CSRR1), R0		/* old MSR */
838	MOVW	R0, SPR(SPR_SRR1)
839	BR	trapcommon
840
841/*
842 * machine check.
843 * make it look like the others.
844 */
845TEXT	trapmvec(SB), 1, $-4
846	MOVW	LR, R0
847	MOVW	R0, SPR(SAVEXX)
848	MOVW	SPR(SPR_MCSRR0), R0		/* PC or excepting insn */
849	MOVW	R0, SPR(SPR_SRR0)
850	MOVW	SPR(SPR_MCSRR1), R0		/* old MSR */
851	MOVW	R0, SPR(SPR_SRR1)
852	BR	trapcommon
853
854/*
855 * enter with stack set and mapped.
856 * on return, SB (R2) has been set, and R3 has the Ureg*,
857 * the MMU has been re-enabled, kernel text and PC are in KSEG,
858 * Stack (R1), R(MACH) and R(USER) are set by caller, if required.
859 */
860TEXT	saveureg(SB), 1, $-4
861/*
862 * save state
863 */
864	MOVMW	R2, 48(R1)		/* save gprs r2 to r31 */
865	MOVW	$setSB(SB), R2
866	MOVW	SPR(SAVER1), R4
867	MOVW	R4, 44(R1)
868	MOVW	SPR(SAVER0), R5
869	MOVW	R5, 40(R1)
870	MOVW	CTR, R6
871	MOVW	R6, 36(R1)
872	MOVW	XER, R4
873	MOVW	R4, 32(R1)
874	MOVW	CR, R5
875	MOVW	R5, 28(R1)
876	MOVW	SPR(SAVELR), R6	/* LR */
877	MOVW	R6, 24(R1)
878	MOVW	SPR(SPR_SPRG7R), R6	/* up->kstack+KSTACK-UREGSPACE */
879	MOVW	R6, 20(R1)
880	MOVW	SPR(SPR_SRR0), R0
881	MOVW	R0, 16(R1)		/* PC of excepting insn (or next insn) */
882	MOVW	SPR(SPR_SRR1), R0
883	MOVW	R0, 12(R1)		/* old MSR */
884	MOVW	SPR(SAVEXX), R0
885	MOVW	R0, 8(R1)		/* cause/vector */
886	ADD	$8, R1, R3		/* Ureg* */
887	STWCCC	R3, (R1)		/* break any pending reservations */
888	MOVW	$0, R0		/* compiler/linker expect R0 to be zero */
889	RETURN
890
891/*
892 * restore state from Ureg and return from trap/interrupt
893 */
894TEXT sysrforkret(SB), 1, $-4
895	MOVW	R1, 20(R1)	/* up->kstack+KSTACK-UREGSPACE set in ureg */
896	BR	restoreureg
897
898/*
899 * 4xx specific
900 */
901TEXT	firmware(SB), 1, $0
902	MOVW	$(3<<28), R3
903	MOVW	R3, SPR(SPR_DBCR0)	/* system reset */
904	BR	0(PC)
905