Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * mips 24k machine assist for routerboard rb450g
3
 */
4
#include "mem.h"
5
#include "mips.s"
6
 
7
#define SANITY 0x12345678
8
 
9
	NOSCHED
10
 
11
/*
12
 * Boot only processor
13
 */
14
TEXT	start(SB), $-4
15
	MOVW	$setR30(SB), R30
16
 
17
PUTC('9', R1, R2)
18
	DI(0)
19
 
20
	MOVW	sanity(SB), R1
21
	CONST(SANITY, R2)
22
	SUBU	R1, R2, R2
23
	BNE	R2, insane
24
	NOP
25
 
26
	MOVW	R0, M(COMPARE)
27
	EHB
28
 
29
	/* don't enable any interrupts nor FP, but leave BEV on. */
30
	MOVW	$BEV,R1
31
	MOVW	R1, M(STATUS)
32
	UBARRIERS(7, R7, stshb)		/* returns to kseg1 space */
33
	MOVW	R0, M(CAUSE)
34
	EHB
35
 
36
	/* silence the atheros watchdog */
37
	MOVW	$(KSEG1|0x18060008), R1
38
	MOVW	R0, (R1)			/* set no action */
39
	SYNC
40
 
41
	MOVW	$PE, R1
42
	MOVW	R1, M(CACHEECC)		/* aka ErrCtl */
43
	EHB
44
	JAL	cleancache(SB)
45
	NOP
46
 
47
	MOVW	$TLBROFF, R1
48
	MOVW	R1, M(WIRED)
49
 
50
	MOVW	R0, M(CONTEXT)
51
	EHB
52
 
53
	/* set KSEG0 cachability before trying LL/SC in lock code */
54
	MOVW	M(CONFIG), R1
55
	AND	$~CFG_K0, R1
56
	/* make kseg0 cachable, enable write-through merging */
57
	OR	$((PTECACHABILITY>>3)|CFG_MM), R1
58
	MOVW	R1, M(CONFIG)
59
	BARRIERS(7, R7, cfghb)			/* back to kseg0 space */
60
 
61
	MOVW	$setR30(SB), R30		/* again */
62
 
63
	/* initialize Mach, including stack */
64
	MOVW	$MACHADDR, R(MACH)
65
	ADDU	$(MACHSIZE-BY2V), R(MACH), SP
66
	MOVW	R(MACH), R1
67
clrmach:
68
	MOVW	R0, (R1)
69
	ADDU	$BY2WD, R1
70
	BNE	R1, SP, clrmach
71
	NOP
72
	MOVW	R0, 0(R(MACH))			/* m->machno = 0 */
73
	MOVW	R0, R(USER)			/* up = nil */
74
 
75
	/* zero bss, byte-by-byte */
76
	MOVW	$edata(SB), R1
77
	MOVW	$end(SB), R2
78
clrbss:
79
	MOVB	R0, (R1)
80
	ADDU	$1, R1
81
	BNE	R1, R2, clrbss
82
	NOP
83
 
84
	MOVW	$0x16, R16
85
	MOVW	$0x17, R17
86
	MOVW	$0x18, R18
87
	MOVW	$0x19, R19
88
	MOVW	$0x20, R20
89
	MOVW	$0x21, R21
90
	MOVW	$0x22, R22
91
	MOVW	$0x23, R23
92
 
93
	MOVW	R0, HI
94
	MOVW	R0, LO
95
 
96
PUTC('\r', R1, R2)
97
PUTC('\n', R1, R2)
98
	JAL	main(SB)
99
	NOP
100
	CONST(ROM, R1)
101
	JMP	(R1)			/* back to the rom */
102
 
103
#define PUT(c) PUTC(c, R1, R2)
104
#define DELAY(lab) \
105
	CONST(34000000, R3); \
106
lab:	SUBU	$1, R3; \
107
	BNE	R3, lab; \
108
	NOP
109
 
110
insane:
111
	/*
112
	 * data segment is misaligned; kernel needs vl -R4096 or -R16384,
113
	 * as appropriate, for reboot.
114
	 */
115
	PUT('?'); PUT('d'); PUT('a'); PUT('t'); PUT('a'); PUT(' '); DELAY(dl1)
116
	PUT('s'); PUT('e'); PUT('g'); PUT('m'); PUT('e'); PUT('n'); DELAY(dl2)
117
	PUT('t'); PUT(' '); PUT('m'); PUT('i'); PUT('s'); PUT('a'); DELAY(dl3)
118
	PUT('l'); PUT('i'); PUT('g'); PUT('n'); PUT('e'); PUT('d'); DELAY(dl4)
119
	PUT('\r'); PUT('\n'); DELAY(dl5)
120
	CONST(ROM, R1)
121
	JMP	(R1)			/* back to the rom */
122
	NOP
123
 
124
/* target for JALRHB in BARRIERS */
125
TEXT ret(SB), $-4
126
	JMP	(R22)
127
	NOP
128
 
129
/* print R1 in hex; clobbers R3—8 */
130
TEXT printhex(SB), $-4
131
	MOVW	$32, R5
132
	MOVW	$9, R7
133
prtop:
134
	SUB	$4, R5
135
	MOVW	R1, R6
136
	SRL	R5, R6
137
	AND	$0xf, R6
138
	SGTU	R6, R7, R8
139
	BEQ	R8, prdec		/* branch if R6 <= 9 */
140
	NOP
141
	ADD	$('a'-10), R6
142
	JMP	prchar
143
	NOP
144
prdec:
145
	ADD	$'0', R6
146
prchar:
147
	PUTC(R6, R3, R4)
148
	BNE	R5, prtop
149
	NOP
150
	RETURN
151
 
152
/*
153
 * Take first processor into user mode
154
 * 	- argument is stack pointer to user
155
 */
156
TEXT	touser(SB), $-4
157
	MOVW	R1, SP
158
	MOVW	$(UTZERO+32), R2	/* header appears in text */
159
	MOVW	R2, M(EPC)
160
	EHB
161
	MOVW	M(STATUS), R4
162
	AND	$(~KMODEMASK), R4
163
	OR	$(KUSER|IE|EXL), R4	/* switch to user mode, intrs on, exc */
164
	MOVW	R4, M(STATUS)		/* " */
165
	ERET				/* clears EXL */
166
 
167
/*
168
 * manipulate interrupts
169
 */
170
 
171
/* enable an interrupt; bit is in R1 */
172
TEXT	intron(SB), $0
173
	MOVW	M(STATUS), R2
174
	OR	R1, R2
175
	MOVW	R2, M(STATUS)
176
	EHB
177
	RETURN
178
 
179
/* disable an interrupt; bit is in R1 */
180
TEXT	introff(SB), $0
181
	MOVW	M(STATUS), R2
182
	XOR	$-1, R1
183
	AND	R1, R2
184
	MOVW	R2, M(STATUS)
185
	EHB
186
	RETURN
187
 
188
/* on our 24k, wait instructions are not interruptible, alas. */
189
TEXT	idle(SB), $-4
190
	EI(1)				/* old M(STATUS) into R1 */
191
	EHB
192
	/* fall through */
193
 
194
TEXT	wait(SB), $-4
195
	WAIT
196
	NOP
197
 
198
	MOVW	R1, M(STATUS)		/* interrupts restored */
199
	EHB
200
	RETURN
201
 
202
TEXT	splhi(SB), $0
203
	EHB
204
	MOVW	R31, 12(R(MACH))	/* save PC in m->splpc */
205
	DI(1)				/* old M(STATUS) into R1 */
206
	EHB
207
	RETURN
208
 
209
TEXT	splx(SB), $0
210
	EHB
211
	MOVW	R31, 12(R(MACH))	/* save PC in m->splpc */
212
	MOVW	M(STATUS), R2
213
	AND	$IE, R1
214
	AND	$~IE, R2
215
	OR	R2, R1
216
	MOVW	R1, M(STATUS)
217
	EHB
218
	RETURN
219
 
220
TEXT	spllo(SB), $0
221
	EHB
222
	EI(1)				/* old M(STATUS) into R1 */
223
	EHB
224
	RETURN
225
 
226
TEXT	spldone(SB), $0
227
	RETURN
228
 
229
TEXT	islo(SB), $0
230
	MOVW	M(STATUS), R1
231
	AND	$IE, R1
232
	RETURN
233
 
234
TEXT	coherence(SB), $-4
235
	BARRIERS(7, R7, cohhb)
236
	SYNC
237
	EHB
238
	RETURN
239
 
240
/*
241
 * process switching
242
 */
243
 
244
TEXT	setlabel(SB), $-4
245
	MOVW	R29, 0(R1)
246
	MOVW	R31, 4(R1)
247
	MOVW	R0, R1
248
	RETURN
249
 
250
TEXT	gotolabel(SB), $-4
251
	MOVW	0(R1), R29
252
	MOVW	4(R1), R31
253
	MOVW	$1, R1
254
	RETURN
255
 
256
/*
257
 * the tlb routines need to be called at splhi.
258
 */
259
 
260
TEXT	puttlb(SB), $0			/* puttlb(virt, phys0, phys1) */
261
	EHB
262
	MOVW	R1, M(TLBVIRT)
263
	EHB
264
	MOVW	4(FP), R2		/* phys0 */
265
	MOVW	8(FP), R3		/* phys1 */
266
	MOVW	R2, M(TLBPHYS0)
267
	EHB
268
	MOVW	$PGSZ, R1
269
	MOVW	R3, M(TLBPHYS1)
270
	EHB
271
	MOVW	R1, M(PAGEMASK)
272
	OR	R2, R3, R4		/* MTC0 delay slot */
273
	AND	$PTEVALID, R4		/* MTC0 delay slot */
274
	EHB
275
	TLBP				/* tlb probe */
276
	EHB
277
	MOVW	M(INDEX), R1
278
	BGEZ	R1, index		/* if tlb entry found, use it */
279
	NOP
280
	BEQ	R4, dont		/* not valid? cf. kunmap */
281
	NOP
282
	MOVW	M(RANDOM), R1		/* write random tlb entry */
283
	MOVW	R1, M(INDEX)
284
index:
285
	EHB
286
	TLBWI				/* write indexed tlb entry */
287
	JRHB(31)			/* return and clear all hazards */
288
dont:
289
	RETURN
290
 
291
TEXT	getwired(SB),$0
292
	MOVW	M(WIRED), R1
293
	RETURN
294
 
295
TEXT	setwired(SB),$0
296
	MOVW	R1, M(WIRED)
297
	EHB
298
	RETURN
299
 
300
TEXT	getrandom(SB),$0
301
	MOVW	M(RANDOM), R1
302
	RETURN
303
 
304
TEXT	getpagemask(SB),$0
305
	MOVW	M(PAGEMASK), R1
306
	RETURN
307
 
308
TEXT	setpagemask(SB),$0
309
	EHB
310
	MOVW	R1, M(PAGEMASK)
311
	EHB
312
	MOVW	R0, R1			/* prevent accidents */
313
	RETURN
314
 
315
TEXT	puttlbx(SB), $0	/* puttlbx(index, virt, phys0, phys1, pagemask) */
316
	MOVW	4(FP), R2
317
	MOVW	8(FP), R3
318
	MOVW	12(FP), R4
319
	MOVW	16(FP), R5
320
	EHB
321
	MOVW	R2, M(TLBVIRT)
322
	EHB
323
	MOVW	R3, M(TLBPHYS0)
324
	MOVW	R4, M(TLBPHYS1)
325
	MOVW	R5, M(PAGEMASK)
326
	EHB
327
	MOVW	R1, M(INDEX)
328
	EHB
329
	TLBWI				/* write indexed tlb entry */
330
	JRHB(31)			/* return and clear all hazards */
331
 
332
TEXT	tlbvirt(SB), $0
333
	EHB
334
	MOVW	M(TLBVIRT), R1
335
	EHB
336
	RETURN
337
 
338
TEXT	gettlbx(SB), $0			/* gettlbx(index, &entry) */
339
	MOVW	4(FP), R5
340
	MOVW	M(TLBVIRT), R10		/* save our asid */
341
	EHB
342
	MOVW	R1, M(INDEX)
343
	EHB
344
	TLBR				/* read indexed tlb entry */
345
	EHB
346
	MOVW	M(TLBVIRT), R2
347
	MOVW	M(TLBPHYS0), R3
348
	MOVW	M(TLBPHYS1), R4
349
	MOVW	R2, 0(R5)
350
	MOVW	R3, 4(R5)
351
	MIPS24KNOP
352
	MOVW	R4, 8(R5)
353
	EHB
354
	MOVW	R10, M(TLBVIRT)		/* restore our asid */
355
	EHB
356
	RETURN
357
 
358
TEXT	gettlbp(SB), $0			/* gettlbp(tlbvirt, &entry) */
359
	MOVW	4(FP), R5
360
	MOVW	M(TLBVIRT), R10		/* save our asid */
361
	EHB
362
	MOVW	R1, M(TLBVIRT)
363
	EHB
364
	TLBP				/* probe tlb */
365
	EHB
366
	MOVW	M(INDEX), R1
367
	BLTZ	R1, gettlbp1		/* if no tlb entry found, return */
368
	NOP
369
	EHB
370
	TLBR				/* read indexed tlb entry */
371
	EHB
372
	MOVW	M(TLBVIRT), R2
373
	MOVW	M(TLBPHYS0), R3
374
	MOVW	M(TLBPHYS1), R4
375
	MOVW	M(PAGEMASK), R6
376
	MOVW	R2, 0(R5)
377
	MOVW	R3, 4(R5)
378
	MIPS24KNOP
379
	MOVW	R4, 8(R5)
380
	MOVW	R6, 12(R5)
381
gettlbp1:
382
	EHB
383
	MOVW	R10, M(TLBVIRT)		/* restore our asid */
384
	EHB
385
	RETURN
386
 
387
TEXT	gettlbvirt(SB), $0		/* gettlbvirt(index) */
388
	MOVW	M(TLBVIRT), R10		/* save our asid */
389
	EHB
390
	MOVW	R1, M(INDEX)
391
	EHB
392
	TLBR				/* read indexed tlb entry */
393
	EHB
394
	MOVW	M(TLBVIRT), R1
395
	EHB
396
	MOVW	R10, M(TLBVIRT)		/* restore our asid */
397
	EHB
398
	RETURN
399
 
400
/*
401
 * exceptions.
402
 * mips promises that there will be no current hazards upon entry
403
 * to exception handlers.
404
 */
405
 
406
TEXT	vector0(SB), $-4
407
	MOVW	$utlbmiss(SB), R26
408
	JMP	(R26)
409
	NOP
410
 
411
/*
412
 * compute stlb hash index.
413
 * must match index calculation in mmu.c/putstlb()
414
 *
415
 * M(TLBVIRT) [page & asid] in arg, result in arg.
416
 * stir in swizzled asid; we get best results with asid in both high & low bits.
417
 *
418
 * page = tlbvirt >> (PGSHIFT+1);	// ignoring even/odd bit
419
 * R27 = ((tlbvirt<<(STLBLOG-8) ^ (uchar)tlbvirt ^ page ^
420
 *	((page & (MASK(HIPFNBITS) << STLBLOG)) >> HIPFNBITS)) &
421
 *	(STLBSIZE-1)) * 12;
422
 */
423
#define STLBHASH(arg, tmp, tmp2) \
424
	MOVW	arg, tmp2; \
425
	SRL	$(PGSHIFT+1), arg;	/* move low page # bits to low bits */ \
426
	CONST	((MASK(HIPFNBITS) << STLBLOG), tmp); \
427
	AND	arg, tmp;		/* extract high page # bits */ \
428
	SRL	$HIPFNBITS, tmp;	/* position them */ \
429
	XOR	tmp, arg;		/* include them */ \
430
	MOVW	tmp2, tmp;		/* asid in low byte */ \
431
	SLL	$(STLBLOG-8), tmp;	/* move asid to high bits */ \
432
	XOR	tmp, arg;		/* include asid in high bits too */ \
433
	AND	$0xff, tmp2, tmp;	/* asid in low byte */ \
434
	XOR	tmp, arg;		/* include asid in low bits */ \
435
	CONST	(STLBSIZE-1, tmp); \
436
	AND	tmp, arg		/* chop to fit */
437
 
438
TEXT	utlbmiss(SB), $-4
439
	/*
440
	 * don't use R28 by using constants that span both word halves,
441
	 * it's unsaved so far.  avoid R24 (up in kernel) and R25 (m in kernel).
442
	 */
443
	/* update statistics */
444
	CONST	(MACHADDR, R26)		/* R26 = m-> */
445
	MOVW	16(R26), R27
446
	ADDU	$1, R27
447
	MOVW	R27, 16(R26)		/* m->tlbfault++ */
448
 
449
	MOVW	R23, M(DESAVE)		/* save R23 */
450
 
451
#ifdef	KUTLBSTATS
452
	MOVW	M(STATUS), R23
453
	AND	$KUSER, R23
454
	BEQ	R23, kmiss
455
 
456
	MOVW	24(R26), R27
457
	ADDU	$1, R27
458
	MOVW	R27, 24(R26)		/* m->utlbfault++ */
459
	JMP	either
460
kmiss:
461
	MOVW	20(R26), R27
462
	ADDU	$1, R27
463
	MOVW	R27, 20(R26)		/* m->ktlbfault++ */
464
either:
465
#endif
466
 
467
	/* compute stlb index */
468
	EHB
469
	MOVW	M(TLBVIRT), R27		/* asid in low byte */
470
	STLBHASH(R27, R26, R23)
471
	MOVW	M(DESAVE), R23		/* restore R23 */
472
 
473
	/* scale to a byte index (multiply by 12) */
474
	SLL	$1, R27, R26		/* × 2 */
475
	ADDU	R26, R27		/* × 3 */
476
	SLL	$2, R27			/* × 12 */
477
 
478
	CONST	(MACHADDR, R26)		/* R26 = m-> */
479
	MOVW	4(R26), R26		/* R26 = m->stb */
480
	ADDU	R26, R27		/* R27 = &m->stb[hash] */
481
 
482
	MOVW	M(BADVADDR), R26
483
	AND	$BY2PG, R26
484
	BNE	R26, utlbodd		/* odd page? */
485
	NOP
486
 
487
utlbeven:
488
	MOVW	4(R27), R26		/* R26 = m->stb[hash].phys0 */
489
	BEQ	R26, stlbm		/* nothing cached? do it the hard way */
490
	NOP
491
	MOVW	R26, M(TLBPHYS0)
492
	EHB
493
	MOVW	8(R27), R26		/* R26 = m->stb[hash].phys1 */
494
	JMP	utlbcom
495
	MOVW	R26, M(TLBPHYS1)	/* branch delay slot */
496
 
497
utlbodd:
498
	MOVW	8(R27), R26		/* R26 = m->stb[hash].phys1 */
499
	BEQ	R26, stlbm		/* nothing cached? do it the hard way */
500
	NOP
501
	MOVW	R26, M(TLBPHYS1)
502
	EHB
503
	MOVW	4(R27), R26		/* R26 = m->stb[hash].phys0 */
504
	MOVW	R26, M(TLBPHYS0)
505
 
506
utlbcom:
507
	EHB				/* MTC0/MFC0 hazard */
508
	MOVW	M(TLBVIRT), R26
509
	MOVW	(R27), R27		/* R27 = m->stb[hash].virt */
510
	BEQ	R27, stlbm		/* nothing cached? do it the hard way */
511
	NOP
512
	/* is the stlb entry for the right virtual address? */
513
	BNE	R26, R27, stlbm		/* M(TLBVIRT) != m->stb[hash].virt? */
514
	NOP
515
 
516
	/* if an entry exists, overwrite it, else write a random one */
517
	CONST	(PGSZ, R27)
518
	MOVW	R27, M(PAGEMASK)	/* select page size */
519
	EHB
520
	TLBP				/* probe tlb */
521
	EHB
522
	MOVW	M(INDEX), R26
523
	BGEZ	R26, utlindex		/* if tlb entry found, rewrite it */
524
	EHB				/* delay slot */
525
	TLBWR				/* else write random tlb entry */
526
	ERET
527
utlindex:
528
	TLBWI				/* write indexed tlb entry */
529
	ERET
530
 
531
/* not in the stlb either; make trap.c figure it out */
532
stlbm:
533
	MOVW	$exception(SB), R26
534
	JMP	(R26)
535
	NOP
536
 
537
TEXT	stlbhash(SB), $-4
538
	STLBHASH(R1, R2, R3)
539
	RETURN
540
 
541
TEXT	vector100(SB), $-4
542
	MOVW	$exception(SB), R26
543
	JMP	(R26)
544
	NOP
545
 
546
TEXT	vector180(SB), $-4
547
	MOVW	$exception(SB), R26
548
	JMP	(R26)
549
	NOP
550
 
551
TEXT	exception(SB), $-4
552
	MOVW	M(STATUS), R26
553
	AND	$KUSER, R26, R27
554
	BEQ	R27, waskernel
555
	MOVW	SP, R27			/* delay slot */
556
 
557
wasuser:
558
	CONST	(MACHADDR, SP)		/*  m-> */
559
	MOVW	8(SP), SP		/*  m->proc */
560
	MOVW	8(SP), SP		/*  m->proc->kstack */
561
	MOVW	M(STATUS), R26		/* redundant load */
562
	ADDU	$(KSTACK-UREGSIZE), SP
563
	MOVW	R31, Ureg_r31(SP)
564
 
565
	JAL	savereg1(SB)
566
	NOP
567
 
568
	MOVW	R30, Ureg_r30(SP)
569
	MOVW	R(MACH), Ureg_r25(SP)
570
	MIPS24KNOP
571
	MOVW	R(USER), Ureg_r24(SP)
572
 
573
	MOVW	$setR30(SB), R30
574
	CONST	(MACHADDR, R(MACH))		/* R(MACH) = m-> */
575
	MOVW	8(R(MACH)), R(USER)		/* up = m->proc */
576
 
577
	AND	$(EXCMASK<<2), R26, R1
578
	SUBU	$(CSYS<<2), R1
579
	BNE	R1, notsys
580
	NOP
581
 
582
	/* the carrera does this: */
583
//	ADDU	$8, SP, R1			/* first arg for syscall */
584
 
585
	MOVW	SP, R1				/* first arg for syscall */
586
	JAL	syscall(SB)
587
	SUBU	$Notuoffset, SP			/* delay slot */
588
sysrestore:
589
	JAL	restreg1(SB)
590
	ADDU	$Notuoffset, SP			/* delay slot */
591
 
592
	MOVW	Ureg_r31(SP), R31
593
	MOVW	Ureg_status(SP), R26
594
	MOVW	Ureg_r30(SP), R30
595
	MOVW	R26, M(STATUS)
596
	EHB
597
	MOVW	Ureg_pc(SP), R26		/* old pc */
598
	MOVW	Ureg_sp(SP), SP
599
	MOVW	R26, M(EPC)
600
	ERET
601
 
602
notsys:
603
	JAL	savereg2(SB)
604
	NOP
605
 
606
	/* the carrera does this: */
607
//	ADDU	$8, SP, R1			/* first arg for trap */
608
 
609
	MOVW	SP, R1				/* first arg for trap */
610
	JAL	trap(SB)
611
	SUBU	$Notuoffset, SP			/* delay slot */
612
 
613
	ADDU	$Notuoffset, SP
614
 
615
restore:
616
	JAL	restreg1(SB)
617
	NOP
618
	JAL	restreg2(SB)		/* restores R28, among others */
619
	NOP
620
 
621
	MOVW	Ureg_r30(SP), R30
622
	MOVW	Ureg_r31(SP), R31
623
	MOVW	Ureg_r25(SP), R(MACH)
624
	MOVW	Ureg_r24(SP), R(USER)
625
	MOVW	Ureg_sp(SP), SP
626
	MOVW	R26, M(EPC)
627
	ERET
628
 
629
waskernel:
630
	SUBU	$UREGSIZE, SP
631
	OR	$7, SP				/* conservative rounding */
632
	XOR	$7, SP
633
	MOVW	R31, Ureg_r31(SP)
634
 
635
	JAL	savereg1(SB)
636
	NOP
637
	JAL	savereg2(SB)
638
	NOP
639
 
640
	/* the carrera does this: */
641
//	ADDU	$8, SP, R1			/* first arg for trap */
642
 
643
	MOVW	SP, R1			/* first arg for trap */
644
	JAL	trap(SB)
645
	SUBU	$Notuoffset, SP			/* delay slot */
646
 
647
	ADDU	$Notuoffset, SP
648
 
649
	JAL	restreg1(SB)
650
	NOP
651
 
652
	/*
653
	 * if about to return to `wait', interrupt arrived just before
654
	 * executing wait, so move saved pc past it.
655
	 */
656
	MOVW	Ureg_pc(SP), R26
657
	MOVW	R26, R31
658
	MOVW	$wait(SB), R1
659
	SUBU	R1, R31
660
	BNE	R31, notwait
661
	NOP
662
	ADD	$BY2WD, R26		/* advance saved pc */
663
	MOVW	R26, Ureg_pc(SP)
664
notwait:
665
	JAL	restreg2(SB)		/* restores R28, among others */
666
	NOP
667
 
668
	MOVW	Ureg_r31(SP), R31
669
	MOVW	Ureg_sp(SP), SP
670
	MOVW	R26, M(EPC)
671
	ERET
672
 
673
TEXT	forkret(SB), $0
674
	JMP	sysrestore
675
	MOVW	R0, R1			/* delay slot; child returns 0 */
676
 
677
/*
678
 * save mandatory registers.
679
 * called with old M(STATUS) in R26.
680
 * called with old SP in R27
681
 * returns with M(CAUSE) in R26
682
 */
683
TEXT	savereg1(SB), $-4
684
	MOVW	R1, Ureg_r1(SP)
685
 
686
	MOVW	$(~KMODEMASK),R1	/* don't use R28, it's unsaved so far */
687
	AND	R26, R1
688
	MOVW	R1, M(STATUS)
689
	EHB
690
 
691
	MOVW	R26, Ureg_status(SP)	/* status */
692
	MOVW	R27, Ureg_sp(SP)	/* user SP */
693
 
694
	MOVW	M(EPC), R1
695
	MOVW	M(CAUSE), R26
696
 
697
	MOVW	R23, Ureg_r23(SP)
698
	MOVW	R22, Ureg_r22(SP)
699
	MIPS24KNOP
700
	MOVW	R21, Ureg_r21(SP)
701
	MOVW	R20, Ureg_r20(SP)
702
	MIPS24KNOP
703
	MOVW	R19, Ureg_r19(SP)
704
	MOVW	R1, Ureg_pc(SP)
705
	RETURN
706
 
707
/*
708
 * all other registers.
709
 * called with M(CAUSE) in R26
710
 */
711
TEXT	savereg2(SB), $-4
712
	MOVW	R2, Ureg_r2(SP)
713
 
714
	MOVW	M(BADVADDR), R2
715
	MOVW	R26, Ureg_cause(SP)
716
	MOVW	M(TLBVIRT), R1
717
	MOVW	R2, Ureg_badvaddr(SP)
718
	MOVW	R1, Ureg_tlbvirt(SP)
719
	MOVW	HI, R1
720
	MOVW	LO, R2
721
	MOVW	R1, Ureg_hi(SP)
722
	MOVW	R2, Ureg_lo(SP)
723
	MIPS24KNOP
724
					/* LINK,SB,SP missing */
725
	MOVW	R28, Ureg_r28(SP)
726
					/* R27, R26 not saved */
727
					/* R25, R24 missing */
728
					/* R23- R19 saved in save1 */
729
	MOVW	R18, Ureg_r18(SP)
730
	MIPS24KNOP
731
	MOVW	R17, Ureg_r17(SP)
732
	MOVW	R16, Ureg_r16(SP)
733
	MIPS24KNOP
734
	MOVW	R15, Ureg_r15(SP)
735
	MOVW	R14, Ureg_r14(SP)
736
	MIPS24KNOP
737
	MOVW	R13, Ureg_r13(SP)
738
	MOVW	R12, Ureg_r12(SP)
739
	MIPS24KNOP
740
	MOVW	R11, Ureg_r11(SP)
741
	MOVW	R10, Ureg_r10(SP)
742
	MIPS24KNOP
743
	MOVW	R9, Ureg_r9(SP)
744
	MOVW	R8, Ureg_r8(SP)
745
	MIPS24KNOP
746
	MOVW	R7, Ureg_r7(SP)
747
	MOVW	R6, Ureg_r6(SP)
748
	MIPS24KNOP
749
	MOVW	R5, Ureg_r5(SP)
750
	MOVW	R4, Ureg_r4(SP)
751
	MIPS24KNOP
752
	MOVW	R3, Ureg_r3(SP)
753
	RETURN
754
 
755
TEXT	restreg1(SB), $-4
756
	MOVW	Ureg_r23(SP), R23
757
	MOVW	Ureg_r22(SP), R22
758
	MOVW	Ureg_r21(SP), R21
759
	MOVW	Ureg_r20(SP), R20
760
	MOVW	Ureg_r19(SP), R19
761
	RETURN
762
 
763
TEXT	restreg2(SB), $-4
764
					/* LINK,SB,SP missing */
765
	MOVW	Ureg_r28(SP), R28
766
					/* R27, R26 not saved */
767
					/* R25, R24 missing */
768
					/* R19- R23 restored in rest1 */
769
	MOVW	Ureg_r18(SP), R18
770
	MOVW	Ureg_r17(SP), R17
771
	MOVW	Ureg_r16(SP), R16
772
	MOVW	Ureg_r15(SP), R15
773
	MOVW	Ureg_r14(SP), R14
774
	MOVW	Ureg_r13(SP), R13
775
	MOVW	Ureg_r12(SP), R12
776
	MOVW	Ureg_r11(SP), R11
777
	MOVW	Ureg_r10(SP), R10
778
	MOVW	Ureg_r9(SP), R9
779
	MOVW	Ureg_r8(SP), R8
780
	MOVW	Ureg_r7(SP), R7
781
	MOVW	Ureg_r6(SP), R6
782
	MOVW	Ureg_r5(SP), R5
783
	MOVW	Ureg_r4(SP), R4
784
	MOVW	Ureg_r3(SP), R3
785
	MOVW	Ureg_lo(SP), R2
786
	MOVW	Ureg_hi(SP), R1
787
	MOVW	R2, LO
788
	MOVW	R1, HI
789
 
790
	MOVW	Ureg_status(SP), R1
791
	MOVW	Ureg_r2(SP), R2
792
	MOVW	R1, M(STATUS)		/* could change interruptibility */
793
	EHB
794
	MOVW	Ureg_r1(SP), R1	/* BOTCH */
795
	MOVW	Ureg_pc(SP), R26
796
	RETURN
797
 
798
#ifdef OLD_MIPS_EXAMPLE
799
/* this appears to be a dreg from the distant past */
800
TEXT	rfnote(SB), $0
801
	MOVW	R1, R26			/* 1st arg is &uregpointer */
802
	JMP	restore
803
	SUBU	$(BY2WD), R26, SP	/* delay slot: pc hole */
804
#endif
805
 
806
/*
807
 * degenerate floating-point stuff
808
 */
809
 
810
TEXT	clrfpintr(SB), $0
811
	RETURN
812
 
813
TEXT	savefpregs(SB), $0
814
	RETURN
815
 
816
TEXT	restfpregs(SB), $0
817
	RETURN
818
 
819
TEXT	fcr31(SB), $0			/* fp csr */
820
	MOVW	R0, R1
821
	RETURN
822
 
823
/*
824
 * Emulate 68020 test and set: load linked / store conditional
825
 */
826
 
827
TEXT	tas(SB), $0
828
	MOVW	R1, R2		/* address of key */
829
tas1:
830
	MOVW	$1, R3
831
	LL(2, 1)
832
	NOP
833
	SC(2, 3)
834
	NOP
835
	BEQ	R3, tas1
836
	NOP
837
	RETURN
838
 
839
TEXT	_xinc(SB), $0
840
	MOVW	R1, R2		/* address of counter */
841
loop:
842
	MOVW	$1, R3
843
	LL(2, 1)
844
	NOP
845
	ADDU	R1, R3
846
	MOVW	R3, R1		/* return new value */
847
	SC(2, 3)
848
	NOP
849
	BEQ	R3, loop
850
	NOP
851
	RETURN
852
 
853
TEXT	_xdec(SB), $0
854
	SYNC
855
	MOVW	R1, R2		/* address of counter */
856
loop1:
857
	MOVW	$-1, R3
858
	LL(2, 1)
859
	NOP
860
	ADDU	R1, R3
861
	MOVW	R3, R1		/* return new value */
862
	SC(2, 3)
863
	NOP
864
	BEQ	R3, loop1
865
	NOP
866
	RETURN
867
 
868
/* used by the semaphore implementation */
869
TEXT cmpswap(SB), $0
870
	MOVW	R1, R2		/* address of key */
871
	MOVW	old+4(FP), R3	/* old value */
872
	MOVW	new+8(FP), R4	/* new value */
873
	LL(2, 1)		/* R1 = (R2) */
874
	NOP
875
	BNE	R1, R3, fail
876
	NOP
877
	MOVW	R4, R1
878
	SC(2, 1)	/* (R2) = R1 if (R2) hasn't changed; R1 = success */
879
	NOP
880
	RETURN
881
fail:
882
	MOVW	R0, R1
883
	RETURN
884
 
885
/*
886
 *  cache manipulation
887
 */
888
 
889
/*
890
 *  we avoided using R4, R5, R6, and R7 so gotopc can call us without saving
891
 *  them, but gotopc is now gone.
892
 */
893
TEXT	icflush(SB), $-4			/* icflush(virtaddr, count) */
894
	MOVW	4(FP), R9
895
	DI(10)				/* intrs off, old status -> R10 */
896
	UBARRIERS(7, R7, ichb);		/* return to kseg1 (uncached) */
897
	ADDU	R1, R9			/* R9 = last address */
898
	MOVW	$(~(CACHELINESZ-1)), R8
899
	AND	R1, R8			/* R8 = first address, rounded down */
900
	ADDU	$(CACHELINESZ-1), R9
901
	AND	$(~(CACHELINESZ-1)), R9	/* round last address up */
902
	SUBU	R8, R9			/* R9 = revised count */
903
icflush1:
904
//	CACHE	PD+HWB, (R8)		/* flush D to ram */
905
	CACHE	PI+HINV, (R8)		/* invalidate in I */
906
	SUBU	$CACHELINESZ, R9
907
	BGTZ	R9, icflush1
908
	ADDU	$CACHELINESZ, R8	/* delay slot */
909
 
910
	BARRIERS(7, R7, ic2hb);		/* return to kseg0 (cached) */
911
	MOVW	R10, M(STATUS)
912
	JRHB(31)			/* return and clear all hazards */
913
 
914
TEXT	dcflush(SB), $-4			/* dcflush(virtaddr, count) */
915
	MOVW	4(FP), R9
916
	DI(10)				/* intrs off, old status -> R10 */
917
	SYNC
918
	EHB
919
	ADDU	R1, R9			/* R9 = last address */
920
	MOVW	$(~(CACHELINESZ-1)), R8
921
	AND	R1, R8			/* R8 = first address, rounded down */
922
	ADDU	$(CACHELINESZ-1), R9
923
	AND	$(~(CACHELINESZ-1)), R9	/* round last address up */
924
	SUBU	R8, R9			/* R9 = revised count */
925
dcflush1:
926
//	CACHE	PI+HINV, (R8)		/* invalidate in I */
927
	CACHE	PD+HWBI, (R8)		/* flush & invalidate in D */
928
	SUBU	$CACHELINESZ, R9
929
	BGTZ	R9, dcflush1
930
	ADDU	$CACHELINESZ, R8	/* delay slot */
931
	SYNC
932
	EHB
933
	MOVW	R10, M(STATUS)
934
	JRHB(31)			/* return and clear all hazards */
935
 
936
/* the i and d caches may be different sizes, so clean them separately */
937
TEXT	cleancache(SB), $-4
938
	DI(10)				/* intrs off, old status -> R10 */
939
 
940
	UBARRIERS(7, R7, cchb);		/* return to kseg1 (uncached) */
941
	MOVW	R0, R1			/* index, not address */
942
	MOVW	$ICACHESIZE, R9
943
iccache:
944
	CACHE	PI+IWBI, (R1)		/* flush & invalidate I by index */
945
	SUBU	$CACHELINESZ, R9
946
	BGTZ	R9, iccache
947
	ADDU	$CACHELINESZ, R1	/* delay slot */
948
 
949
	BARRIERS(7, R7, cc2hb);		/* return to kseg0 (cached) */
950
 
951
	MOVW	R0, R1			/* index, not address */
952
	MOVW	$DCACHESIZE, R9
953
dccache:
954
	CACHE	PD+IWBI, (R1)		/* flush & invalidate D by index */
955
	SUBU	$CACHELINESZ, R9
956
	BGTZ	R9, dccache
957
	ADDU	$CACHELINESZ, R1	/* delay slot */
958
 
959
	SYNC
960
	MOVW	R10, M(STATUS)
961
	JRHB(31)			/* return and clear all hazards */
962
 
963
/*
964
 * access to CP0 registers
965
 */
966
 
967
TEXT	prid(SB), $0
968
	MOVW	M(PRID), R1
969
	RETURN
970
 
971
TEXT	rdcount(SB), $0
972
	MOVW	M(COUNT), R1
973
	RETURN
974
 
975
TEXT	wrcount(SB), $0
976
	MOVW	R1, M(COUNT)
977
	EHB
978
	RETURN
979
 
980
TEXT	wrcompare(SB), $0
981
	MOVW	R1, M(COMPARE)
982
	EHB
983
	RETURN
984
 
985
TEXT	rdcompare(SB), $0
986
	MOVW	M(COMPARE), R1
987
	RETURN
988
 
989
TEXT	getconfig(SB), $-4
990
	MOVW	M(CONFIG), R1
991
	RETURN
992
 
993
TEXT	getconfig1(SB), $-4
994
	MFC0(CONFIG, 1, 1)
995
	RETURN
996
 
997
TEXT	getconfig2(SB), $-4
998
	MFC0(CONFIG, 2, 1)
999
	RETURN
1000
 
1001
TEXT	getconfig3(SB), $-4
1002
	MFC0(CONFIG, 3, 1)
1003
	RETURN
1004
 
1005
TEXT	getconfig4(SB), $-4
1006
	MFC0(CONFIG, 4, 1)
1007
	RETURN
1008
 
1009
TEXT	getconfig7(SB), $-4
1010
	MFC0(CONFIG, 7, 1)
1011
	RETURN
1012
 
1013
TEXT	gethwreg3(SB), $-4
1014
	RDHWR(3, 1)
1015
	RETURN
1016
 
1017
TEXT	getcause(SB), $-4
1018
	MOVW	M(CAUSE), R1
1019
	RETURN
1020
 
1021
TEXT	C_fcr0(SB), $-4		/* fp implementation */
1022
	MOVW	$0x500, R1	/* claim to be an r4k, thus have ll/sc */
1023
	RETURN
1024
 
1025
TEXT	getstatus(SB), $0
1026
	MOVW	M(STATUS), R1
1027
	RETURN
1028
 
1029
TEXT	setstatus(SB), $0
1030
	MOVW	R1, M(STATUS)
1031
	EHB
1032
	RETURN
1033
 
1034
TEXT	setwatchhi0(SB), $0
1035
	MOVW	R1, M(WATCHHI)
1036
	EHB
1037
	RETURN
1038
 
1039
/*
1040
 * beware that the register takes a double-word address, so it's not
1041
 * precise to the individual instruction.
1042
 */
1043
TEXT	setwatchlo0(SB), $0
1044
	MOVW	R1, M(WATCHLO)
1045
	EHB
1046
	RETURN
1047
 
1048
TEXT	setsp(SB), $-4
1049
	MOVW	R1, SP
1050
	RETURN
1051
 
1052
TEXT	getintctl(SB), $-4
1053
	MFC0(STATUS, 1, 1)
1054
	RETURN
1055
 
1056
TEXT	getsrsctl(SB), $-4
1057
	MFC0(STATUS, 2, 1)
1058
	RETURN
1059
 
1060
TEXT	getsrsmap(SB), $-4
1061
	MFC0(STATUS, 3, 1)
1062
	RETURN
1063
 
1064
TEXT	getperfctl0(SB), $-4
1065
	MFC0(PERFCOUNT, 0, 1)
1066
	RETURN
1067
 
1068
TEXT	getperfctl1(SB), $-4
1069
	MFC0(PERFCOUNT, 2, 1)
1070
	RETURN
1071
 
1072
	GLOBL	sanity(SB), $4
1073
	DATA	sanity(SB)/4, $SANITY
1074
 
1075
	SCHED