xref: /original-bsd/sys/pmax/pmax/locore.s (revision 759b7897)
135b3e579Smckusick/*
2ccf8c816Sbostic * Copyright (c) 1992, 1993
3ccf8c816Sbostic *	The Regents of the University of California.  All rights reserved.
435b3e579Smckusick *
535b3e579Smckusick * This code is derived from software contributed to Berkeley by
635b3e579Smckusick * Digital Equipment Corporation and Ralph Campbell.
735b3e579Smckusick *
835b3e579Smckusick * %sccs.include.redist.c%
935b3e579Smckusick *
1035b3e579Smckusick * Copyright (C) 1989 Digital Equipment Corporation.
1135b3e579Smckusick * Permission to use, copy, modify, and distribute this software and
1235b3e579Smckusick * its documentation for any purpose and without fee is hereby granted,
1335b3e579Smckusick * provided that the above copyright notice appears in all copies.
1435b3e579Smckusick * Digital Equipment Corporation makes no representations about the
1535b3e579Smckusick * suitability of this software for any purpose.  It is provided "as is"
1635b3e579Smckusick * without express or implied warranty.
1735b3e579Smckusick *
1835b3e579Smckusick * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
1935b3e579Smckusick *	v 1.1 89/07/11 17:55:04 nelson Exp $ SPRITE (DECWRL)
2035b3e579Smckusick * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
2135b3e579Smckusick *	v 9.2 90/01/29 18:00:39 shirriff Exp $ SPRITE (DECWRL)
2235b3e579Smckusick * from: $Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
2335b3e579Smckusick *	v 1.1 89/07/10 14:27:41 nelson Exp $ SPRITE (DECWRL)
2435b3e579Smckusick *
25*759b7897Sralph *	@(#)locore.s	8.7 (Berkeley) 06/02/95
2635b3e579Smckusick */
2735b3e579Smckusick
2835b3e579Smckusick/*
2935b3e579Smckusick *	Contains code that is the first executed at boot time plus
3035b3e579Smckusick *	assembly language support routines.
3135b3e579Smckusick */
3235b3e579Smckusick
33327b2279Sbostic#include <sys/errno.h>
34bab3189dSralph#include <sys/syscall.h>
3535b3e579Smckusick
36327b2279Sbostic#include <machine/param.h>
37327b2279Sbostic#include <machine/psl.h>
38327b2279Sbostic#include <machine/reg.h>
39327b2279Sbostic#include <machine/machAsmDefs.h>
40327b2279Sbostic#include <machine/pte.h>
41327b2279Sbostic
4235b3e579Smckusick#include "assym.h"
4335b3e579Smckusick
444854f40cSralph	.set	noreorder
454854f40cSralph
4635b3e579Smckusick/*
4735b3e579Smckusick * Amount to take off of the stack for the benefit of the debugger.
4835b3e579Smckusick */
4935b3e579Smckusick#define START_FRAME	((4 * 4) + 4 + 4)
5035b3e579Smckusick
5135b3e579Smckusick	.globl	start
5235b3e579Smckusickstart:
5335b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
5492e9186eSralph	li	t1, MACH_CACHED_MEMORY_ADDR	# invalid address
5535b3e579Smckusick	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
5635b3e579Smckusick	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
5735b3e579Smckusick/*
5835b3e579Smckusick * Clear the TLB (just to be safe).
5935b3e579Smckusick * Align the starting value (t1), the increment (t2) and the upper bound (t3).
6035b3e579Smckusick */
6135b3e579Smckusick	move	t1, zero
6235b3e579Smckusick	li	t2, 1 << VMMACH_TLB_INDEX_SHIFT
6335b3e579Smckusick	li	t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
6435b3e579Smckusick1:
6535b3e579Smckusick	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register.
6635b3e579Smckusick	addu	t1, t1, t2			# Increment index.
6735b3e579Smckusick	bne	t1, t3, 1b			# NB: always executes next
6835b3e579Smckusick	tlbwi					# Write the TLB entry.
6935b3e579Smckusick
70193a1c3eSralph	la	sp, start - START_FRAME
71193a1c3eSralph #	la	gp, _gp
7235b3e579Smckusick	sw	zero, START_FRAME - 4(sp)	# Zero out old ra for debugger
7335b3e579Smckusick	jal	mach_init			# mach_init(argc, argv, envp)
7435b3e579Smckusick	sw	zero, START_FRAME - 8(sp)	# Zero out old fp for debugger
7535b3e579Smckusick
7635b3e579Smckusick	li	t0, MACH_SR_COP_1_BIT		# Disable interrupts and
7735b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	#   enable the coprocessor
7835b3e579Smckusick	li	sp, KERNELSTACK - START_FRAME	# switch to standard stack
7935b3e579Smckusick	mfc0	t0, MACH_COP_0_PRID		# read processor ID register
8035b3e579Smckusick	cfc1	t1, MACH_FPC_ID			# read FPU ID register
8135b3e579Smckusick	sw	t0, cpu				# save PRID register
8235b3e579Smckusick	sw	t1, fpu				# save FPU ID register
832e5b9d54Smckusick	jal	main				# main(regs)
842e5b9d54Smckusick	move	a0, zero
852e5b9d54Smckusick/*
862e5b9d54Smckusick * proc[1] == /etc/init now running here.
872e5b9d54Smckusick * Restore user registers and return.
882e5b9d54Smckusick */
892e5b9d54Smckusick	.set	noat
9035b3e579Smckusick	li	v0, PSL_USERSET
9135b3e579Smckusick	mtc0	v0, MACH_COP_0_STATUS_REG	# switch to user mode
922e5b9d54Smckusick	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
932e5b9d54Smckusick	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
942e5b9d54Smckusick	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
952e5b9d54Smckusick	mtlo	t0
962e5b9d54Smckusick	mthi	t1
972e5b9d54Smckusick	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
982e5b9d54Smckusick	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
992e5b9d54Smckusick	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
1002e5b9d54Smckusick	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
1012e5b9d54Smckusick	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
1022e5b9d54Smckusick	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
1032e5b9d54Smckusick	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
1042e5b9d54Smckusick	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
1052e5b9d54Smckusick	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
1062e5b9d54Smckusick	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
1072e5b9d54Smckusick	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
1082e5b9d54Smckusick	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
1092e5b9d54Smckusick	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
1102e5b9d54Smckusick	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
1112e5b9d54Smckusick	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
1122e5b9d54Smckusick	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
1132e5b9d54Smckusick	lw	s0, UADDR+U_PCB_REGS+(S0 * 4)
1142e5b9d54Smckusick	lw	s1, UADDR+U_PCB_REGS+(S1 * 4)
1152e5b9d54Smckusick	lw	s2, UADDR+U_PCB_REGS+(S2 * 4)
1162e5b9d54Smckusick	lw	s3, UADDR+U_PCB_REGS+(S3 * 4)
1172e5b9d54Smckusick	lw	s4, UADDR+U_PCB_REGS+(S4 * 4)
1182e5b9d54Smckusick	lw	s5, UADDR+U_PCB_REGS+(S5 * 4)
1192e5b9d54Smckusick	lw	s6, UADDR+U_PCB_REGS+(S6 * 4)
1202e5b9d54Smckusick	lw	s7, UADDR+U_PCB_REGS+(S7 * 4)
1212e5b9d54Smckusick	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
1222e5b9d54Smckusick	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
1232e5b9d54Smckusick	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
1242e5b9d54Smckusick	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
1252e5b9d54Smckusick	lw	s8, UADDR+U_PCB_REGS+(S8 * 4)
1262e5b9d54Smckusick	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
1272e5b9d54Smckusick	j	k0
12835b3e579Smckusick	rfe
1292e5b9d54Smckusick	.set	at
13035b3e579Smckusick
13135b3e579Smckusick/*
1320bb4cdc4Sralph * GCC2 seems to want to call __main in main() for some reason.
1330bb4cdc4Sralph */
1340bb4cdc4SralphLEAF(__main)
1350bb4cdc4Sralph	j	ra
1364854f40cSralph	nop
1370bb4cdc4SralphEND(__main)
1380bb4cdc4Sralph
1390bb4cdc4Sralph/*
140bab3189dSralph * This code is copied the user's stack for returning from signal handlers
141bab3189dSralph * (see sendsig() and sigreturn()). We have to compute the address
142bab3189dSralph * of the sigcontext struct for the sigreturn call.
143bab3189dSralph */
144bab3189dSralph	.globl	sigcode
145bab3189dSralphsigcode:
146bab3189dSralph	addu	a0, sp, 16		# address of sigcontext
147bab3189dSralph	li	v0, SYS_sigreturn	# sigreturn(scp)
148bab3189dSralph	syscall
149bab3189dSralph	break	0			# just in case sigreturn fails
150bab3189dSralph	.globl	esigcode
151bab3189dSralphesigcode:
152bab3189dSralph
153bab3189dSralph/*
15435b3e579Smckusick * Primitives
15535b3e579Smckusick */
15635b3e579Smckusick
15735b3e579Smckusick/*
15835b3e579Smckusick * This table is indexed by u.u_pcb.pcb_onfault in trap().
15935b3e579Smckusick * The reason for using this table rather than storing an address in
16035b3e579Smckusick * u.u_pcb.pcb_onfault is simply to make the code faster.
16135b3e579Smckusick */
16235b3e579Smckusick	.globl	onfault_table
16335b3e579Smckusick	.data
16435b3e579Smckusick	.align	2
16535b3e579Smckusickonfault_table:
16635b3e579Smckusick	.word	0		# invalid index number
16735b3e579Smckusick#define BADERR		1
16835b3e579Smckusick	.word	baderr
1690bb4cdc4Sralph#define COPYERR		2
17035b3e579Smckusick	.word	copyerr
1710bb4cdc4Sralph#define FSWBERR		3
17235b3e579Smckusick	.word	fswberr
1730bb4cdc4Sralph#define FSWINTRBERR	4
1740bb4cdc4Sralph	.word	fswintrberr
1754cf6ea80Sralph#ifdef KADB
1764cf6ea80Sralph#define KADBERR		5
1774cf6ea80Sralph	.word	kadberr
1784cf6ea80Sralph#endif
17935b3e579Smckusick	.text
18035b3e579Smckusick
18135b3e579Smckusick/*
18235b3e579Smckusick * See if access to addr with a len type instruction causes a machine check.
18335b3e579Smckusick * len is length of access (1=byte, 2=short, 4=long)
18435b3e579Smckusick *
18535b3e579Smckusick * badaddr(addr, len)
18635b3e579Smckusick *	char *addr;
18735b3e579Smckusick *	int len;
18835b3e579Smckusick */
18935b3e579SmckusickLEAF(badaddr)
19035b3e579Smckusick	li	v0, BADERR
19135b3e579Smckusick	bne	a1, 1, 2f
1924854f40cSralph	sw	v0, UADDR+U_PCB_ONFAULT
19335b3e579Smckusick	b	5f
1944854f40cSralph	lbu	v0, (a0)
19535b3e579Smckusick2:
19635b3e579Smckusick	bne	a1, 2, 4f
1974854f40cSralph	nop
19835b3e579Smckusick	b	5f
1994854f40cSralph	lhu	v0, (a0)
20035b3e579Smckusick4:
20135b3e579Smckusick	lw	v0, (a0)
20235b3e579Smckusick5:
20335b3e579Smckusick	sw	zero, UADDR+U_PCB_ONFAULT
2044854f40cSralph	j	ra
20535b3e579Smckusick	move	v0, zero		# made it w/o errors
20635b3e579Smckusickbaderr:
20735b3e579Smckusick	j	ra
2084854f40cSralph	li	v0, 1			# trap sends us here
20935b3e579SmckusickEND(badaddr)
21035b3e579Smckusick
21135b3e579Smckusick/*
21235b3e579Smckusick * netorder = htonl(hostorder)
21335b3e579Smckusick * hostorder = ntohl(netorder)
21435b3e579Smckusick */
21535b3e579SmckusickLEAF(htonl)				# a0 = 0x11223344, return 0x44332211
21635b3e579SmckusickALEAF(ntohl)
21735b3e579Smckusick	srl	v1, a0, 24		# v1 = 0x00000011
21835b3e579Smckusick	sll	v0, a0, 24		# v0 = 0x44000000
21935b3e579Smckusick	or	v0, v0, v1
22035b3e579Smckusick	and	v1, a0, 0xff00
22135b3e579Smckusick	sll	v1, v1, 8		# v1 = 0x00330000
22235b3e579Smckusick	or	v0, v0, v1
22335b3e579Smckusick	srl	v1, a0, 8
22435b3e579Smckusick	and	v1, v1, 0xff00		# v1 = 0x00002200
22535b3e579Smckusick	j	ra
2264854f40cSralph	or	v0, v0, v1
22735b3e579SmckusickEND(htonl)
22835b3e579Smckusick
22935b3e579Smckusick/*
23035b3e579Smckusick * netorder = htons(hostorder)
23135b3e579Smckusick * hostorder = ntohs(netorder)
23235b3e579Smckusick */
23335b3e579SmckusickLEAF(htons)
23435b3e579SmckusickALEAF(ntohs)
23535b3e579Smckusick	srl	v0, a0, 8
23635b3e579Smckusick	and	v0, v0, 0xff
23735b3e579Smckusick	sll	v1, a0, 8
23835b3e579Smckusick	and	v1, v1, 0xff00
23935b3e579Smckusick	j	ra
2404854f40cSralph	or	v0, v0, v1
24135b3e579SmckusickEND(htons)
24235b3e579Smckusick
24335b3e579Smckusick/*
24435b3e579Smckusick * bit = ffs(value)
24535b3e579Smckusick */
24635b3e579SmckusickLEAF(ffs)
24735b3e579Smckusick	beq	a0, zero, 2f
2484854f40cSralph	move	v0, zero
24935b3e579Smckusick1:
25035b3e579Smckusick	and	v1, a0, 1		# bit set?
25135b3e579Smckusick	addu	v0, v0, 1
25235b3e579Smckusick	beq	v1, zero, 1b		# no, continue
2534854f40cSralph	srl	a0, a0, 1
25435b3e579Smckusick2:
25535b3e579Smckusick	j	ra
2564854f40cSralph	nop
25735b3e579SmckusickEND(ffs)
25835b3e579Smckusick
25935b3e579Smckusick/*
26035b3e579Smckusick * strlen(str)
26135b3e579Smckusick */
26235b3e579SmckusickLEAF(strlen)
26335b3e579Smckusick	addu	v1, a0, 1
26435b3e579Smckusick1:
26535b3e579Smckusick	lb	v0, 0(a0)		# get byte from string
26635b3e579Smckusick	addu	a0, a0, 1		# increment pointer
26735b3e579Smckusick	bne	v0, zero, 1b		# continue if not end
2684854f40cSralph	nop
26935b3e579Smckusick	j	ra
2704854f40cSralph	subu	v0, a0, v1		# compute length - 1 for '\0' char
27135b3e579SmckusickEND(strlen)
27235b3e579Smckusick
27335b3e579Smckusick/*
2744cf6ea80Sralph * NOTE: this version assumes unsigned chars in order to be "8 bit clean".
2754cf6ea80Sralph */
2764cf6ea80SralphLEAF(strcmp)
2774cf6ea80Sralph1:
2784cf6ea80Sralph	lbu	t0, 0(a0)		# get two bytes and compare them
2794cf6ea80Sralph	lbu	t1, 0(a1)
2804cf6ea80Sralph	beq	t0, zero, LessOrEq	# end of first string?
2814854f40cSralph	nop
2824cf6ea80Sralph	bne	t0, t1, NotEq
2834854f40cSralph	nop
2844cf6ea80Sralph	lbu	t0, 1(a0)		# unroll loop
2854cf6ea80Sralph	lbu	t1, 1(a1)
2864cf6ea80Sralph	beq	t0, zero, LessOrEq	# end of first string?
2874854f40cSralph	addu	a0, a0, 2
2884cf6ea80Sralph	beq	t0, t1, 1b
2894854f40cSralph	addu	a1, a1, 2
2904cf6ea80SralphNotEq:
2914854f40cSralph	j	ra
2924cf6ea80Sralph	subu	v0, t0, t1
2934cf6ea80SralphLessOrEq:
2944cf6ea80Sralph	j	ra
2954854f40cSralph	subu	v0, zero, t1
2964cf6ea80SralphEND(strcmp)
2974cf6ea80Sralph
2984cf6ea80Sralph/*
29935b3e579Smckusick * bzero(s1, n)
30035b3e579Smckusick */
30135b3e579SmckusickLEAF(bzero)
30235b3e579SmckusickALEAF(blkclr)
30335b3e579Smckusick	blt	a1, 12, smallclr	# small amount to clear?
30435b3e579Smckusick	subu	a3, zero, a0		# compute # bytes to word align address
30535b3e579Smckusick	and	a3, a3, 3
30635b3e579Smckusick	beq	a3, zero, 1f		# skip if word aligned
30735b3e579Smckusick	subu	a1, a1, a3		# subtract from remaining count
30835b3e579Smckusick	swr	zero, 0(a0)		# clear 1, 2, or 3 bytes to align
30935b3e579Smckusick	addu	a0, a0, a3
31035b3e579Smckusick1:
31135b3e579Smckusick	and	v0, a1, 3		# compute number of words left
31235b3e579Smckusick	subu	a3, a1, v0
31335b3e579Smckusick	move	a1, v0
31435b3e579Smckusick	addu	a3, a3, a0		# compute ending address
31535b3e579Smckusick2:
31635b3e579Smckusick	addu	a0, a0, 4		# clear words
317193a1c3eSralph	bne	a0, a3, 2b		#  unrolling loop does not help
318193a1c3eSralph	sw	zero, -4(a0)		#  since we are limited by memory speed
31935b3e579Smckusicksmallclr:
32035b3e579Smckusick	ble	a1, zero, 2f
32135b3e579Smckusick	addu	a3, a1, a0		# compute ending address
32235b3e579Smckusick1:
32335b3e579Smckusick	addu	a0, a0, 1		# clear bytes
32435b3e579Smckusick	bne	a0, a3, 1b
32535b3e579Smckusick	sb	zero, -1(a0)
32635b3e579Smckusick2:
32735b3e579Smckusick	j	ra
32835b3e579Smckusick	nop
32935b3e579SmckusickEND(bzero)
33035b3e579Smckusick
33135b3e579Smckusick/*
33235b3e579Smckusick * bcmp(s1, s2, n)
33335b3e579Smckusick */
33435b3e579SmckusickLEAF(bcmp)
33535b3e579Smckusick	blt	a2, 16, smallcmp	# is it worth any trouble?
33635b3e579Smckusick	xor	v0, a0, a1		# compare low two bits of addresses
33735b3e579Smckusick	and	v0, v0, 3
33835b3e579Smckusick	subu	a3, zero, a1		# compute # bytes to word align address
33935b3e579Smckusick	bne	v0, zero, unalignedcmp	# not possible to align addresses
34035b3e579Smckusick	and	a3, a3, 3
34135b3e579Smckusick
34235b3e579Smckusick	beq	a3, zero, 1f
34335b3e579Smckusick	subu	a2, a2, a3		# subtract from remaining count
34435b3e579Smckusick	move	v0, v1			# init v0,v1 so unmodified bytes match
34535b3e579Smckusick	lwr	v0, 0(a0)		# read 1, 2, or 3 bytes
34635b3e579Smckusick	lwr	v1, 0(a1)
34735b3e579Smckusick	addu	a1, a1, a3
34835b3e579Smckusick	bne	v0, v1, nomatch
34935b3e579Smckusick	addu	a0, a0, a3
35035b3e579Smckusick1:
35135b3e579Smckusick	and	a3, a2, ~3		# compute number of whole words left
35235b3e579Smckusick	subu	a2, a2, a3		#   which has to be >= (16-3) & ~3
35335b3e579Smckusick	addu	a3, a3, a0		# compute ending address
35435b3e579Smckusick2:
35535b3e579Smckusick	lw	v0, 0(a0)		# compare words
35635b3e579Smckusick	lw	v1, 0(a1)
35735b3e579Smckusick	addu	a0, a0, 4
35835b3e579Smckusick	bne	v0, v1, nomatch
35935b3e579Smckusick	addu	a1, a1, 4
36035b3e579Smckusick	bne	a0, a3, 2b
36135b3e579Smckusick	nop
36235b3e579Smckusick	b	smallcmp		# finish remainder
36335b3e579Smckusick	nop
36435b3e579Smckusickunalignedcmp:
36535b3e579Smckusick	beq	a3, zero, 2f
36635b3e579Smckusick	subu	a2, a2, a3		# subtract from remaining count
36735b3e579Smckusick	addu	a3, a3, a0		# compute ending address
36835b3e579Smckusick1:
36935b3e579Smckusick	lbu	v0, 0(a0)		# compare bytes until a1 word aligned
37035b3e579Smckusick	lbu	v1, 0(a1)
37135b3e579Smckusick	addu	a0, a0, 1
37235b3e579Smckusick	bne	v0, v1, nomatch
37335b3e579Smckusick	addu	a1, a1, 1
37435b3e579Smckusick	bne	a0, a3, 1b
37535b3e579Smckusick	nop
37635b3e579Smckusick2:
37735b3e579Smckusick	and	a3, a2, ~3		# compute number of whole words left
37835b3e579Smckusick	subu	a2, a2, a3		#   which has to be >= (16-3) & ~3
37935b3e579Smckusick	addu	a3, a3, a0		# compute ending address
38035b3e579Smckusick3:
38135b3e579Smckusick	lwr	v0, 0(a0)		# compare words a0 unaligned, a1 aligned
38235b3e579Smckusick	lwl	v0, 3(a0)
38335b3e579Smckusick	lw	v1, 0(a1)
38435b3e579Smckusick	addu	a0, a0, 4
38535b3e579Smckusick	bne	v0, v1, nomatch
38635b3e579Smckusick	addu	a1, a1, 4
38735b3e579Smckusick	bne	a0, a3, 3b
38835b3e579Smckusick	nop
38935b3e579Smckusicksmallcmp:
39035b3e579Smckusick	ble	a2, zero, match
39135b3e579Smckusick	addu	a3, a2, a0		# compute ending address
39235b3e579Smckusick1:
39335b3e579Smckusick	lbu	v0, 0(a0)
39435b3e579Smckusick	lbu	v1, 0(a1)
39535b3e579Smckusick	addu	a0, a0, 1
39635b3e579Smckusick	bne	v0, v1, nomatch
39735b3e579Smckusick	addu	a1, a1, 1
39835b3e579Smckusick	bne	a0, a3, 1b
39935b3e579Smckusick	nop
40035b3e579Smckusickmatch:
40135b3e579Smckusick	j	ra
40235b3e579Smckusick	move	v0, zero
40335b3e579Smckusicknomatch:
40435b3e579Smckusick	j	ra
40535b3e579Smckusick	li	v0, 1
40635b3e579SmckusickEND(bcmp)
40735b3e579Smckusick
40835b3e579Smckusick/*
40952c87c4dSmckusick * memcpy(to, from, len)
41035b3e579Smckusick * {ov}bcopy(from, to, len)
41135b3e579Smckusick */
41252c87c4dSmckusickLEAF(memcpy)
41352c87c4dSmckusick	move	v0, a0			# swap from and to
41452c87c4dSmckusick	move	a0, a1
41552c87c4dSmckusick	move	a1, v0
41652c87c4dSmckusickALEAF(bcopy)
41735b3e579SmckusickALEAF(ovbcopy)
41835b3e579Smckusick	addu	t0, a0, a2		# t0 = end of s1 region
41935b3e579Smckusick	sltu	t1, a1, t0
42035b3e579Smckusick	sltu	t2, a0, a1
42135b3e579Smckusick	and	t1, t1, t2		# t1 = true if from < to < (from+len)
42235b3e579Smckusick	beq	t1, zero, forward	# non overlapping, do forward copy
42335b3e579Smckusick	slt	t2, a2, 12		# check for small copy
42435b3e579Smckusick
42535b3e579Smckusick	ble	a2, zero, 2f
42635b3e579Smckusick	addu	t1, a1, a2		# t1 = end of to region
42735b3e579Smckusick1:
42852c87c4dSmckusick	lb	v1, -1(t0)		# copy bytes backwards,
429193a1c3eSralph	subu	t0, t0, 1		#   doesnt happen often so do slow way
43035b3e579Smckusick	subu	t1, t1, 1
43135b3e579Smckusick	bne	t0, a0, 1b
43252c87c4dSmckusick	sb	v1, 0(t1)
43335b3e579Smckusick2:
43435b3e579Smckusick	j	ra
43535b3e579Smckusick	nop
43635b3e579Smckusickforward:
43735b3e579Smckusick	bne	t2, zero, smallcpy	# do a small bcopy
43852c87c4dSmckusick	xor	v1, a0, a1		# compare low two bits of addresses
43952c87c4dSmckusick	and	v1, v1, 3
44035b3e579Smckusick	subu	a3, zero, a1		# compute # bytes to word align address
44152c87c4dSmckusick	beq	v1, zero, aligned	# addresses can be word aligned
44235b3e579Smckusick	and	a3, a3, 3
44335b3e579Smckusick
44435b3e579Smckusick	beq	a3, zero, 1f
44535b3e579Smckusick	subu	a2, a2, a3		# subtract from remaining count
44652c87c4dSmckusick	lwr	v1, 0(a0)		# get next 4 bytes (unaligned)
44752c87c4dSmckusick	lwl	v1, 3(a0)
44835b3e579Smckusick	addu	a0, a0, a3
44952c87c4dSmckusick	swr	v1, 0(a1)		# store 1, 2, or 3 bytes to align a1
45035b3e579Smckusick	addu	a1, a1, a3
45135b3e579Smckusick1:
45252c87c4dSmckusick	and	v1, a2, 3		# compute number of words left
45352c87c4dSmckusick	subu	a3, a2, v1
45452c87c4dSmckusick	move	a2, v1
45535b3e579Smckusick	addu	a3, a3, a0		# compute ending address
45635b3e579Smckusick2:
45752c87c4dSmckusick	lwr	v1, 0(a0)		# copy words a0 unaligned, a1 aligned
45852c87c4dSmckusick	lwl	v1, 3(a0)
45935b3e579Smckusick	addu	a0, a0, 4
46035b3e579Smckusick	addu	a1, a1, 4
46135b3e579Smckusick	bne	a0, a3, 2b
46252c87c4dSmckusick	sw	v1, -4(a1)
46335b3e579Smckusick	b	smallcpy
46435b3e579Smckusick	nop
46535b3e579Smckusickaligned:
46635b3e579Smckusick	beq	a3, zero, 1f
46735b3e579Smckusick	subu	a2, a2, a3		# subtract from remaining count
46852c87c4dSmckusick	lwr	v1, 0(a0)		# copy 1, 2, or 3 bytes to align
46935b3e579Smckusick	addu	a0, a0, a3
47052c87c4dSmckusick	swr	v1, 0(a1)
47135b3e579Smckusick	addu	a1, a1, a3
47235b3e579Smckusick1:
47352c87c4dSmckusick	and	v1, a2, 3		# compute number of whole words left
47452c87c4dSmckusick	subu	a3, a2, v1
47552c87c4dSmckusick	move	a2, v1
47635b3e579Smckusick	addu	a3, a3, a0		# compute ending address
47735b3e579Smckusick2:
47852c87c4dSmckusick	lw	v1, 0(a0)		# copy words
47935b3e579Smckusick	addu	a0, a0, 4
48035b3e579Smckusick	addu	a1, a1, 4
48135b3e579Smckusick	bne	a0, a3, 2b
48252c87c4dSmckusick	sw	v1, -4(a1)
48335b3e579Smckusicksmallcpy:
48435b3e579Smckusick	ble	a2, zero, 2f
48535b3e579Smckusick	addu	a3, a2, a0		# compute ending address
48635b3e579Smckusick1:
48752c87c4dSmckusick	lbu	v1, 0(a0)		# copy bytes
48835b3e579Smckusick	addu	a0, a0, 1
48935b3e579Smckusick	addu	a1, a1, 1
49035b3e579Smckusick	bne	a0, a3, 1b
49152c87c4dSmckusick	sb	v1, -1(a1)
49235b3e579Smckusick2:
49335b3e579Smckusick	j	ra
49452c87c4dSmckusick	nop
49552c87c4dSmckusickEND(memcpy)
49635b3e579Smckusick
49735b3e579Smckusick/*
49835b3e579Smckusick * Copy a null terminated string within the kernel address space.
49935b3e579Smckusick * Maxlength may be null if count not wanted.
50035b3e579Smckusick *	copystr(fromaddr, toaddr, maxlength, &lencopied)
50135b3e579Smckusick *		caddr_t fromaddr;
50235b3e579Smckusick *		caddr_t toaddr;
50335b3e579Smckusick *		u_int maxlength;
50435b3e579Smckusick *		u_int *lencopied;
50535b3e579Smckusick */
50635b3e579SmckusickLEAF(copystr)
50735b3e579Smckusick	move	t2, a2			# Save the number of bytes
50835b3e579Smckusick1:
5094854f40cSralph	lbu	t0, 0(a0)
5104854f40cSralph	subu	a2, a2, 1
51135b3e579Smckusick	beq	t0, zero, 2f
5124854f40cSralph	sb	t0, 0(a1)
5134854f40cSralph	addu	a0, a0, 1
51435b3e579Smckusick	bne	a2, zero, 1b
5154854f40cSralph	addu	a1, a1, 1
51635b3e579Smckusick2:
51735b3e579Smckusick	beq	a3, zero, 3f
5184854f40cSralph	subu	a2, t2, a2		# compute length copied
51935b3e579Smckusick	sw	a2, 0(a3)
52035b3e579Smckusick3:
52135b3e579Smckusick	j	ra
5224854f40cSralph	move	v0, zero
52335b3e579SmckusickEND(copystr)
52435b3e579Smckusick
52535b3e579Smckusick/*
52635b3e579Smckusick * Copy a null terminated string from the user address space into
52735b3e579Smckusick * the kernel address space.
52835b3e579Smckusick *
52935b3e579Smckusick *	copyinstr(fromaddr, toaddr, maxlength, &lencopied)
53035b3e579Smckusick *		caddr_t fromaddr;
53135b3e579Smckusick *		caddr_t toaddr;
53235b3e579Smckusick *		u_int maxlength;
53335b3e579Smckusick *		u_int *lencopied;
53435b3e579Smckusick */
535193a1c3eSralphNON_LEAF(copyinstr, STAND_FRAME_SIZE, ra)
536193a1c3eSralph	subu	sp, sp, STAND_FRAME_SIZE
537193a1c3eSralph	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
538193a1c3eSralph	sw	ra, STAND_RA_OFFSET(sp)
53935b3e579Smckusick	blt	a0, zero, copyerr	# make sure address is in user space
5404854f40cSralph	li	v0, COPYERR
541193a1c3eSralph	jal	copystr
5424854f40cSralph	sw	v0, UADDR+U_PCB_ONFAULT
543193a1c3eSralph	lw	ra, STAND_RA_OFFSET(sp)
544193a1c3eSralph	sw	zero, UADDR+U_PCB_ONFAULT
545193a1c3eSralph	addu	sp, sp, STAND_FRAME_SIZE
546193a1c3eSralph	j	ra
5474854f40cSralph	move	v0, zero
54835b3e579SmckusickEND(copyinstr)
54935b3e579Smckusick
55035b3e579Smckusick/*
55135b3e579Smckusick * Copy a null terminated string from the kernel address space into
55235b3e579Smckusick * the user address space.
55335b3e579Smckusick *
55435b3e579Smckusick *	copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
55535b3e579Smckusick *		caddr_t fromaddr;
55635b3e579Smckusick *		caddr_t toaddr;
55735b3e579Smckusick *		u_int maxlength;
55835b3e579Smckusick *		u_int *lencopied;
55935b3e579Smckusick */
560193a1c3eSralphNON_LEAF(copyoutstr, STAND_FRAME_SIZE, ra)
561193a1c3eSralph	subu	sp, sp, STAND_FRAME_SIZE
562193a1c3eSralph	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
563193a1c3eSralph	sw	ra, STAND_RA_OFFSET(sp)
56435b3e579Smckusick	blt	a1, zero, copyerr	# make sure address is in user space
5654854f40cSralph	li	v0, COPYERR
566193a1c3eSralph	jal	copystr
5674854f40cSralph	sw	v0, UADDR+U_PCB_ONFAULT
568193a1c3eSralph	lw	ra, STAND_RA_OFFSET(sp)
569193a1c3eSralph	sw	zero, UADDR+U_PCB_ONFAULT
570193a1c3eSralph	addu	sp, sp, STAND_FRAME_SIZE
571193a1c3eSralph	j	ra
5724854f40cSralph	move	v0, zero
57335b3e579SmckusickEND(copyoutstr)
57435b3e579Smckusick
57535b3e579Smckusick/*
57635b3e579Smckusick * Copy specified amount of data from user space into the kernel
57735b3e579Smckusick *	copyin(from, to, len)
57835b3e579Smckusick *		caddr_t *from;	(user source address)
57935b3e579Smckusick *		caddr_t *to;	(kernel destination address)
58035b3e579Smckusick *		unsigned len;
58135b3e579Smckusick */
582193a1c3eSralphNON_LEAF(copyin, STAND_FRAME_SIZE, ra)
583193a1c3eSralph	subu	sp, sp, STAND_FRAME_SIZE
584193a1c3eSralph	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
585193a1c3eSralph	sw	ra, STAND_RA_OFFSET(sp)
58635b3e579Smckusick	blt	a0, zero, copyerr	# make sure address is in user space
5874854f40cSralph	li	v0, COPYERR
588193a1c3eSralph	jal	bcopy
5894854f40cSralph	sw	v0, UADDR+U_PCB_ONFAULT
590193a1c3eSralph	lw	ra, STAND_RA_OFFSET(sp)
591193a1c3eSralph	sw	zero, UADDR+U_PCB_ONFAULT
592193a1c3eSralph	addu	sp, sp, STAND_FRAME_SIZE
593193a1c3eSralph	j	ra
5944854f40cSralph	move	v0, zero
59535b3e579SmckusickEND(copyin)
59635b3e579Smckusick
59735b3e579Smckusick/*
59835b3e579Smckusick * Copy specified amount of data from kernel to the user space
59935b3e579Smckusick *	copyout(from, to, len)
60035b3e579Smckusick *		caddr_t *from;	(kernel source address)
60135b3e579Smckusick *		caddr_t *to;	(user destination address)
60235b3e579Smckusick *		unsigned len;
60335b3e579Smckusick */
604193a1c3eSralphNON_LEAF(copyout, STAND_FRAME_SIZE, ra)
605193a1c3eSralph	subu	sp, sp, STAND_FRAME_SIZE
606193a1c3eSralph	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
607193a1c3eSralph	sw	ra, STAND_RA_OFFSET(sp)
60835b3e579Smckusick	blt	a1, zero, copyerr	# make sure address is in user space
6094854f40cSralph	li	v0, COPYERR
610193a1c3eSralph	jal	bcopy
6114854f40cSralph	sw	v0, UADDR+U_PCB_ONFAULT
612193a1c3eSralph	lw	ra, STAND_RA_OFFSET(sp)
613193a1c3eSralph	sw	zero, UADDR+U_PCB_ONFAULT
614193a1c3eSralph	addu	sp, sp, STAND_FRAME_SIZE
615193a1c3eSralph	j	ra
6164854f40cSralph	move	v0, zero
61735b3e579SmckusickEND(copyout)
61835b3e579Smckusick
61935b3e579SmckusickLEAF(copyerr)
620193a1c3eSralph	lw	ra, STAND_RA_OFFSET(sp)
621193a1c3eSralph	sw	zero, UADDR+U_PCB_ONFAULT
622193a1c3eSralph	addu	sp, sp, STAND_FRAME_SIZE
62335b3e579Smckusick	j	ra
6244854f40cSralph	li	v0, EFAULT		# return error
62535b3e579SmckusickEND(copyerr)
62635b3e579Smckusick
62735b3e579Smckusick/*
62835b3e579Smckusick * Copy data to the DMA buffer.
62935b3e579Smckusick * The DMA bufffer can only be written one short at a time
63035b3e579Smckusick * (and takes ~14 cycles).
63135b3e579Smckusick *
63235b3e579Smckusick *	CopyToBuffer(src, dst, length)
63335b3e579Smckusick *		u_short *src;	NOTE: must be short aligned
63435b3e579Smckusick *		u_short *dst;
63535b3e579Smckusick *		int length;
63635b3e579Smckusick */
63735b3e579SmckusickLEAF(CopyToBuffer)
63835b3e579Smckusick	blez	a2, 2f
6394854f40cSralph	nop
64035b3e579Smckusick1:
64135b3e579Smckusick	lhu	t0, 0(a0)		# read 2 bytes of data
64235b3e579Smckusick	subu	a2, a2, 2
64335b3e579Smckusick	addu	a0, a0, 2
64435b3e579Smckusick	addu	a1, a1, 4
64535b3e579Smckusick	bgtz	a2, 1b
6464854f40cSralph	sh	t0, -4(a1)		# write 2 bytes of data to buffer
64735b3e579Smckusick2:
64835b3e579Smckusick	j	ra
6494854f40cSralph	nop
65035b3e579SmckusickEND(CopyToBuffer)
65135b3e579Smckusick
65235b3e579Smckusick/*
65335b3e579Smckusick * Copy data from the DMA buffer.
65435b3e579Smckusick * The DMA bufffer can only be read one short at a time
65535b3e579Smckusick * (and takes ~12 cycles).
65635b3e579Smckusick *
65735b3e579Smckusick *	CopyFromBuffer(src, dst, length)
65835b3e579Smckusick *		u_short *src;
65935b3e579Smckusick *		char *dst;
66035b3e579Smckusick *		int length;
66135b3e579Smckusick */
66235b3e579SmckusickLEAF(CopyFromBuffer)
66335b3e579Smckusick	and	t0, a1, 1		# test for aligned dst
66435b3e579Smckusick	beq	t0, zero, 3f
6654854f40cSralph	nop
66635b3e579Smckusick	blt	a2, 2, 7f		# at least 2 bytes to copy?
6674854f40cSralph	nop
66835b3e579Smckusick1:
66935b3e579Smckusick	lhu	t0, 0(a0)		# read 2 bytes of data from buffer
67035b3e579Smckusick	addu	a0, a0, 4		# keep buffer pointer word aligned
67135b3e579Smckusick	addu	a1, a1, 2
67235b3e579Smckusick	subu	a2, a2, 2
67335b3e579Smckusick	sb	t0, -2(a1)
67435b3e579Smckusick	srl	t0, t0, 8
67535b3e579Smckusick	bge	a2, 2, 1b
6764854f40cSralph	sb	t0, -1(a1)
67735b3e579Smckusick3:
67835b3e579Smckusick	blt	a2, 2, 7f		# at least 2 bytes to copy?
6794854f40cSralph	nop
68035b3e579Smckusick6:
68135b3e579Smckusick	lhu	t0, 0(a0)		# read 2 bytes of data from buffer
68235b3e579Smckusick	addu	a0, a0, 4		# keep buffer pointer word aligned
68335b3e579Smckusick	addu	a1, a1, 2
68435b3e579Smckusick	subu	a2, a2, 2
68535b3e579Smckusick	bge	a2, 2, 6b
6864854f40cSralph	sh	t0, -2(a1)
68735b3e579Smckusick7:
68835b3e579Smckusick	ble	a2, zero, 9f		# done?
6894854f40cSralph	nop
69035b3e579Smckusick	lhu	t0, 0(a0)		# copy one more byte
6914854f40cSralph	nop
69235b3e579Smckusick	sb	t0, 0(a1)
69335b3e579Smckusick9:
69435b3e579Smckusick	j	ra
6954854f40cSralph	nop
69635b3e579SmckusickEND(CopyFromBuffer)
69735b3e579Smckusick
69835b3e579Smckusick/*
69935b3e579Smckusick * Copy the kernel stack to the new process and save the current context so
7000082cbe2Sbostic * the new process will return nonzero when it is resumed by cpu_switch().
70135b3e579Smckusick *
70235b3e579Smckusick *	copykstack(up)
70335b3e579Smckusick *		struct user *up;
70435b3e579Smckusick */
70535b3e579SmckusickLEAF(copykstack)
70635b3e579Smckusick	subu	v0, sp, UADDR		# compute offset into stack
70735b3e579Smckusick	addu	v0, v0, a0		# v0 = new stack address
70835b3e579Smckusick	move	v1, sp			# v1 = old stack address
70935b3e579Smckusick	li	t1, KERNELSTACK
71035b3e579Smckusick1:
71135b3e579Smckusick	lw	t0, 0(v1)		# copy stack data
71235b3e579Smckusick	addu	v1, v1, 4
71335b3e579Smckusick	sw	t0, 0(v0)
71435b3e579Smckusick	bne	v1, t1, 1b
7154854f40cSralph	addu	v0, v0, 4
71635b3e579Smckusick	/* FALLTHROUGH */
71735b3e579Smckusick/*
71835b3e579Smckusick * Save registers and state so we can do a longjmp later.
71935b3e579Smckusick * Note: this only works if p != curproc since
7200082cbe2Sbostic * cpu_switch() will copy over pcb_context.
72135b3e579Smckusick *
72235b3e579Smckusick *	savectx(up)
72335b3e579Smckusick *		struct user *up;
72435b3e579Smckusick */
72535b3e579SmckusickALEAF(savectx)
72635b3e579Smckusick	sw	s0, U_PCB_CONTEXT+0(a0)
72735b3e579Smckusick	sw	s1, U_PCB_CONTEXT+4(a0)
72835b3e579Smckusick	sw	s2, U_PCB_CONTEXT+8(a0)
72935b3e579Smckusick	sw	s3, U_PCB_CONTEXT+12(a0)
73035b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG
73135b3e579Smckusick	sw	s4, U_PCB_CONTEXT+16(a0)
73235b3e579Smckusick	sw	s5, U_PCB_CONTEXT+20(a0)
73335b3e579Smckusick	sw	s6, U_PCB_CONTEXT+24(a0)
73435b3e579Smckusick	sw	s7, U_PCB_CONTEXT+28(a0)
73535b3e579Smckusick	sw	sp, U_PCB_CONTEXT+32(a0)
73635b3e579Smckusick	sw	s8, U_PCB_CONTEXT+36(a0)
73735b3e579Smckusick	sw	ra, U_PCB_CONTEXT+40(a0)
73835b3e579Smckusick	sw	v0, U_PCB_CONTEXT+44(a0)
73935b3e579Smckusick	j	ra
74035b3e579Smckusick	move	v0, zero
74135b3e579SmckusickEND(copykstack)
74235b3e579Smckusick
74335b3e579Smckusick/*
744793bd282Sbostic * The following primitives manipulate the run queues.  _whichqs tells which
745793bd282Sbostic * of the 32 queues _qs have processes in them.  Setrunqueue puts processes
746793bd282Sbostic * into queues, Remrq removes them from queues.  The running process is on
7470082cbe2Sbostic * no queue, other processes are on a queue related to p->p_priority, divided
7480082cbe2Sbostic * by 4 actually to shrink the 0-127 range of priorities into the 32 available
74935b3e579Smckusick * queues.
75035b3e579Smckusick */
75135b3e579Smckusick/*
752793bd282Sbostic * setrunqueue(p)
75335b3e579Smckusick *	proc *p;
75435b3e579Smckusick *
75535b3e579Smckusick * Call should be made at splclock(), and p->p_stat should be SRUN.
75635b3e579Smckusick */
757793bd282SbosticNON_LEAF(setrunqueue, STAND_FRAME_SIZE, ra)
75835b3e579Smckusick	subu	sp, sp, STAND_FRAME_SIZE
75935b3e579Smckusick	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
7600082cbe2Sbostic	lw	t0, P_BACK(a0)		## firewall: p->p_back must be 0
76135b3e579Smckusick	sw	ra, STAND_RA_OFFSET(sp)	##
7624cf6ea80Sralph	beq	t0, zero, 1f		##
7630082cbe2Sbostic	lbu	t0, P_PRIORITY(a0)	# put on p->p_priority / 4 queue
764793bd282Sbostic	PANIC("setrunqueue")		##
76535b3e579Smckusick1:
76635b3e579Smckusick	li	t1, 1			# compute corresponding bit
7674854f40cSralph	srl	t0, t0, 2		# compute index into 'whichqs'
76835b3e579Smckusick	sll	t1, t1, t0
76935b3e579Smckusick	lw	t2, whichqs		# set corresponding bit
7704854f40cSralph	nop
77135b3e579Smckusick	or	t2, t2, t1
77235b3e579Smckusick	sw	t2, whichqs
77335b3e579Smckusick	sll	t0, t0, 3		# compute index into 'qs'
77435b3e579Smckusick	la	t1, qs
77535b3e579Smckusick	addu	t0, t0, t1		# t0 = qp = &qs[pri >> 2]
7760082cbe2Sbostic	lw	t1, P_BACK(t0)		# t1 = qp->ph_rlink
7770082cbe2Sbostic	sw	t0, P_FORW(a0)		# p->p_forw = qp
7780082cbe2Sbostic	sw	t1, P_BACK(a0)		# p->p_back = qp->ph_rlink
7790082cbe2Sbostic	sw	a0, P_FORW(t1)		# p->p_back->p_forw = p;
7800082cbe2Sbostic	sw	a0, P_BACK(t0)		# qp->ph_rlink = p
78135b3e579Smckusick	j	ra
7824854f40cSralph	addu	sp, sp, STAND_FRAME_SIZE
783793bd282SbosticEND(setrunqueue)
78435b3e579Smckusick
78535b3e579Smckusick/*
78635b3e579Smckusick * Remrq(p)
78735b3e579Smckusick *
78835b3e579Smckusick * Call should be made at splclock().
78935b3e579Smckusick */
79035b3e579SmckusickNON_LEAF(remrq, STAND_FRAME_SIZE, ra)
79135b3e579Smckusick	subu	sp, sp, STAND_FRAME_SIZE
79235b3e579Smckusick	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
7930082cbe2Sbostic	lbu	t0, P_PRIORITY(a0)	# get from p->p_priority / 4 queue
79435b3e579Smckusick	li	t1, 1			# compute corresponding bit
7954854f40cSralph	srl	t0, t0, 2		# compute index into 'whichqs'
79635b3e579Smckusick	lw	t2, whichqs		# check corresponding bit
7974854f40cSralph	sll	t1, t1, t0
79835b3e579Smckusick	and	v0, t2, t1
79935b3e579Smckusick	sw	ra, STAND_RA_OFFSET(sp)	##
8004cf6ea80Sralph	bne	v0, zero, 1f		##
8010082cbe2Sbostic	lw	v0, P_BACK(a0)		# v0 = p->p_back
802193a1c3eSralph	PANIC("remrq")			## it wasnt recorded to be on its q
80335b3e579Smckusick1:
8040082cbe2Sbostic	lw	v1, P_FORW(a0)		# v1 = p->p_forw
8054854f40cSralph	nop
8060082cbe2Sbostic	sw	v1, P_FORW(v0)		# p->p_back->p_forw = p->p_forw;
8070082cbe2Sbostic	sw	v0, P_BACK(v1)		# p->p_forw->p_back = p->r_rlink
80835b3e579Smckusick	sll	t0, t0, 3		# compute index into 'qs'
80935b3e579Smckusick	la	v0, qs
81035b3e579Smckusick	addu	t0, t0, v0		# t0 = qp = &qs[pri >> 2]
8110082cbe2Sbostic	lw	v0, P_FORW(t0)		# check if queue empty
8124854f40cSralph	nop
81335b3e579Smckusick	bne	v0, t0, 2f		# No. qp->ph_link != qp
8144854f40cSralph	nop
81535b3e579Smckusick	xor	t2, t2, t1		# clear corresponding bit in 'whichqs'
81635b3e579Smckusick	sw	t2, whichqs
81735b3e579Smckusick2:
8180082cbe2Sbostic	sw	zero, P_BACK(a0)	## for firewall checking
81935b3e579Smckusick	j	ra
8204854f40cSralph	addu	sp, sp, STAND_FRAME_SIZE
82135b3e579SmckusickEND(remrq)
82235b3e579Smckusick
82335b3e579Smckusick/*
8240082cbe2Sbostic * switch_exit()
82535b3e579Smckusick *
8260082cbe2Sbostic * At exit of a process, do a cpu_switch for the last time.
82735b3e579Smckusick * The mapping of the pcb at p->p_addr has already been deleted,
82835b3e579Smckusick * and the memory for the pcb+stack has been freed.
82935b3e579Smckusick * All interrupts should be blocked at this point.
83035b3e579Smckusick */
8310082cbe2SbosticLEAF(switch_exit)
83292e9186eSralph	la	v1, nullproc			# save state into garbage proc
83392e9186eSralph	lw	t0, P_UPTE+0(v1)		# t0 = first u. pte
83492e9186eSralph	lw	t1, P_UPTE+4(v1)		# t1 = 2nd u. pte
83535b3e579Smckusick	li	v0, UADDR			# v0 = first HI entry
83635b3e579Smckusick	mtc0	zero, MACH_COP_0_TLB_INDEX	# set the index register
83735b3e579Smckusick	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
83835b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_LOW		# init low entry
83935b3e579Smckusick	li	t0, 1 << VMMACH_TLB_INDEX_SHIFT
84035b3e579Smckusick	tlbwi					# Write the TLB entry.
84135b3e579Smckusick	addu	v0, v0, NBPG			# 2nd HI entry
84235b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_INDEX	# set the index register
84335b3e579Smckusick	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
84435b3e579Smckusick	mtc0	t1, MACH_COP_0_TLB_LOW		# init low entry
84592e9186eSralph	sw	zero, curproc
84635b3e579Smckusick	tlbwi					# Write the TLB entry.
8470082cbe2Sbostic	b	cpu_switch
84892e9186eSralph	li	sp, KERNELSTACK - START_FRAME	# switch to standard stack
8490082cbe2SbosticEND(switch_exit)
85035b3e579Smckusick
85135b3e579Smckusick/*
8520082cbe2Sbostic * When no processes are on the runq, cpu_switch branches to idle
85335b3e579Smckusick * to wait for something to come ready.
8540082cbe2Sbostic * Note: this is really a part of cpu_switch() but defined here for kernel
8550bb4cdc4Sralph * profiling.
85635b3e579Smckusick */
85735b3e579SmckusickLEAF(idle)
85835b3e579Smckusick	li	t0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
85935b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# enable all interrupts
860986ec53bSralph	sw	zero, curproc			# set curproc NULL for stats
86135b3e579Smckusick1:
86235b3e579Smckusick	lw	t0, whichqs			# look for non-empty queue
8634cf6ea80Sralph	nop
86435b3e579Smckusick	beq	t0, zero, 1b
8654cf6ea80Sralph	nop
86635b3e579Smckusick	b	sw1
8674cf6ea80Sralph	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable all interrupts
86835b3e579SmckusickEND(idle)
86935b3e579Smckusick
87035b3e579Smckusick/*
8710082cbe2Sbostic * cpu_switch()
87235b3e579Smckusick * Find the highest priority process and resume it.
87335b3e579Smckusick */
8740082cbe2SbosticNON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra)
87535b3e579Smckusick	sw	sp, UADDR+U_PCB_CONTEXT+32	# save old sp
87635b3e579Smckusick	subu	sp, sp, STAND_FRAME_SIZE
87735b3e579Smckusick	sw	ra, STAND_RA_OFFSET(sp)
87835b3e579Smckusick	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
879049c0333Smckusick#ifdef DEBUG
880049c0333Smckusick	lw	a1, intr_level
881049c0333Smckusick	sw	a0, STAND_FRAME_SIZE(sp)
882049c0333Smckusick	beq	a1, zero, 1f
883049c0333Smckusick	nop
884049c0333Smckusick	PANIC("cpu_switch: intr_level %d")	# can't sleep in interrupt()
885049c0333Smckusick1:
886049c0333Smckusick#endif
88735b3e579Smckusick	lw	t2, cnt+V_SWTCH			# for statistics
88835b3e579Smckusick	lw	t1, whichqs			# look for non-empty queue
88992e9186eSralph	sw	s0, UADDR+U_PCB_CONTEXT+0	# do a 'savectx()'
89092e9186eSralph	sw	s1, UADDR+U_PCB_CONTEXT+4
89192e9186eSralph	sw	s2, UADDR+U_PCB_CONTEXT+8
89292e9186eSralph	sw	s3, UADDR+U_PCB_CONTEXT+12
89335b3e579Smckusick	mfc0	t0, MACH_COP_0_STATUS_REG	# t0 = saved status register
89492e9186eSralph	sw	s4, UADDR+U_PCB_CONTEXT+16
89592e9186eSralph	sw	s5, UADDR+U_PCB_CONTEXT+20
89692e9186eSralph	sw	s6, UADDR+U_PCB_CONTEXT+24
89792e9186eSralph	sw	s7, UADDR+U_PCB_CONTEXT+28
89892e9186eSralph	sw	s8, UADDR+U_PCB_CONTEXT+36
89935b3e579Smckusick	sw	ra, UADDR+U_PCB_CONTEXT+40	# save return address
90035b3e579Smckusick	sw	t0, UADDR+U_PCB_CONTEXT+44	# save status register
90135b3e579Smckusick	addu	t2, t2, 1
90235b3e579Smckusick	sw	t2, cnt+V_SWTCH
90392e9186eSralph	beq	t1, zero, idle			# if none, idle
90435b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable all interrupts
9054cf6ea80Sralphsw1:
9064cf6ea80Sralph	nop					# wait for intrs disabled
90735b3e579Smckusick	nop
90835b3e579Smckusick	lw	t0, whichqs			# look for non-empty queue
90935b3e579Smckusick	li	t2, -1				# t2 = lowest bit set
91035b3e579Smckusick	beq	t0, zero, idle			# if none, idle
91135b3e579Smckusick	move	t3, t0				# t3 = saved whichqs
91235b3e579Smckusick1:
9134854f40cSralph	addu	t2, t2, 1
91435b3e579Smckusick	and	t1, t0, 1			# bit set?
91535b3e579Smckusick	beq	t1, zero, 1b
91635b3e579Smckusick	srl	t0, t0, 1			# try next bit
91735b3e579Smckusick/*
91835b3e579Smckusick * Remove process from queue.
91935b3e579Smckusick */
92035b3e579Smckusick	sll	t0, t2, 3
92135b3e579Smckusick	la	t1, qs
92235b3e579Smckusick	addu	t0, t0, t1			# t0 = qp = &qs[highbit]
9230082cbe2Sbostic	lw	a0, P_FORW(t0)			# a0 = p = highest pri process
92435b3e579Smckusick	nop
9250082cbe2Sbostic	lw	v0, P_FORW(a0)			# v0 = p->p_forw
92635b3e579Smckusick	bne	t0, a0, 2f			# make sure something in queue
9270082cbe2Sbostic	sw	v0, P_FORW(t0)			# qp->ph_link = p->p_forw;
9280082cbe2Sbostic	PANIC("cpu_switch")			# nothing in queue
92935b3e579Smckusick2:
9300082cbe2Sbostic	sw	t0, P_BACK(v0)			# p->p_forw->p_back = qp
93135b3e579Smckusick	bne	v0, t0, 3f			# queue still not empty
9320082cbe2Sbostic	sw	zero, P_BACK(a0)		## for firewall checking
93335b3e579Smckusick	li	v1, 1				# compute bit in 'whichqs'
93435b3e579Smckusick	sll	v1, v1, t2
93535b3e579Smckusick	xor	t3, t3, v1			# clear bit in 'whichqs'
93635b3e579Smckusick	sw	t3, whichqs
93735b3e579Smckusick3:
93835b3e579Smckusick/*
93992e9186eSralph * Switch to new context.
94035b3e579Smckusick */
94135b3e579Smckusick	sw	zero, want_resched
94235b3e579Smckusick	jal	pmap_alloc_tlbpid		# v0 = TLB PID
9432e5b9d54Smckusick	move	s0, a0				# BDSLOT: save p
9442e5b9d54Smckusick	sw	s0, curproc			# set curproc
94535b3e579Smckusick	sll	v0, v0, VMMACH_TLB_PID_SHIFT	# v0 = aligned PID
9462e5b9d54Smckusick	lw	t0, P_UPTE+0(s0)		# t0 = first u. pte
9472e5b9d54Smckusick	lw	t1, P_UPTE+4(s0)		# t1 = 2nd u. pte
9484cf6ea80Sralph	or	v0, v0, UADDR			# v0 = first HI entry
94935b3e579Smckusick/*
95035b3e579Smckusick * Resume process indicated by the pte's for its u struct
95135b3e579Smckusick * NOTE: This is hard coded to UPAGES == 2.
95235b3e579Smckusick * Also, there should be no TLB faults at this point.
95335b3e579Smckusick */
95435b3e579Smckusick	mtc0	zero, MACH_COP_0_TLB_INDEX	# set the index register
95535b3e579Smckusick	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
95635b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_LOW		# init low entry
95735b3e579Smckusick	li	t0, 1 << VMMACH_TLB_INDEX_SHIFT
95835b3e579Smckusick	tlbwi					# Write the TLB entry.
95935b3e579Smckusick	addu	v0, v0, NBPG			# 2nd HI entry
96035b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_INDEX	# set the index register
96135b3e579Smckusick	mtc0	v0, MACH_COP_0_TLB_HI		# init high entry
96235b3e579Smckusick	mtc0	t1, MACH_COP_0_TLB_LOW		# init low entry
96335b3e579Smckusick	nop
96435b3e579Smckusick	tlbwi					# Write the TLB entry.
96535b3e579Smckusick/*
96635b3e579Smckusick * Now running on new u struct.
96735b3e579Smckusick * Restore registers and return.
96835b3e579Smckusick */
96935b3e579Smckusick	lw	v0, UADDR+U_PCB_CONTEXT+44	# restore kernel context
97035b3e579Smckusick	lw	ra, UADDR+U_PCB_CONTEXT+40
97135b3e579Smckusick	lw	s0, UADDR+U_PCB_CONTEXT+0
97235b3e579Smckusick	lw	s1, UADDR+U_PCB_CONTEXT+4
97335b3e579Smckusick	lw	s2, UADDR+U_PCB_CONTEXT+8
97435b3e579Smckusick	lw	s3, UADDR+U_PCB_CONTEXT+12
97535b3e579Smckusick	lw	s4, UADDR+U_PCB_CONTEXT+16
97635b3e579Smckusick	lw	s5, UADDR+U_PCB_CONTEXT+20
97735b3e579Smckusick	lw	s6, UADDR+U_PCB_CONTEXT+24
97835b3e579Smckusick	lw	s7, UADDR+U_PCB_CONTEXT+28
97935b3e579Smckusick	lw	sp, UADDR+U_PCB_CONTEXT+32
98035b3e579Smckusick	lw	s8, UADDR+U_PCB_CONTEXT+36
98135b3e579Smckusick	mtc0	v0, MACH_COP_0_STATUS_REG
98235b3e579Smckusick	j	ra
98335b3e579Smckusick	li	v0, 1				# possible return to 'savectx()'
9840082cbe2SbosticEND(cpu_switch)
98535b3e579Smckusick
98635b3e579Smckusick/*
9870bb4cdc4Sralph * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to
9880bb4cdc4Sralph * user text space.
9890bb4cdc4Sralph * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to
9900bb4cdc4Sralph * user data space.
99135b3e579Smckusick */
99235b3e579SmckusickLEAF(fuword)
99335b3e579SmckusickALEAF(fuiword)
99435b3e579Smckusick	blt	a0, zero, fswberr	# make sure address is in user space
9954854f40cSralph	li	v0, FSWBERR
99635b3e579Smckusick	sw	v0, UADDR+U_PCB_ONFAULT
99735b3e579Smckusick	lw	v0, 0(a0)		# fetch word
99835b3e579Smckusick	j	ra
9994854f40cSralph	sw	zero, UADDR+U_PCB_ONFAULT
100035b3e579SmckusickEND(fuword)
100135b3e579Smckusick
10020bb4cdc4SralphLEAF(fusword)
10030bb4cdc4SralphALEAF(fuisword)
10040bb4cdc4Sralph	blt	a0, zero, fswberr	# make sure address is in user space
10054854f40cSralph	li	v0, FSWBERR
10060bb4cdc4Sralph	sw	v0, UADDR+U_PCB_ONFAULT
10070bb4cdc4Sralph	lhu	v0, 0(a0)		# fetch short
10080bb4cdc4Sralph	j	ra
10094854f40cSralph	sw	zero, UADDR+U_PCB_ONFAULT
10100bb4cdc4SralphEND(fusword)
10110bb4cdc4Sralph
101235b3e579SmckusickLEAF(fubyte)
101335b3e579SmckusickALEAF(fuibyte)
101435b3e579Smckusick	blt	a0, zero, fswberr	# make sure address is in user space
10154854f40cSralph	li	v0, FSWBERR
101635b3e579Smckusick	sw	v0, UADDR+U_PCB_ONFAULT
101735b3e579Smckusick	lbu	v0, 0(a0)		# fetch byte
101835b3e579Smckusick	j	ra
10194854f40cSralph	sw	zero, UADDR+U_PCB_ONFAULT
102035b3e579SmckusickEND(fubyte)
102135b3e579Smckusick
102235b3e579SmckusickLEAF(suword)
102335b3e579Smckusick	blt	a0, zero, fswberr	# make sure address is in user space
10244854f40cSralph	li	v0, FSWBERR
102535b3e579Smckusick	sw	v0, UADDR+U_PCB_ONFAULT
102635b3e579Smckusick	sw	a1, 0(a0)		# store word
102735b3e579Smckusick	sw	zero, UADDR+U_PCB_ONFAULT
102835b3e579Smckusick	j	ra
10294854f40cSralph	move	v0, zero
103035b3e579SmckusickEND(suword)
103135b3e579Smckusick
10324cf6ea80Sralph/*
10334cf6ea80Sralph * Have to flush instruction cache afterwards.
10344cf6ea80Sralph */
10354cf6ea80SralphLEAF(suiword)
10364cf6ea80Sralph	blt	a0, zero, fswberr	# make sure address is in user space
10374854f40cSralph	li	v0, FSWBERR
10384cf6ea80Sralph	sw	v0, UADDR+U_PCB_ONFAULT
10394cf6ea80Sralph	sw	a1, 0(a0)		# store word
10404cf6ea80Sralph	sw	zero, UADDR+U_PCB_ONFAULT
10414cf6ea80Sralph	move	v0, zero
10424cf6ea80Sralph	b	MachFlushICache		# NOTE: this should not clobber v0!
10434854f40cSralph	li	a1, 4			# size of word
10444cf6ea80SralphEND(suiword)
10454cf6ea80Sralph
10464cf6ea80Sralph/*
10474cf6ea80Sralph * Will have to flush the instruction cache if byte merging is done in hardware.
10484cf6ea80Sralph */
10490bb4cdc4SralphLEAF(susword)
10500bb4cdc4SralphALEAF(suisword)
10510bb4cdc4Sralph	blt	a0, zero, fswberr	# make sure address is in user space
10524854f40cSralph	li	v0, FSWBERR
10530bb4cdc4Sralph	sw	v0, UADDR+U_PCB_ONFAULT
10540bb4cdc4Sralph	sh	a1, 0(a0)		# store short
10550bb4cdc4Sralph	sw	zero, UADDR+U_PCB_ONFAULT
10560bb4cdc4Sralph	j	ra
10574854f40cSralph	move	v0, zero
10580bb4cdc4SralphEND(susword)
10590bb4cdc4Sralph
106035b3e579SmckusickLEAF(subyte)
106135b3e579SmckusickALEAF(suibyte)
106235b3e579Smckusick	blt	a0, zero, fswberr	# make sure address is in user space
10634854f40cSralph	li	v0, FSWBERR
106435b3e579Smckusick	sw	v0, UADDR+U_PCB_ONFAULT
106535b3e579Smckusick	sb	a1, 0(a0)		# store byte
106635b3e579Smckusick	sw	zero, UADDR+U_PCB_ONFAULT
106735b3e579Smckusick	j	ra
10684854f40cSralph	move	v0, zero
106935b3e579SmckusickEND(subyte)
107035b3e579Smckusick
107135b3e579SmckusickLEAF(fswberr)
107235b3e579Smckusick	j	ra
10734854f40cSralph	li	v0, -1
107435b3e579SmckusickEND(fswberr)
107535b3e579Smckusick
107635b3e579Smckusick/*
10770bb4cdc4Sralph * fuswintr and suswintr are just like fusword and susword except that if
10780bb4cdc4Sralph * the page is not in memory or would cause a trap, then we return an error.
10790082cbe2Sbostic * The important thing is to prevent sleep() and switch().
10800bb4cdc4Sralph */
10810bb4cdc4SralphLEAF(fuswintr)
10820bb4cdc4Sralph	blt	a0, zero, fswintrberr	# make sure address is in user space
10834854f40cSralph	li	v0, FSWINTRBERR
10840bb4cdc4Sralph	sw	v0, UADDR+U_PCB_ONFAULT
10850bb4cdc4Sralph	lhu	v0, 0(a0)		# fetch short
10860bb4cdc4Sralph	j	ra
10874854f40cSralph	sw	zero, UADDR+U_PCB_ONFAULT
10880bb4cdc4SralphEND(fuswintr)
10890bb4cdc4Sralph
10900bb4cdc4SralphLEAF(suswintr)
10910bb4cdc4Sralph	blt	a0, zero, fswintrberr	# make sure address is in user space
10924854f40cSralph	li	v0, FSWINTRBERR
10930bb4cdc4Sralph	sw	v0, UADDR+U_PCB_ONFAULT
10940bb4cdc4Sralph	sh	a1, 0(a0)		# store short
10950bb4cdc4Sralph	sw	zero, UADDR+U_PCB_ONFAULT
10960bb4cdc4Sralph	j	ra
10974854f40cSralph	move	v0, zero
10980bb4cdc4SralphEND(suswintr)
10990bb4cdc4Sralph
11000bb4cdc4SralphLEAF(fswintrberr)
11010bb4cdc4Sralph	j	ra
11024854f40cSralph	li	v0, -1
11030bb4cdc4SralphEND(fswintrberr)
11040bb4cdc4Sralph
11050bb4cdc4Sralph/*
110635b3e579Smckusick * Insert 'p' after 'q'.
110735b3e579Smckusick *	_insque(p, q)
110835b3e579Smckusick *		caddr_t p, q;
110935b3e579Smckusick */
111035b3e579SmckusickLEAF(_insque)
111135b3e579Smckusick	lw	v0, 0(a1)		# v0 = q->next
111235b3e579Smckusick	sw	a1, 4(a0)		# p->prev = q
111335b3e579Smckusick	sw	v0, 0(a0)		# p->next = q->next
111435b3e579Smckusick	sw	a0, 4(v0)		# q->next->prev = p
111535b3e579Smckusick	j	ra
11164854f40cSralph	sw	a0, 0(a1)		# q->next = p
111735b3e579SmckusickEND(_insque)
111835b3e579Smckusick
111935b3e579Smckusick/*
112035b3e579Smckusick * Remove item 'p' from queue.
112135b3e579Smckusick *	_remque(p)
112235b3e579Smckusick *		caddr_t p;
112335b3e579Smckusick */
112435b3e579SmckusickLEAF(_remque)
112535b3e579Smckusick	lw	v0, 0(a0)		# v0 = p->next
112635b3e579Smckusick	lw	v1, 4(a0)		# v1 = p->prev
11274854f40cSralph	nop
112835b3e579Smckusick	sw	v0, 0(v1)		# p->prev->next = p->next
112935b3e579Smckusick	j	ra
11304854f40cSralph	sw	v1, 4(v0)		# p->next->prev = p->prev
113135b3e579SmckusickEND(_remque)
113235b3e579Smckusick
113335b3e579Smckusick/*
113435b3e579Smckusick * This code is copied to the UTLB exception vector address to
113535b3e579Smckusick * handle user level TLB translation misses.
113635b3e579Smckusick * NOTE: This code must be relocatable!!!
113735b3e579Smckusick */
113835b3e579Smckusick	.globl	MachUTLBMiss
113935b3e579SmckusickMachUTLBMiss:
114035b3e579Smckusick	.set	noat
114135b3e579Smckusick	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the virtual address
114292e9186eSralph	lw	k1, UADDR+U_PCB_SEGTAB		# get the current segment table
114392e9186eSralph	bltz	k0, 1f				# R3000 chip bug
114492e9186eSralph	srl	k0, k0, SEGSHIFT		# compute segment table index
114592e9186eSralph	sll	k0, k0, 2
114692e9186eSralph	addu	k1, k1, k0
114792e9186eSralph	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the virtual address
114892e9186eSralph	lw	k1, 0(k1)			# get pointer to segment map
114992e9186eSralph	srl	k0, k0, PGSHIFT - 2		# compute segment map index
115092e9186eSralph	andi	k0, k0, (NPTEPG - 1) << 2
115192e9186eSralph	beq	k1, zero, 2f			# invalid segment map
115292e9186eSralph	addu	k1, k1, k0			# index into segment map
115392e9186eSralph	lw	k0, 0(k1)			# get page PTE
115435b3e579Smckusick	nop
115592e9186eSralph	beq	k0, zero, 2f			# dont load invalid entries
115635b3e579Smckusick	mtc0	k0, MACH_COP_0_TLB_LOW
115792e9186eSralph	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
115835b3e579Smckusick	tlbwr					# update TLB
115992e9186eSralph	j	k1
116035b3e579Smckusick	rfe
116135b3e579Smckusick1:
116292e9186eSralph	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
116392e9186eSralph	nop
116492e9186eSralph	j	k1
116592e9186eSralph	rfe
116692e9186eSralph2:
116792e9186eSralph	j	SlowFault			# handle the rest
116835b3e579Smckusick	nop
116935b3e579Smckusick	.set	at
117035b3e579Smckusick	.globl	MachUTLBMissEnd
117135b3e579SmckusickMachUTLBMissEnd:
117235b3e579Smckusick
117335b3e579Smckusick/*
117435b3e579Smckusick * This code is copied to the general exception vector address to
117535b3e579Smckusick * handle all execptions except RESET and UTLBMiss.
117635b3e579Smckusick * NOTE: This code must be relocatable!!!
117735b3e579Smckusick */
117835b3e579Smckusick	.globl	MachException
117935b3e579SmckusickMachException:
118035b3e579Smckusick/*
118135b3e579Smckusick * Find out what mode we came from and jump to the proper handler.
118235b3e579Smckusick */
118335b3e579Smckusick	.set	noat
118435b3e579Smckusick	mfc0	k0, MACH_COP_0_STATUS_REG	# Get the status register
118535b3e579Smckusick	mfc0	k1, MACH_COP_0_CAUSE_REG	# Get the cause register value.
118635b3e579Smckusick	and	k0, k0, MACH_SR_KU_PREV		# test for user mode
1187d85b31faSralph	sll	k0, k0, 3			# shift user bit for cause index
118835b3e579Smckusick	and	k1, k1, MACH_CR_EXC_CODE	# Mask out the cause bits.
1189d85b31faSralph	or	k1, k1, k0			# change index to user table
119035b3e579Smckusick1:
119135b3e579Smckusick	la	k0, machExceptionTable		# get base of the jump table
1192d85b31faSralph	addu	k0, k0, k1			# Get the address of the
119335b3e579Smckusick						#  function entry.  Note that
119435b3e579Smckusick						#  the cause is already
119535b3e579Smckusick						#  shifted left by 2 bits so
1196193a1c3eSralph						#  we dont have to shift.
119735b3e579Smckusick	lw	k0, 0(k0)			# Get the function address
119835b3e579Smckusick	nop
119935b3e579Smckusick	j	k0				# Jump to the function.
120035b3e579Smckusick	nop
120135b3e579Smckusick	.set	at
120235b3e579Smckusick	.globl	MachExceptionEnd
120335b3e579SmckusickMachExceptionEnd:
120435b3e579Smckusick
120535b3e579Smckusick/*
120635b3e579Smckusick * We couldn't find a TLB entry.
120735b3e579Smckusick * Find out what mode we came from and call the appropriate handler.
120835b3e579Smckusick */
120935b3e579SmckusickSlowFault:
121092e9186eSralph	.set	noat
121135b3e579Smckusick	mfc0	k0, MACH_COP_0_STATUS_REG
121235b3e579Smckusick	nop
121335b3e579Smckusick	and	k0, k0, MACH_SR_KU_PREV
121435b3e579Smckusick	bne	k0, zero, MachUserGenException
121535b3e579Smckusick	nop
121635b3e579Smckusick	.set	at
121735b3e579Smckusick/*
121835b3e579Smckusick * Fall though ...
121935b3e579Smckusick */
122035b3e579Smckusick
122135b3e579Smckusick/*----------------------------------------------------------------------------
122235b3e579Smckusick *
122335b3e579Smckusick * MachKernGenException --
122435b3e579Smckusick *
122535b3e579Smckusick *	Handle an exception from kernel mode.
122635b3e579Smckusick *
122735b3e579Smckusick * Results:
122835b3e579Smckusick *	None.
122935b3e579Smckusick *
123035b3e579Smckusick * Side effects:
123135b3e579Smckusick *	None.
123235b3e579Smckusick *
123335b3e579Smckusick *----------------------------------------------------------------------------
123435b3e579Smckusick */
123535b3e579Smckusick
123635b3e579Smckusick/*
123735b3e579Smckusick * The kernel exception stack contains 18 saved general registers,
123835b3e579Smckusick * the status register and the multiply lo and high registers.
123935b3e579Smckusick * In addition, we set this up for linkage conventions.
124035b3e579Smckusick */
124135b3e579Smckusick#define KERN_REG_SIZE		(18 * 4)
124235b3e579Smckusick#define KERN_REG_OFFSET		(STAND_FRAME_SIZE)
124335b3e579Smckusick#define KERN_SR_OFFSET		(STAND_FRAME_SIZE + KERN_REG_SIZE)
124435b3e579Smckusick#define KERN_MULT_LO_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
124535b3e579Smckusick#define KERN_MULT_HI_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
124635b3e579Smckusick#define	KERN_EXC_FRAME_SIZE	(STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
124735b3e579Smckusick
124892e9186eSralphNNON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra)
124935b3e579Smckusick	.set	noat
12504cf6ea80Sralph#ifdef KADB
12514cf6ea80Sralph	la	k0, kdbpcb			# save registers for kadb
12524cf6ea80Sralph	sw	s0, (S0 * 4)(k0)
12534cf6ea80Sralph	sw	s1, (S1 * 4)(k0)
12544cf6ea80Sralph	sw	s2, (S2 * 4)(k0)
12554cf6ea80Sralph	sw	s3, (S3 * 4)(k0)
12564cf6ea80Sralph	sw	s4, (S4 * 4)(k0)
12574cf6ea80Sralph	sw	s5, (S5 * 4)(k0)
12584cf6ea80Sralph	sw	s6, (S6 * 4)(k0)
12594cf6ea80Sralph	sw	s7, (S7 * 4)(k0)
12604cf6ea80Sralph	sw	s8, (S8 * 4)(k0)
12614cf6ea80Sralph	sw	gp, (GP * 4)(k0)
12624cf6ea80Sralph	sw	sp, (SP * 4)(k0)
12634cf6ea80Sralph#endif
126435b3e579Smckusick	subu	sp, sp, KERN_EXC_FRAME_SIZE
126535b3e579Smckusick	.mask	0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE)
126635b3e579Smckusick/*
126735b3e579Smckusick * Save the relevant kernel registers onto the stack.
126835b3e579Smckusick * We don't need to save s0 - s8, sp and gp because
126935b3e579Smckusick * the compiler does it for us.
127035b3e579Smckusick */
127135b3e579Smckusick	sw	AT, KERN_REG_OFFSET + 0(sp)
127235b3e579Smckusick	sw	v0, KERN_REG_OFFSET + 4(sp)
127335b3e579Smckusick	sw	v1, KERN_REG_OFFSET + 8(sp)
127435b3e579Smckusick	sw	a0, KERN_REG_OFFSET + 12(sp)
127535b3e579Smckusick	mflo	v0
127635b3e579Smckusick	mfhi	v1
127735b3e579Smckusick	sw	a1, KERN_REG_OFFSET + 16(sp)
127835b3e579Smckusick	sw	a2, KERN_REG_OFFSET + 20(sp)
127935b3e579Smckusick	sw	a3, KERN_REG_OFFSET + 24(sp)
128035b3e579Smckusick	sw	t0, KERN_REG_OFFSET + 28(sp)
128135b3e579Smckusick	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
128235b3e579Smckusick	sw	t1, KERN_REG_OFFSET + 32(sp)
128335b3e579Smckusick	sw	t2, KERN_REG_OFFSET + 36(sp)
128435b3e579Smckusick	sw	t3, KERN_REG_OFFSET + 40(sp)
128535b3e579Smckusick	sw	t4, KERN_REG_OFFSET + 44(sp)
128635b3e579Smckusick	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
128735b3e579Smckusick	sw	t5, KERN_REG_OFFSET + 48(sp)
128835b3e579Smckusick	sw	t6, KERN_REG_OFFSET + 52(sp)
128935b3e579Smckusick	sw	t7, KERN_REG_OFFSET + 56(sp)
129035b3e579Smckusick	sw	t8, KERN_REG_OFFSET + 60(sp)
129135b3e579Smckusick	mfc0	a2, MACH_COP_0_BAD_VADDR	# Third arg is the fault addr.
129235b3e579Smckusick	sw	t9, KERN_REG_OFFSET + 64(sp)
129335b3e579Smckusick	sw	ra, KERN_REG_OFFSET + 68(sp)
129435b3e579Smckusick	sw	v0, KERN_MULT_LO_OFFSET(sp)
129535b3e579Smckusick	sw	v1, KERN_MULT_HI_OFFSET(sp)
129635b3e579Smckusick	mfc0	a3, MACH_COP_0_EXC_PC		# Fourth arg is the pc.
129735b3e579Smckusick	sw	a0, KERN_SR_OFFSET(sp)
129835b3e579Smckusick/*
129935b3e579Smckusick * Call the exception handler.
130035b3e579Smckusick */
130135b3e579Smckusick	jal	trap
130235b3e579Smckusick	sw	a3, STAND_RA_OFFSET(sp)		# for debugging
130335b3e579Smckusick/*
130435b3e579Smckusick * Restore registers and return from the exception.
130535b3e579Smckusick * v0 contains the return address.
130635b3e579Smckusick */
130735b3e579Smckusick	lw	a0, KERN_SR_OFFSET(sp)
130835b3e579Smckusick	lw	t0, KERN_MULT_LO_OFFSET(sp)
130935b3e579Smckusick	lw	t1, KERN_MULT_HI_OFFSET(sp)
131035b3e579Smckusick	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
131135b3e579Smckusick	mtlo	t0
131235b3e579Smckusick	mthi	t1
131335b3e579Smckusick	move	k0, v0
131435b3e579Smckusick	lw	AT, KERN_REG_OFFSET + 0(sp)
131535b3e579Smckusick	lw	v0, KERN_REG_OFFSET + 4(sp)
131635b3e579Smckusick	lw	v1, KERN_REG_OFFSET + 8(sp)
131735b3e579Smckusick	lw	a0, KERN_REG_OFFSET + 12(sp)
131835b3e579Smckusick	lw	a1, KERN_REG_OFFSET + 16(sp)
131935b3e579Smckusick	lw	a2, KERN_REG_OFFSET + 20(sp)
132035b3e579Smckusick	lw	a3, KERN_REG_OFFSET + 24(sp)
132135b3e579Smckusick	lw	t0, KERN_REG_OFFSET + 28(sp)
132235b3e579Smckusick	lw	t1, KERN_REG_OFFSET + 32(sp)
132335b3e579Smckusick	lw	t2, KERN_REG_OFFSET + 36(sp)
132435b3e579Smckusick	lw	t3, KERN_REG_OFFSET + 40(sp)
132535b3e579Smckusick	lw	t4, KERN_REG_OFFSET + 44(sp)
132635b3e579Smckusick	lw	t5, KERN_REG_OFFSET + 48(sp)
132735b3e579Smckusick	lw	t6, KERN_REG_OFFSET + 52(sp)
132835b3e579Smckusick	lw	t7, KERN_REG_OFFSET + 56(sp)
132935b3e579Smckusick	lw	t8, KERN_REG_OFFSET + 60(sp)
133035b3e579Smckusick	lw	t9, KERN_REG_OFFSET + 64(sp)
133135b3e579Smckusick	lw	ra, KERN_REG_OFFSET + 68(sp)
133235b3e579Smckusick	addu	sp, sp, KERN_EXC_FRAME_SIZE
133335b3e579Smckusick	j	k0				# Now return from the
133435b3e579Smckusick	rfe					#  exception.
133535b3e579Smckusick	.set	at
133635b3e579SmckusickEND(MachKernGenException)
133735b3e579Smckusick
133835b3e579Smckusick/*----------------------------------------------------------------------------
133935b3e579Smckusick *
134035b3e579Smckusick * MachUserGenException --
134135b3e579Smckusick *
134235b3e579Smckusick *	Handle an exception from user mode.
134335b3e579Smckusick *
134435b3e579Smckusick * Results:
134535b3e579Smckusick * 	None.
134635b3e579Smckusick *
134735b3e579Smckusick * Side effects:
134835b3e579Smckusick *	None.
134935b3e579Smckusick *
135035b3e579Smckusick *----------------------------------------------------------------------------
135135b3e579Smckusick */
135292e9186eSralphNNON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra)
135335b3e579Smckusick	.set	noat
135435b3e579Smckusick	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
135535b3e579Smckusick/*
135635b3e579Smckusick * Save all of the registers except for the kernel temporaries in u.u_pcb.
135735b3e579Smckusick */
135835b3e579Smckusick	sw	AT, UADDR+U_PCB_REGS+(AST * 4)
135935b3e579Smckusick	sw	v0, UADDR+U_PCB_REGS+(V0 * 4)
136035b3e579Smckusick	sw	v1, UADDR+U_PCB_REGS+(V1 * 4)
136135b3e579Smckusick	sw	a0, UADDR+U_PCB_REGS+(A0 * 4)
136235b3e579Smckusick	mflo	v0
136335b3e579Smckusick	sw	a1, UADDR+U_PCB_REGS+(A1 * 4)
136435b3e579Smckusick	sw	a2, UADDR+U_PCB_REGS+(A2 * 4)
136535b3e579Smckusick	sw	a3, UADDR+U_PCB_REGS+(A3 * 4)
136635b3e579Smckusick	sw	t0, UADDR+U_PCB_REGS+(T0 * 4)
136735b3e579Smckusick	mfhi	v1
136835b3e579Smckusick	sw	t1, UADDR+U_PCB_REGS+(T1 * 4)
136935b3e579Smckusick	sw	t2, UADDR+U_PCB_REGS+(T2 * 4)
137035b3e579Smckusick	sw	t3, UADDR+U_PCB_REGS+(T3 * 4)
137135b3e579Smckusick	sw	t4, UADDR+U_PCB_REGS+(T4 * 4)
137235b3e579Smckusick	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
137335b3e579Smckusick	sw	t5, UADDR+U_PCB_REGS+(T5 * 4)
137435b3e579Smckusick	sw	t6, UADDR+U_PCB_REGS+(T6 * 4)
137535b3e579Smckusick	sw	t7, UADDR+U_PCB_REGS+(T7 * 4)
137635b3e579Smckusick	sw	s0, UADDR+U_PCB_REGS+(S0 * 4)
137735b3e579Smckusick	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
137835b3e579Smckusick	sw	s1, UADDR+U_PCB_REGS+(S1 * 4)
137935b3e579Smckusick	sw	s2, UADDR+U_PCB_REGS+(S2 * 4)
138035b3e579Smckusick	sw	s3, UADDR+U_PCB_REGS+(S3 * 4)
138135b3e579Smckusick	sw	s4, UADDR+U_PCB_REGS+(S4 * 4)
138235b3e579Smckusick	mfc0	a2, MACH_COP_0_BAD_VADDR	# Third arg is the fault addr
138335b3e579Smckusick	sw	s5, UADDR+U_PCB_REGS+(S5 * 4)
138435b3e579Smckusick	sw	s6, UADDR+U_PCB_REGS+(S6 * 4)
138535b3e579Smckusick	sw	s7, UADDR+U_PCB_REGS+(S7 * 4)
138635b3e579Smckusick	sw	t8, UADDR+U_PCB_REGS+(T8 * 4)
138735b3e579Smckusick	mfc0	a3, MACH_COP_0_EXC_PC		# Fourth arg is the pc.
138835b3e579Smckusick	sw	t9, UADDR+U_PCB_REGS+(T9 * 4)
138935b3e579Smckusick	sw	gp, UADDR+U_PCB_REGS+(GP * 4)
139035b3e579Smckusick	sw	sp, UADDR+U_PCB_REGS+(SP * 4)
139135b3e579Smckusick	sw	s8, UADDR+U_PCB_REGS+(S8 * 4)
139235b3e579Smckusick	li	sp, KERNELSTACK - STAND_FRAME_SIZE	# switch to kernel SP
139335b3e579Smckusick	sw	ra, UADDR+U_PCB_REGS+(RA * 4)
139435b3e579Smckusick	sw	v0, UADDR+U_PCB_REGS+(MULLO * 4)
139535b3e579Smckusick	sw	v1, UADDR+U_PCB_REGS+(MULHI * 4)
139635b3e579Smckusick	sw	a0, UADDR+U_PCB_REGS+(SR * 4)
1397193a1c3eSralph #	la	gp, _gp				# switch to kernel GP
139835b3e579Smckusick	sw	a3, UADDR+U_PCB_REGS+(PC * 4)
139935b3e579Smckusick	sw	a3, STAND_RA_OFFSET(sp)		# for debugging
1400193a1c3eSralph	.set	at
140135b3e579Smckusick	and	t0, a0, ~MACH_SR_COP_1_BIT	# Turn off the FPU.
1402193a1c3eSralph	.set	noat
140335b3e579Smckusick/*
140435b3e579Smckusick * Call the exception handler.
140535b3e579Smckusick */
140635b3e579Smckusick	jal	trap
140735b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG
140835b3e579Smckusick/*
140935b3e579Smckusick * Restore user registers and return. NOTE: interrupts are enabled.
141035b3e579Smckusick */
141135b3e579Smckusick	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
141235b3e579Smckusick	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
141335b3e579Smckusick	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
141435b3e579Smckusick	mtc0	a0, MACH_COP_0_STATUS_REG	# this should disable interrupts
141535b3e579Smckusick	mtlo	t0
141635b3e579Smckusick	mthi	t1
141735b3e579Smckusick	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
141835b3e579Smckusick	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
141935b3e579Smckusick	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
142035b3e579Smckusick	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
142135b3e579Smckusick	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
142235b3e579Smckusick	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
142335b3e579Smckusick	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
142435b3e579Smckusick	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
142535b3e579Smckusick	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
142635b3e579Smckusick	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
142735b3e579Smckusick	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
142835b3e579Smckusick	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
142935b3e579Smckusick	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
143035b3e579Smckusick	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
143135b3e579Smckusick	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
143235b3e579Smckusick	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
143335b3e579Smckusick	lw	s0, UADDR+U_PCB_REGS+(S0 * 4)
143435b3e579Smckusick	lw	s1, UADDR+U_PCB_REGS+(S1 * 4)
143535b3e579Smckusick	lw	s2, UADDR+U_PCB_REGS+(S2 * 4)
143635b3e579Smckusick	lw	s3, UADDR+U_PCB_REGS+(S3 * 4)
143735b3e579Smckusick	lw	s4, UADDR+U_PCB_REGS+(S4 * 4)
143835b3e579Smckusick	lw	s5, UADDR+U_PCB_REGS+(S5 * 4)
143935b3e579Smckusick	lw	s6, UADDR+U_PCB_REGS+(S6 * 4)
144035b3e579Smckusick	lw	s7, UADDR+U_PCB_REGS+(S7 * 4)
144135b3e579Smckusick	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
144235b3e579Smckusick	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
144335b3e579Smckusick	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
144435b3e579Smckusick	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
144535b3e579Smckusick	lw	s8, UADDR+U_PCB_REGS+(S8 * 4)
144635b3e579Smckusick	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
144735b3e579Smckusick	j	k0
144835b3e579Smckusick	rfe
144935b3e579Smckusick	.set	at
145035b3e579SmckusickEND(MachUserGenException)
145135b3e579Smckusick
145235b3e579Smckusick/*----------------------------------------------------------------------------
145335b3e579Smckusick *
145435b3e579Smckusick * MachKernIntr --
145535b3e579Smckusick *
145635b3e579Smckusick *	Handle an interrupt from kernel mode.
145792e9186eSralph *	Interrupts use the standard kernel stack.
14580082cbe2Sbostic *	switch_exit sets up a kernel stack after exit so interrupts won't fail.
145935b3e579Smckusick *
146035b3e579Smckusick * Results:
146135b3e579Smckusick *	None.
146235b3e579Smckusick *
146335b3e579Smckusick * Side effects:
146435b3e579Smckusick *	None.
146535b3e579Smckusick *
146635b3e579Smckusick *----------------------------------------------------------------------------
146735b3e579Smckusick */
146835b3e579Smckusick#define KINTR_REG_OFFSET	(STAND_FRAME_SIZE)
146935b3e579Smckusick#define KINTR_SR_OFFSET		(STAND_FRAME_SIZE + KERN_REG_SIZE)
147092e9186eSralph#define KINTR_MULT_LO_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
147192e9186eSralph#define KINTR_MULT_HI_OFFSET	(STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
147292e9186eSralph#define	KINTR_FRAME_SIZE	(STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
147335b3e579Smckusick
147492e9186eSralphNNON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra)
147535b3e579Smckusick	.set	noat
147635b3e579Smckusick	subu	sp, sp, KINTR_FRAME_SIZE	# allocate stack frame
147792e9186eSralph	.mask	0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE)
147835b3e579Smckusick/*
147935b3e579Smckusick * Save the relevant kernel registers onto the stack.
148035b3e579Smckusick * We don't need to save s0 - s8, sp and gp because
148135b3e579Smckusick * the compiler does it for us.
148235b3e579Smckusick */
148335b3e579Smckusick	sw	AT, KINTR_REG_OFFSET + 0(sp)
148435b3e579Smckusick	sw	v0, KINTR_REG_OFFSET + 4(sp)
148535b3e579Smckusick	sw	v1, KINTR_REG_OFFSET + 8(sp)
148635b3e579Smckusick	sw	a0, KINTR_REG_OFFSET + 12(sp)
148735b3e579Smckusick	mflo	v0
148835b3e579Smckusick	mfhi	v1
148935b3e579Smckusick	sw	a1, KINTR_REG_OFFSET + 16(sp)
149035b3e579Smckusick	sw	a2, KINTR_REG_OFFSET + 20(sp)
149135b3e579Smckusick	sw	a3, KINTR_REG_OFFSET + 24(sp)
149235b3e579Smckusick	sw	t0, KINTR_REG_OFFSET + 28(sp)
149335b3e579Smckusick	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
149435b3e579Smckusick	sw	t1, KINTR_REG_OFFSET + 32(sp)
149535b3e579Smckusick	sw	t2, KINTR_REG_OFFSET + 36(sp)
149635b3e579Smckusick	sw	t3, KINTR_REG_OFFSET + 40(sp)
149735b3e579Smckusick	sw	t4, KINTR_REG_OFFSET + 44(sp)
149835b3e579Smckusick	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
149935b3e579Smckusick	sw	t5, KINTR_REG_OFFSET + 48(sp)
150035b3e579Smckusick	sw	t6, KINTR_REG_OFFSET + 52(sp)
150135b3e579Smckusick	sw	t7, KINTR_REG_OFFSET + 56(sp)
150235b3e579Smckusick	sw	t8, KINTR_REG_OFFSET + 60(sp)
150335b3e579Smckusick	mfc0	a2, MACH_COP_0_EXC_PC		# Third arg is the pc.
150435b3e579Smckusick	sw	t9, KINTR_REG_OFFSET + 64(sp)
150535b3e579Smckusick	sw	ra, KINTR_REG_OFFSET + 68(sp)
150635b3e579Smckusick	sw	v0, KINTR_MULT_LO_OFFSET(sp)
150735b3e579Smckusick	sw	v1, KINTR_MULT_HI_OFFSET(sp)
150835b3e579Smckusick	sw	a0, KINTR_SR_OFFSET(sp)
150935b3e579Smckusick/*
151035b3e579Smckusick * Call the interrupt handler.
151135b3e579Smckusick */
151235b3e579Smckusick	jal	interrupt
151335b3e579Smckusick	sw	a2, STAND_RA_OFFSET(sp)		# for debugging
151435b3e579Smckusick/*
151535b3e579Smckusick * Restore registers and return from the interrupt.
151635b3e579Smckusick */
151735b3e579Smckusick	lw	a0, KINTR_SR_OFFSET(sp)
151835b3e579Smckusick	lw	t0, KINTR_MULT_LO_OFFSET(sp)
151935b3e579Smckusick	lw	t1, KINTR_MULT_HI_OFFSET(sp)
152035b3e579Smckusick	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
152135b3e579Smckusick	mtlo	t0
152235b3e579Smckusick	mthi	t1
152335b3e579Smckusick	lw	k0, STAND_RA_OFFSET(sp)
152435b3e579Smckusick	lw	AT, KINTR_REG_OFFSET + 0(sp)
152535b3e579Smckusick	lw	v0, KINTR_REG_OFFSET + 4(sp)
152635b3e579Smckusick	lw	v1, KINTR_REG_OFFSET + 8(sp)
152735b3e579Smckusick	lw	a0, KINTR_REG_OFFSET + 12(sp)
152835b3e579Smckusick	lw	a1, KINTR_REG_OFFSET + 16(sp)
152935b3e579Smckusick	lw	a2, KINTR_REG_OFFSET + 20(sp)
153035b3e579Smckusick	lw	a3, KINTR_REG_OFFSET + 24(sp)
153135b3e579Smckusick	lw	t0, KINTR_REG_OFFSET + 28(sp)
153235b3e579Smckusick	lw	t1, KINTR_REG_OFFSET + 32(sp)
153335b3e579Smckusick	lw	t2, KINTR_REG_OFFSET + 36(sp)
153435b3e579Smckusick	lw	t3, KINTR_REG_OFFSET + 40(sp)
153535b3e579Smckusick	lw	t4, KINTR_REG_OFFSET + 44(sp)
153635b3e579Smckusick	lw	t5, KINTR_REG_OFFSET + 48(sp)
153735b3e579Smckusick	lw	t6, KINTR_REG_OFFSET + 52(sp)
153835b3e579Smckusick	lw	t7, KINTR_REG_OFFSET + 56(sp)
153935b3e579Smckusick	lw	t8, KINTR_REG_OFFSET + 60(sp)
154035b3e579Smckusick	lw	t9, KINTR_REG_OFFSET + 64(sp)
154135b3e579Smckusick	lw	ra, KINTR_REG_OFFSET + 68(sp)
154292e9186eSralph	addu	sp, sp, KINTR_FRAME_SIZE
154335b3e579Smckusick	j	k0				# Now return from the
154435b3e579Smckusick	rfe					#  interrupt.
154535b3e579Smckusick	.set	at
154635b3e579SmckusickEND(MachKernIntr)
154735b3e579Smckusick
154835b3e579Smckusick/*----------------------------------------------------------------------------
154935b3e579Smckusick *
155035b3e579Smckusick * MachUserIntr --
155135b3e579Smckusick *
155235b3e579Smckusick *	Handle an interrupt from user mode.
155335b3e579Smckusick *	Note: we save minimal state in the u.u_pcb struct and use the standard
155435b3e579Smckusick *	kernel stack since there has to be a u page if we came from user mode.
155535b3e579Smckusick *	If there is a pending software interrupt, then save the remaining state
15560082cbe2Sbostic *	and call softintr(). This is all because if we call switch() inside
155735b3e579Smckusick *	interrupt(), not all the user registers have been saved in u.u_pcb.
155835b3e579Smckusick *
155935b3e579Smckusick * Results:
156035b3e579Smckusick * 	None.
156135b3e579Smckusick *
156235b3e579Smckusick * Side effects:
156335b3e579Smckusick *	None.
156435b3e579Smckusick *
156535b3e579Smckusick *----------------------------------------------------------------------------
156635b3e579Smckusick */
156792e9186eSralphNNON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra)
156835b3e579Smckusick	.set	noat
156935b3e579Smckusick	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
157035b3e579Smckusick/*
157135b3e579Smckusick * Save the relevant user registers into the u.u_pcb struct.
157235b3e579Smckusick * We don't need to save s0 - s8 because
157335b3e579Smckusick * the compiler does it for us.
157435b3e579Smckusick */
157535b3e579Smckusick	sw	AT, UADDR+U_PCB_REGS+(AST * 4)
157635b3e579Smckusick	sw	v0, UADDR+U_PCB_REGS+(V0 * 4)
157735b3e579Smckusick	sw	v1, UADDR+U_PCB_REGS+(V1 * 4)
157835b3e579Smckusick	sw	a0, UADDR+U_PCB_REGS+(A0 * 4)
157935b3e579Smckusick	mflo	v0
158035b3e579Smckusick	mfhi	v1
158135b3e579Smckusick	sw	a1, UADDR+U_PCB_REGS+(A1 * 4)
158235b3e579Smckusick	sw	a2, UADDR+U_PCB_REGS+(A2 * 4)
158335b3e579Smckusick	sw	a3, UADDR+U_PCB_REGS+(A3 * 4)
158435b3e579Smckusick	sw	t0, UADDR+U_PCB_REGS+(T0 * 4)
158535b3e579Smckusick	mfc0	a0, MACH_COP_0_STATUS_REG	# First arg is the status reg.
158635b3e579Smckusick	sw	t1, UADDR+U_PCB_REGS+(T1 * 4)
158735b3e579Smckusick	sw	t2, UADDR+U_PCB_REGS+(T2 * 4)
158835b3e579Smckusick	sw	t3, UADDR+U_PCB_REGS+(T3 * 4)
158935b3e579Smckusick	sw	t4, UADDR+U_PCB_REGS+(T4 * 4)
159035b3e579Smckusick	mfc0	a1, MACH_COP_0_CAUSE_REG	# Second arg is the cause reg.
159135b3e579Smckusick	sw	t5, UADDR+U_PCB_REGS+(T5 * 4)
159235b3e579Smckusick	sw	t6, UADDR+U_PCB_REGS+(T6 * 4)
159335b3e579Smckusick	sw	t7, UADDR+U_PCB_REGS+(T7 * 4)
159435b3e579Smckusick	sw	t8, UADDR+U_PCB_REGS+(T8 * 4)
159535b3e579Smckusick	mfc0	a2, MACH_COP_0_EXC_PC		# Third arg is the pc.
159635b3e579Smckusick	sw	t9, UADDR+U_PCB_REGS+(T9 * 4)
159735b3e579Smckusick	sw	gp, UADDR+U_PCB_REGS+(GP * 4)
159835b3e579Smckusick	sw	sp, UADDR+U_PCB_REGS+(SP * 4)
159935b3e579Smckusick	sw	ra, UADDR+U_PCB_REGS+(RA * 4)
160035b3e579Smckusick	li	sp, KERNELSTACK - STAND_FRAME_SIZE	# switch to kernel SP
160135b3e579Smckusick	sw	v0, UADDR+U_PCB_REGS+(MULLO * 4)
160235b3e579Smckusick	sw	v1, UADDR+U_PCB_REGS+(MULHI * 4)
160335b3e579Smckusick	sw	a0, UADDR+U_PCB_REGS+(SR * 4)
160435b3e579Smckusick	sw	a2, UADDR+U_PCB_REGS+(PC * 4)
1605193a1c3eSralph #	la	gp, _gp				# switch to kernel GP
1606193a1c3eSralph	.set	at
160735b3e579Smckusick	and	t0, a0, ~MACH_SR_COP_1_BIT	# Turn off the FPU.
1608193a1c3eSralph	.set	noat
160935b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG
161035b3e579Smckusick/*
161135b3e579Smckusick * Call the interrupt handler.
161235b3e579Smckusick */
161335b3e579Smckusick	jal	interrupt
161435b3e579Smckusick	sw	a2, STAND_RA_OFFSET(sp)		# for debugging
161535b3e579Smckusick/*
161635b3e579Smckusick * Restore registers and return from the interrupt.
161735b3e579Smckusick */
161835b3e579Smckusick	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
161935b3e579Smckusick	lw	v0, astpending			# any pending interrupts?
162035b3e579Smckusick	mtc0	a0, MACH_COP_0_STATUS_REG	# Restore the SR, disable intrs
1621193a1c3eSralph	bne	v0, zero, 1f			# dont restore, call softintr
162235b3e579Smckusick	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
162335b3e579Smckusick	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
162435b3e579Smckusick	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
162535b3e579Smckusick	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
162635b3e579Smckusick	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
162735b3e579Smckusick	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
162835b3e579Smckusick	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
162935b3e579Smckusick	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
163035b3e579Smckusick	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
163135b3e579Smckusick	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
163235b3e579Smckusick	mtlo	t0
163335b3e579Smckusick	mthi	t1
163435b3e579Smckusick	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
163535b3e579Smckusick	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
163635b3e579Smckusick	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
163735b3e579Smckusick	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
163835b3e579Smckusick	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
163935b3e579Smckusick	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
164035b3e579Smckusick	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
164135b3e579Smckusick	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
164235b3e579Smckusick	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
164335b3e579Smckusick	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
164435b3e579Smckusick	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
164535b3e579Smckusick	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
164635b3e579Smckusick	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
164735b3e579Smckusick	j	k0				# Now return from the
164835b3e579Smckusick	rfe					#  interrupt.
164935b3e579Smckusick
165035b3e579Smckusick1:
165135b3e579Smckusick/*
165235b3e579Smckusick * We have pending software interrupts; save remaining user state in u.u_pcb.
165335b3e579Smckusick */
165435b3e579Smckusick	sw	s0, UADDR+U_PCB_REGS+(S0 * 4)
165535b3e579Smckusick	sw	s1, UADDR+U_PCB_REGS+(S1 * 4)
165635b3e579Smckusick	sw	s2, UADDR+U_PCB_REGS+(S2 * 4)
165735b3e579Smckusick	sw	s3, UADDR+U_PCB_REGS+(S3 * 4)
165835b3e579Smckusick	sw	s4, UADDR+U_PCB_REGS+(S4 * 4)
165935b3e579Smckusick	sw	s5, UADDR+U_PCB_REGS+(S5 * 4)
166035b3e579Smckusick	sw	s6, UADDR+U_PCB_REGS+(S6 * 4)
166135b3e579Smckusick	sw	s7, UADDR+U_PCB_REGS+(S7 * 4)
166235b3e579Smckusick	sw	s8, UADDR+U_PCB_REGS+(S8 * 4)
166335b3e579Smckusick	li	t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR
166435b3e579Smckusick/*
166535b3e579Smckusick * Call the software interrupt handler.
166635b3e579Smckusick */
166735b3e579Smckusick	jal	softintr
166835b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts (spl0)
166935b3e579Smckusick/*
167035b3e579Smckusick * Restore user registers and return. NOTE: interrupts are enabled.
167135b3e579Smckusick */
167235b3e579Smckusick	lw	a0, UADDR+U_PCB_REGS+(SR * 4)
167335b3e579Smckusick	lw	t0, UADDR+U_PCB_REGS+(MULLO * 4)
167435b3e579Smckusick	lw	t1, UADDR+U_PCB_REGS+(MULHI * 4)
167535b3e579Smckusick	mtc0	a0, MACH_COP_0_STATUS_REG	# this should disable interrupts
167635b3e579Smckusick	mtlo	t0
167735b3e579Smckusick	mthi	t1
167835b3e579Smckusick	lw	k0, UADDR+U_PCB_REGS+(PC * 4)
167935b3e579Smckusick	lw	AT, UADDR+U_PCB_REGS+(AST * 4)
168035b3e579Smckusick	lw	v0, UADDR+U_PCB_REGS+(V0 * 4)
168135b3e579Smckusick	lw	v1, UADDR+U_PCB_REGS+(V1 * 4)
168235b3e579Smckusick	lw	a0, UADDR+U_PCB_REGS+(A0 * 4)
168335b3e579Smckusick	lw	a1, UADDR+U_PCB_REGS+(A1 * 4)
168435b3e579Smckusick	lw	a2, UADDR+U_PCB_REGS+(A2 * 4)
168535b3e579Smckusick	lw	a3, UADDR+U_PCB_REGS+(A3 * 4)
168635b3e579Smckusick	lw	t0, UADDR+U_PCB_REGS+(T0 * 4)
168735b3e579Smckusick	lw	t1, UADDR+U_PCB_REGS+(T1 * 4)
168835b3e579Smckusick	lw	t2, UADDR+U_PCB_REGS+(T2 * 4)
168935b3e579Smckusick	lw	t3, UADDR+U_PCB_REGS+(T3 * 4)
169035b3e579Smckusick	lw	t4, UADDR+U_PCB_REGS+(T4 * 4)
169135b3e579Smckusick	lw	t5, UADDR+U_PCB_REGS+(T5 * 4)
169235b3e579Smckusick	lw	t6, UADDR+U_PCB_REGS+(T6 * 4)
169335b3e579Smckusick	lw	t7, UADDR+U_PCB_REGS+(T7 * 4)
169435b3e579Smckusick	lw	s0, UADDR+U_PCB_REGS+(S0 * 4)
169535b3e579Smckusick	lw	s1, UADDR+U_PCB_REGS+(S1 * 4)
169635b3e579Smckusick	lw	s2, UADDR+U_PCB_REGS+(S2 * 4)
169735b3e579Smckusick	lw	s3, UADDR+U_PCB_REGS+(S3 * 4)
169835b3e579Smckusick	lw	s4, UADDR+U_PCB_REGS+(S4 * 4)
169935b3e579Smckusick	lw	s5, UADDR+U_PCB_REGS+(S5 * 4)
170035b3e579Smckusick	lw	s6, UADDR+U_PCB_REGS+(S6 * 4)
170135b3e579Smckusick	lw	s7, UADDR+U_PCB_REGS+(S7 * 4)
170235b3e579Smckusick	lw	t8, UADDR+U_PCB_REGS+(T8 * 4)
170335b3e579Smckusick	lw	t9, UADDR+U_PCB_REGS+(T9 * 4)
170435b3e579Smckusick	lw	gp, UADDR+U_PCB_REGS+(GP * 4)
170535b3e579Smckusick	lw	sp, UADDR+U_PCB_REGS+(SP * 4)
170635b3e579Smckusick	lw	s8, UADDR+U_PCB_REGS+(S8 * 4)
170735b3e579Smckusick	lw	ra, UADDR+U_PCB_REGS+(RA * 4)
170835b3e579Smckusick	j	k0
170935b3e579Smckusick	rfe
171035b3e579Smckusick	.set	at
171135b3e579SmckusickEND(MachUserIntr)
171235b3e579Smckusick
17134cf6ea80Sralph#if 0
171435b3e579Smckusick/*----------------------------------------------------------------------------
171535b3e579Smckusick *
171635b3e579Smckusick * MachTLBModException --
171735b3e579Smckusick *
171835b3e579Smckusick *	Handle a TLB modified exception.
171935b3e579Smckusick *	The BaddVAddr, Context, and EntryHi registers contain the failed
172035b3e579Smckusick *	virtual address.
172135b3e579Smckusick *
172235b3e579Smckusick * Results:
172335b3e579Smckusick *	None.
172435b3e579Smckusick *
172535b3e579Smckusick * Side effects:
172635b3e579Smckusick *	None.
172735b3e579Smckusick *
172835b3e579Smckusick *----------------------------------------------------------------------------
172935b3e579Smckusick */
173092e9186eSralphNLEAF(MachTLBModException)
173135b3e579Smckusick	.set	noat
173235b3e579Smckusick	tlbp					# find the TLB entry
173335b3e579Smckusick	mfc0	k0, MACH_COP_0_TLB_LOW		# get the physical address
173435b3e579Smckusick	mfc0	k1, MACH_COP_0_TLB_INDEX	# check to be sure its valid
173535b3e579Smckusick	or	k0, k0, VMMACH_TLB_MOD_BIT	# update TLB
173635b3e579Smckusick	blt	k1, zero, 4f			# not found!!!
173735b3e579Smckusick	mtc0	k0, MACH_COP_0_TLB_LOW
173835b3e579Smckusick	li	k1, MACH_CACHED_MEMORY_ADDR
173935b3e579Smckusick	subu	k0, k0, k1
174035b3e579Smckusick	srl	k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT
174135b3e579Smckusick	la	k1, pmap_attributes
17424854f40cSralph	addu	k0, k0, k1
174335b3e579Smckusick	lbu	k1, 0(k0)			# fetch old value
174435b3e579Smckusick	nop
174535b3e579Smckusick	or	k1, k1, 1			# set modified bit
174635b3e579Smckusick	sb	k1, 0(k0)			# save new value
174735b3e579Smckusick	mfc0	k0, MACH_COP_0_EXC_PC		# get return address
174835b3e579Smckusick	nop
174935b3e579Smckusick	j	k0
175035b3e579Smckusick	rfe
175135b3e579Smckusick4:
175235b3e579Smckusick	break	0				# panic
175335b3e579Smckusick	.set	at
175435b3e579SmckusickEND(MachTLBModException)
17554cf6ea80Sralph#endif
175635b3e579Smckusick
175735b3e579Smckusick/*----------------------------------------------------------------------------
175835b3e579Smckusick *
175935b3e579Smckusick * MachTLBMissException --
176035b3e579Smckusick *
176135b3e579Smckusick *	Handle a TLB miss exception from kernel mode.
176235b3e579Smckusick *	The BaddVAddr, Context, and EntryHi registers contain the failed
176335b3e579Smckusick *	virtual address.
176435b3e579Smckusick *
176535b3e579Smckusick * Results:
176635b3e579Smckusick *	None.
176735b3e579Smckusick *
176835b3e579Smckusick * Side effects:
176935b3e579Smckusick *	None.
177035b3e579Smckusick *
177135b3e579Smckusick *----------------------------------------------------------------------------
177235b3e579Smckusick */
177392e9186eSralphNLEAF(MachTLBMissException)
177435b3e579Smckusick	.set	noat
177535b3e579Smckusick	mfc0	k0, MACH_COP_0_BAD_VADDR	# get the fault address
177692e9186eSralph	li	k1, VM_MIN_KERNEL_ADDRESS	# compute index
177735b3e579Smckusick	subu	k0, k0, k1
177892e9186eSralph	lw	k1, Sysmapsize			# index within range?
177935b3e579Smckusick	srl	k0, k0, PGSHIFT
178035b3e579Smckusick	sltu	k1, k0, k1
178192e9186eSralph	beq	k1, zero, 1f			# No. check for valid stack
178292e9186eSralph	nop
178392e9186eSralph	lw	k1, Sysmap
178435b3e579Smckusick	sll	k0, k0, 2			# compute offset from index
178592e9186eSralph	addu	k1, k1, k0
178692e9186eSralph	lw	k0, 0(k1)			# get PTE entry
178735b3e579Smckusick	mfc0	k1, MACH_COP_0_EXC_PC		# get return address
178835b3e579Smckusick	mtc0	k0, MACH_COP_0_TLB_LOW		# save PTE entry
178992e9186eSralph	and	k0, k0, PG_V			# check for valid entry
179092e9186eSralph	beq	k0, zero, MachKernGenException	# PTE invalid
179135b3e579Smckusick	nop
179235b3e579Smckusick	tlbwr					# update TLB
179335b3e579Smckusick	j	k1
179435b3e579Smckusick	rfe
179592e9186eSralph
179692e9186eSralph1:
179792e9186eSralph	subu	k0, sp, UADDR + 0x200		# check to see if we have a
179892e9186eSralph	sltiu	k0, UPAGES*NBPG - 0x200		#  valid kernel stack
179992e9186eSralph	bne	k0, zero, MachKernGenException	# Go panic
180092e9186eSralph	nop
180192e9186eSralph
180292e9186eSralph	la	a0, start - START_FRAME - 8	# set sp to a valid place
180392e9186eSralph	sw	sp, 24(a0)
180492e9186eSralph	move	sp, a0
180592e9186eSralph	la	a0, 1f
180692e9186eSralph	mfc0	a2, MACH_COP_0_STATUS_REG
180792e9186eSralph	mfc0	a3, MACH_COP_0_CAUSE_REG
180892e9186eSralph	mfc0	a1, MACH_COP_0_EXC_PC
180992e9186eSralph	sw	a2, 16(sp)
181092e9186eSralph	sw	a3, 20(sp)
181192e9186eSralph	sw	sp, 24(sp)
181292e9186eSralph	move	a2, ra
181392e9186eSralph	jal	printf
181492e9186eSralph	mfc0	a3, MACH_COP_0_BAD_VADDR
181592e9186eSralph	.data
181692e9186eSralph1:
181792e9186eSralph	.asciiz	"ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n"
181892e9186eSralph	.text
181992e9186eSralph
182092e9186eSralph	la	sp, start - START_FRAME		# set sp to a valid place
182192e9186eSralph	PANIC("kernel stack overflow")
182235b3e579Smckusick	.set	at
182335b3e579SmckusickEND(MachTLBMissException)
182435b3e579Smckusick
182535b3e579Smckusick/*
182635b3e579Smckusick * Set/clear software interrupt routines.
182735b3e579Smckusick */
182835b3e579Smckusick
182935b3e579SmckusickLEAF(setsoftclock)
1830*759b7897Sralph	mfc0	v1, MACH_COP_0_STATUS_REG	# save status register
1831*759b7897Sralph	mtc0	zero, MACH_COP_0_STATUS_REG	# disable interrupts (2 cycles)
1832*759b7897Sralph	nop
1833*759b7897Sralph	nop
183435b3e579Smckusick	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
183535b3e579Smckusick	nop
183635b3e579Smckusick	or	v0, v0, MACH_SOFT_INT_MASK_0	# set soft clock interrupt
183735b3e579Smckusick	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1838*759b7897Sralph	mtc0	v1, MACH_COP_0_STATUS_REG
183935b3e579Smckusick	j	ra
184035b3e579Smckusick	nop
184135b3e579SmckusickEND(setsoftclock)
184235b3e579Smckusick
184335b3e579SmckusickLEAF(clearsoftclock)
1844*759b7897Sralph	mfc0	v1, MACH_COP_0_STATUS_REG	# save status register
1845*759b7897Sralph	mtc0	zero, MACH_COP_0_STATUS_REG	# disable interrupts (2 cycles)
1846*759b7897Sralph	nop
1847*759b7897Sralph	nop
184835b3e579Smckusick	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
184935b3e579Smckusick	nop
185035b3e579Smckusick	and	v0, v0, ~MACH_SOFT_INT_MASK_0	# clear soft clock interrupt
185135b3e579Smckusick	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1852*759b7897Sralph	mtc0	v1, MACH_COP_0_STATUS_REG
185335b3e579Smckusick	j	ra
185435b3e579Smckusick	nop
185535b3e579SmckusickEND(clearsoftclock)
185635b3e579Smckusick
185735b3e579SmckusickLEAF(setsoftnet)
1858*759b7897Sralph	mfc0	v1, MACH_COP_0_STATUS_REG	# save status register
1859*759b7897Sralph	mtc0	zero, MACH_COP_0_STATUS_REG	# disable interrupts (2 cycles)
1860*759b7897Sralph	nop
1861*759b7897Sralph	nop
186235b3e579Smckusick	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
186335b3e579Smckusick	nop
186435b3e579Smckusick	or	v0, v0, MACH_SOFT_INT_MASK_1	# set soft net interrupt
186535b3e579Smckusick	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1866*759b7897Sralph	mtc0	v1, MACH_COP_0_STATUS_REG
186735b3e579Smckusick	j	ra
186835b3e579Smckusick	nop
186935b3e579SmckusickEND(setsoftnet)
187035b3e579Smckusick
187135b3e579SmckusickLEAF(clearsoftnet)
1872*759b7897Sralph	mfc0	v1, MACH_COP_0_STATUS_REG	# save status register
1873*759b7897Sralph	mtc0	zero, MACH_COP_0_STATUS_REG	# disable interrupts (2 cycles)
1874*759b7897Sralph	nop
1875*759b7897Sralph	nop
187635b3e579Smckusick	mfc0	v0, MACH_COP_0_CAUSE_REG	# read cause register
187735b3e579Smckusick	nop
187835b3e579Smckusick	and	v0, v0, ~MACH_SOFT_INT_MASK_1	# clear soft net interrupt
187935b3e579Smckusick	mtc0	v0, MACH_COP_0_CAUSE_REG	# save it
1880*759b7897Sralph	mtc0	v1, MACH_COP_0_STATUS_REG
188135b3e579Smckusick	j	ra
188235b3e579Smckusick	nop
188335b3e579SmckusickEND(clearsoftnet)
188435b3e579Smckusick
188535b3e579Smckusick/*
188635b3e579Smckusick * Set/change interrupt priority routines.
188735b3e579Smckusick */
188835b3e579Smckusick
188935b3e579SmckusickLEAF(MachEnableIntr)
189035b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
189135b3e579Smckusick	nop
189235b3e579Smckusick	or	v0, v0, MACH_SR_INT_ENA_CUR
189335b3e579Smckusick	mtc0	v0, MACH_COP_0_STATUS_REG	# enable all interrupts
189435b3e579Smckusick	j	ra
189535b3e579Smckusick	nop
189635b3e579SmckusickEND(MachEnableIntr)
189735b3e579Smckusick
189835b3e579SmckusickLEAF(spl0)
189935b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
190035b3e579Smckusick	nop
190135b3e579Smckusick	or	t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
190235b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# enable all interrupts
190335b3e579Smckusick	j	ra
190435b3e579Smckusick	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
190535b3e579SmckusickEND(spl0)
190635b3e579Smckusick
190735b3e579SmckusickLEAF(splsoftclock)
190835b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
190933b40316Smckusick	li	t0, ~MACH_SOFT_INT_MASK_0	# disable soft clock
191035b3e579Smckusick	and	t0, t0, v0
191135b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
191235b3e579Smckusick	j	ra
191335b3e579Smckusick	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
191435b3e579SmckusickEND(splsoftclock)
191535b3e579Smckusick
19164cf6ea80SralphLEAF(Mach_spl0)
191733b40316Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
19184cf6ea80Sralph	li	t0, ~(MACH_INT_MASK_0|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
191933b40316Smckusick	and	t0, t0, v0
192033b40316Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
192133b40316Smckusick	j	ra
192233b40316Smckusick	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
19234cf6ea80SralphEND(Mach_spl0)
192433b40316Smckusick
19254cf6ea80SralphLEAF(Mach_spl1)
192635b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
19274cf6ea80Sralph	li	t0, ~(MACH_INT_MASK_1|MACH_SOFT_INT_MASK_0|MACH_SOFT_INT_MASK_1)
192835b3e579Smckusick	and	t0, t0, v0
192935b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
193035b3e579Smckusick	j	ra
193135b3e579Smckusick	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
19324cf6ea80SralphEND(Mach_spl1)
193335b3e579Smckusick
19344cf6ea80SralphLEAF(Mach_spl2)
193535b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
193633b40316Smckusick	li	t0, ~(MACH_INT_MASK_2|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
193735b3e579Smckusick	and	t0, t0, v0
193835b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
193935b3e579Smckusick	j	ra
194035b3e579Smckusick	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
19414cf6ea80SralphEND(Mach_spl2)
194235b3e579Smckusick
19434cf6ea80SralphLEAF(Mach_spl3)
194435b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
194533b40316Smckusick	li	t0, ~(MACH_INT_MASK_3|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
194635b3e579Smckusick	and	t0, t0, v0
194735b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
194835b3e579Smckusick	j	ra
194935b3e579Smckusick	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
19504cf6ea80SralphEND(Mach_spl3)
195135b3e579Smckusick
195292e9186eSralph/*
195392e9186eSralph * We define an alternate entry point after mcount is called so it
195492e9186eSralph * can be used in mcount without causeing a recursive loop.
195592e9186eSralph */
195635b3e579SmckusickLEAF(splhigh)
195792e9186eSralphALEAF(_splhigh)
195835b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG	# read status register
195935b3e579Smckusick	li	t0, ~MACH_SR_INT_ENA_CUR	# disable all interrupts
196035b3e579Smckusick	and	t0, t0, v0
196135b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG	# save it
196235b3e579Smckusick	j	ra
196335b3e579Smckusick	and	v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
196435b3e579SmckusickEND(splhigh)
196535b3e579Smckusick
196635b3e579Smckusick/*
196735b3e579Smckusick * Restore saved interrupt mask.
196835b3e579Smckusick */
196935b3e579SmckusickLEAF(splx)
197092e9186eSralphALEAF(_splx)
197135b3e579Smckusick	mfc0	v0, MACH_COP_0_STATUS_REG
197235b3e579Smckusick	li	t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
197335b3e579Smckusick	and	t0, t0, v0
197435b3e579Smckusick	or	t0, t0, a0
197535b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG
197635b3e579Smckusick	j	ra
197735b3e579Smckusick	nop
197835b3e579SmckusickEND(splx)
197935b3e579Smckusick
198035b3e579Smckusick/*----------------------------------------------------------------------------
198135b3e579Smckusick *
198235b3e579Smckusick * MachEmptyWriteBuffer --
198335b3e579Smckusick *
198435b3e579Smckusick *	Return when the write buffer is empty.
198535b3e579Smckusick *
198635b3e579Smckusick *	MachEmptyWriteBuffer()
198735b3e579Smckusick *
198835b3e579Smckusick * Results:
198935b3e579Smckusick *	None.
199035b3e579Smckusick *
199135b3e579Smckusick * Side effects:
199235b3e579Smckusick *	None.
199335b3e579Smckusick *
199435b3e579Smckusick *----------------------------------------------------------------------------
199535b3e579Smckusick */
199635b3e579SmckusickLEAF(MachEmptyWriteBuffer)
199735b3e579Smckusick	nop
199835b3e579Smckusick	nop
199935b3e579Smckusick	nop
200035b3e579Smckusick	nop
200135b3e579Smckusick1:	bc0f	1b
200235b3e579Smckusick	nop
200335b3e579Smckusick	j	ra
200435b3e579Smckusick	nop
200535b3e579SmckusickEND(MachEmptyWriteBuffer)
200635b3e579Smckusick
200735b3e579Smckusick/*--------------------------------------------------------------------------
200835b3e579Smckusick *
200935b3e579Smckusick * MachTLBWriteIndexed --
201035b3e579Smckusick *
201135b3e579Smckusick *	Write the given entry into the TLB at the given index.
201235b3e579Smckusick *
201335b3e579Smckusick *	MachTLBWriteIndexed(index, highEntry, lowEntry)
201435b3e579Smckusick *		int index;
201535b3e579Smckusick *		int highEntry;
201635b3e579Smckusick *		int lowEntry;
201735b3e579Smckusick *
201835b3e579Smckusick * Results:
201935b3e579Smckusick *	None.
202035b3e579Smckusick *
202135b3e579Smckusick * Side effects:
202235b3e579Smckusick *	TLB entry set.
202335b3e579Smckusick *
202435b3e579Smckusick *--------------------------------------------------------------------------
202535b3e579Smckusick */
202635b3e579SmckusickLEAF(MachTLBWriteIndexed)
202792e9186eSralph	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
202835b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
20294cf6ea80Sralph	mfc0	t0, MACH_COP_0_TLB_HI		# Save the current PID.
203035b3e579Smckusick
203135b3e579Smckusick	sll	a0, a0, VMMACH_TLB_INDEX_SHIFT
203235b3e579Smckusick	mtc0	a0, MACH_COP_0_TLB_INDEX	# Set the index.
203335b3e579Smckusick	mtc0	a1, MACH_COP_0_TLB_HI		# Set up entry high.
203435b3e579Smckusick	mtc0	a2, MACH_COP_0_TLB_LOW		# Set up entry low.
203535b3e579Smckusick	nop
203635b3e579Smckusick	tlbwi					# Write the TLB
203735b3e579Smckusick
203835b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_HI		# Restore the PID.
203935b3e579Smckusick	j	ra
204092e9186eSralph	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
204135b3e579SmckusickEND(MachTLBWriteIndexed)
204235b3e579Smckusick
204392e9186eSralph#if 0
204435b3e579Smckusick/*--------------------------------------------------------------------------
204535b3e579Smckusick *
204635b3e579Smckusick * MachTLBWriteRandom --
204735b3e579Smckusick *
204835b3e579Smckusick *	Write the given entry into the TLB at a random location.
204935b3e579Smckusick *
205035b3e579Smckusick *	MachTLBWriteRandom(highEntry, lowEntry)
205135b3e579Smckusick *		unsigned highEntry;
205235b3e579Smckusick *		unsigned lowEntry;
205335b3e579Smckusick *
205435b3e579Smckusick * Results:
205535b3e579Smckusick *	None.
205635b3e579Smckusick *
205735b3e579Smckusick * Side effects:
205835b3e579Smckusick *	TLB entry set.
205935b3e579Smckusick *
206035b3e579Smckusick *--------------------------------------------------------------------------
206135b3e579Smckusick */
206235b3e579SmckusickLEAF(MachTLBWriteRandom)
206335b3e579Smckusick	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
206435b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
20654cf6ea80Sralph	mfc0	v0, MACH_COP_0_TLB_HI		# Save the current PID.
206692e9186eSralph	nop
206735b3e579Smckusick
206835b3e579Smckusick	mtc0	a0, MACH_COP_0_TLB_HI		# Set up entry high.
206935b3e579Smckusick	mtc0	a1, MACH_COP_0_TLB_LOW		# Set up entry low.
207035b3e579Smckusick	nop
207135b3e579Smckusick	tlbwr					# Write the TLB
207235b3e579Smckusick
207335b3e579Smckusick	mtc0	v0, MACH_COP_0_TLB_HI		# Restore the PID.
207435b3e579Smckusick	j	ra
207535b3e579Smckusick	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
207635b3e579SmckusickEND(MachTLBWriteRandom)
207792e9186eSralph#endif
207835b3e579Smckusick
207935b3e579Smckusick/*--------------------------------------------------------------------------
208035b3e579Smckusick *
208135b3e579Smckusick * MachSetPID --
208235b3e579Smckusick *
208335b3e579Smckusick *	Write the given pid into the TLB pid reg.
208435b3e579Smckusick *
208535b3e579Smckusick *	MachSetPID(pid)
208635b3e579Smckusick *		int pid;
208735b3e579Smckusick *
208835b3e579Smckusick * Results:
208935b3e579Smckusick *	None.
209035b3e579Smckusick *
209135b3e579Smckusick * Side effects:
209235b3e579Smckusick *	PID set in the entry hi register.
209335b3e579Smckusick *
209435b3e579Smckusick *--------------------------------------------------------------------------
209535b3e579Smckusick */
209635b3e579SmckusickLEAF(MachSetPID)
209735b3e579Smckusick	sll	a0, a0, VMMACH_TLB_PID_SHIFT	# put PID in right spot
209835b3e579Smckusick	mtc0	a0, MACH_COP_0_TLB_HI		# Write the hi reg value
209935b3e579Smckusick	j	ra
210035b3e579Smckusick	nop
210135b3e579SmckusickEND(MachSetPID)
210235b3e579Smckusick
210335b3e579Smckusick/*--------------------------------------------------------------------------
210435b3e579Smckusick *
210535b3e579Smckusick * MachTLBFlush --
210635b3e579Smckusick *
210735b3e579Smckusick *	Flush the "random" entries from the TLB.
210835b3e579Smckusick *
210935b3e579Smckusick *	MachTLBFlush()
211035b3e579Smckusick *
211135b3e579Smckusick * Results:
211235b3e579Smckusick *	None.
211335b3e579Smckusick *
211435b3e579Smckusick * Side effects:
211535b3e579Smckusick *	The TLB is flushed.
211635b3e579Smckusick *
211735b3e579Smckusick *--------------------------------------------------------------------------
211835b3e579Smckusick */
211935b3e579SmckusickLEAF(MachTLBFlush)
212035b3e579Smckusick	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
212135b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
21224cf6ea80Sralph	mfc0	t0, MACH_COP_0_TLB_HI		# Save the PID
212392e9186eSralph	li	t1, MACH_CACHED_MEMORY_ADDR	# invalid address
212435b3e579Smckusick	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
212535b3e579Smckusick	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
212635b3e579Smckusick/*
21274cf6ea80Sralph * Align the starting value (t1) and the upper bound (t2).
212835b3e579Smckusick */
212935b3e579Smckusick	li	t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
21304cf6ea80Sralph	li	t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
213135b3e579Smckusick1:
213235b3e579Smckusick	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register.
21334cf6ea80Sralph	addu	t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT	# Increment index.
213492e9186eSralph	bne	t1, t2, 1b
213535b3e579Smckusick	tlbwi					# Write the TLB entry.
213635b3e579Smckusick
213735b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_HI		# Restore the PID
213835b3e579Smckusick	j	ra
213935b3e579Smckusick	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
214035b3e579SmckusickEND(MachTLBFlush)
214135b3e579Smckusick
214292e9186eSralph#if 0
214335b3e579Smckusick/*--------------------------------------------------------------------------
214435b3e579Smckusick *
214535b3e579Smckusick * MachTLBFlushPID --
214635b3e579Smckusick *
214735b3e579Smckusick *	Flush all entries with the given PID from the TLB.
214835b3e579Smckusick *
214935b3e579Smckusick *	MachTLBFlushPID(pid)
215035b3e579Smckusick *		int pid;
215135b3e579Smckusick *
215235b3e579Smckusick * Results:
215335b3e579Smckusick *	None.
215435b3e579Smckusick *
215535b3e579Smckusick * Side effects:
215635b3e579Smckusick *	All entries corresponding to this PID are flushed.
215735b3e579Smckusick *
215835b3e579Smckusick *--------------------------------------------------------------------------
215935b3e579Smckusick */
216035b3e579SmckusickLEAF(MachTLBFlushPID)
216135b3e579Smckusick	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
216235b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
21634cf6ea80Sralph	mfc0	t0, MACH_COP_0_TLB_HI		# Save the current PID
216435b3e579Smckusick	sll	a0, a0, VMMACH_TLB_PID_SHIFT	# Align the pid to flush.
216535b3e579Smckusick/*
21664cf6ea80Sralph * Align the starting value (t1) and the upper bound (t2).
216735b3e579Smckusick */
216835b3e579Smckusick	li	t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
21694cf6ea80Sralph	li	t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
217035b3e579Smckusick	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register
217135b3e579Smckusick1:
21724cf6ea80Sralph	addu	t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT	# Increment index.
217335b3e579Smckusick	tlbr					# Read from the TLB
217435b3e579Smckusick	mfc0	t4, MACH_COP_0_TLB_HI		# Fetch the hi register.
217535b3e579Smckusick	nop
2176193a1c3eSralph	and	t4, t4, VMMACH_TLB_PID		# compare PIDs
217735b3e579Smckusick	bne	t4, a0, 2f
217892e9186eSralph	li	v0, MACH_CACHED_MEMORY_ADDR	# invalid address
217935b3e579Smckusick	mtc0	v0, MACH_COP_0_TLB_HI		# Mark entry high as invalid
218035b3e579Smckusick	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
218135b3e579Smckusick	nop
218235b3e579Smckusick	tlbwi					# Write the entry.
218335b3e579Smckusick2:
21844cf6ea80Sralph	bne	t1, t2, 1b
218535b3e579Smckusick	mtc0	t1, MACH_COP_0_TLB_INDEX	# Set the index register
218635b3e579Smckusick
218735b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
218835b3e579Smckusick	j	ra
218935b3e579Smckusick	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
219035b3e579SmckusickEND(MachTLBFlushPID)
219192e9186eSralph#endif
219235b3e579Smckusick
219335b3e579Smckusick/*--------------------------------------------------------------------------
219435b3e579Smckusick *
219535b3e579Smckusick * MachTLBFlushAddr --
219635b3e579Smckusick *
21974cf6ea80Sralph *	Flush any TLB entries for the given address and TLB PID.
219835b3e579Smckusick *
21994cf6ea80Sralph *	MachTLBFlushAddr(highreg)
22004cf6ea80Sralph *		unsigned highreg;
220135b3e579Smckusick *
220235b3e579Smckusick * Results:
220335b3e579Smckusick *	None.
220435b3e579Smckusick *
220535b3e579Smckusick * Side effects:
220635b3e579Smckusick *	The process's page is flushed from the TLB.
220735b3e579Smckusick *
220835b3e579Smckusick *--------------------------------------------------------------------------
220935b3e579Smckusick */
221035b3e579SmckusickLEAF(MachTLBFlushAddr)
221135b3e579Smckusick	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
221235b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
22134cf6ea80Sralph	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
221492e9186eSralph	nop
22154cf6ea80Sralph
221635b3e579Smckusick	mtc0	a0, MACH_COP_0_TLB_HI		# look for addr & PID
221735b3e579Smckusick	nop
221835b3e579Smckusick	tlbp					# Probe for the entry.
221935b3e579Smckusick	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
222092e9186eSralph	li	t1, MACH_CACHED_MEMORY_ADDR	# Load invalid entry.
222135b3e579Smckusick	bltz	v0, 1f				# index < 0 => !found
22224cf6ea80Sralph	mtc0	t1, MACH_COP_0_TLB_HI		# Mark entry high as invalid
22234cf6ea80Sralph	mtc0	zero, MACH_COP_0_TLB_LOW	# Zero out low entry.
222435b3e579Smckusick	nop
222535b3e579Smckusick	tlbwi
222635b3e579Smckusick1:
222735b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
222835b3e579Smckusick	j	ra
222935b3e579Smckusick	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
223035b3e579SmckusickEND(MachTLBFlushAddr)
223135b3e579Smckusick
223235b3e579Smckusick/*--------------------------------------------------------------------------
223335b3e579Smckusick *
223435b3e579Smckusick * MachTLBUpdate --
223535b3e579Smckusick *
223692e9186eSralph *	Update the TLB if highreg is found; otherwise, enter the data.
223735b3e579Smckusick *
223835b3e579Smckusick *	MachTLBUpdate(highreg, lowreg)
223935b3e579Smckusick *		unsigned highreg, lowreg;
224035b3e579Smckusick *
224135b3e579Smckusick * Results:
224235b3e579Smckusick *	None.
224335b3e579Smckusick *
224435b3e579Smckusick * Side effects:
224535b3e579Smckusick *	None.
224635b3e579Smckusick *
224735b3e579Smckusick *--------------------------------------------------------------------------
224835b3e579Smckusick */
224935b3e579SmckusickLEAF(MachTLBUpdate)
225035b3e579Smckusick	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
225135b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
22524cf6ea80Sralph	mfc0	t0, MACH_COP_0_TLB_HI		# Save current PID
225392e9186eSralph	nop					# 2 cycles before intr disabled
225435b3e579Smckusick	mtc0	a0, MACH_COP_0_TLB_HI		# init high reg.
225535b3e579Smckusick	nop
225635b3e579Smckusick	tlbp					# Probe for the entry.
225735b3e579Smckusick	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
225892e9186eSralph	mtc0	a1, MACH_COP_0_TLB_LOW		# init low reg.
225935b3e579Smckusick	bltz	v0, 1f				# index < 0 => !found
226092e9186eSralph	sra	v0, v0, VMMACH_TLB_INDEX_SHIFT	# convert index to regular num
226192e9186eSralph	b	2f
226292e9186eSralph	tlbwi					# update slot found
226335b3e579Smckusick1:
226492e9186eSralph	mtc0	a0, MACH_COP_0_TLB_HI		# init high reg.
226592e9186eSralph	nop
226692e9186eSralph	tlbwr					# enter into a random slot
226792e9186eSralph2:
226835b3e579Smckusick	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
226935b3e579Smckusick	j	ra
227035b3e579Smckusick	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
227135b3e579SmckusickEND(MachTLBUpdate)
227235b3e579Smckusick
227392e9186eSralph#if defined(DEBUG)
227435b3e579Smckusick/*--------------------------------------------------------------------------
227535b3e579Smckusick *
22764cf6ea80Sralph * MachTLBFind --
227735b3e579Smckusick *
22784cf6ea80Sralph *	Search the TLB for the given entry.
227935b3e579Smckusick *
22804cf6ea80Sralph *	MachTLBFind(hi)
22814cf6ea80Sralph *		unsigned hi;
228235b3e579Smckusick *
228335b3e579Smckusick * Results:
22844cf6ea80Sralph *	Returns a value >= 0 if the entry was found (the index).
22854cf6ea80Sralph *	Returns a value < 0 if the entry was not found.
228635b3e579Smckusick *
228735b3e579Smckusick * Side effects:
22884cf6ea80Sralph *	tlbhi and tlblo will contain the TLB entry found.
228935b3e579Smckusick *
229035b3e579Smckusick *--------------------------------------------------------------------------
229135b3e579Smckusick */
229235b3e579Smckusick	.comm	tlbhi, 4
229335b3e579Smckusick	.comm	tlblo, 4
229435b3e579SmckusickLEAF(MachTLBFind)
229535b3e579Smckusick	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
229635b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
22974cf6ea80Sralph	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
22984cf6ea80Sralph	nop
229935b3e579Smckusick	mtc0	a0, MACH_COP_0_TLB_HI		# Set up entry high.
230035b3e579Smckusick	nop
230135b3e579Smckusick	tlbp					# Probe for the entry.
230235b3e579Smckusick	mfc0	v0, MACH_COP_0_TLB_INDEX	# See what we got
23034cf6ea80Sralph	nop
23044cf6ea80Sralph	bltz	v0, 1f				# not found
23054cf6ea80Sralph	nop
23064cf6ea80Sralph	tlbr					# read TLB
230735b3e579Smckusick	mfc0	t1, MACH_COP_0_TLB_HI		# See what we got
230835b3e579Smckusick	mfc0	t2, MACH_COP_0_TLB_LOW		# See what we got
230935b3e579Smckusick	sw	t1, tlbhi
231035b3e579Smckusick	sw	t2, tlblo
231192e9186eSralph	srl	v0, v0, VMMACH_TLB_INDEX_SHIFT	# convert index to regular num
23124cf6ea80Sralph1:
23134cf6ea80Sralph	mtc0	t0, MACH_COP_0_TLB_HI		# Restore current PID
231435b3e579Smckusick	j	ra
231535b3e579Smckusick	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
231635b3e579SmckusickEND(MachTLBFind)
231735b3e579Smckusick
231835b3e579Smckusick/*--------------------------------------------------------------------------
231935b3e579Smckusick *
23204cf6ea80Sralph * MachTLBRead --
232135b3e579Smckusick *
23224cf6ea80Sralph *	Read the TLB entry.
23234cf6ea80Sralph *
23244cf6ea80Sralph *	MachTLBRead(entry)
23254cf6ea80Sralph *		unsigned entry;
23264cf6ea80Sralph *
23274cf6ea80Sralph * Results:
23284cf6ea80Sralph *	None.
23294cf6ea80Sralph *
23304cf6ea80Sralph * Side effects:
23314cf6ea80Sralph *	tlbhi and tlblo will contain the TLB entry found.
23324cf6ea80Sralph *
23334cf6ea80Sralph *--------------------------------------------------------------------------
23344cf6ea80Sralph */
23354cf6ea80SralphLEAF(MachTLBRead)
23364cf6ea80Sralph	mfc0	v1, MACH_COP_0_STATUS_REG	# Save the status register.
23374cf6ea80Sralph	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts
23384cf6ea80Sralph	mfc0	t0, MACH_COP_0_TLB_HI		# Get current PID
23394cf6ea80Sralph
23404cf6ea80Sralph	sll	a0, a0, VMMACH_TLB_INDEX_SHIFT
23414cf6ea80Sralph	mtc0	a0, MACH_COP_0_TLB_INDEX	# Set the index register
23424cf6ea80Sralph	nop
23434cf6ea80Sralph	tlbr					# Read from the TLB
23444cf6ea80Sralph	mfc0	t3, MACH_COP_0_TLB_HI		# fetch the hi entry
23454cf6ea80Sralph	mfc0	t4, MACH_COP_0_TLB_LOW		# fetch the low entry
23464cf6ea80Sralph	sw	t3, tlbhi
23474cf6ea80Sralph	sw	t4, tlblo
23484cf6ea80Sralph
23494cf6ea80Sralph	mtc0	t0, MACH_COP_0_TLB_HI		# restore PID
23504cf6ea80Sralph	j	ra
23514cf6ea80Sralph	mtc0	v1, MACH_COP_0_STATUS_REG	# Restore the status register
23524cf6ea80SralphEND(MachTLBRead)
23534cf6ea80Sralph
23544cf6ea80Sralph/*--------------------------------------------------------------------------
23554cf6ea80Sralph *
23564cf6ea80Sralph * MachTLBGetPID --
23574cf6ea80Sralph *
23584cf6ea80Sralph *	MachTLBGetPID()
235935b3e579Smckusick *
236035b3e579Smckusick * Results:
236135b3e579Smckusick *	Returns the current TLB pid reg.
236235b3e579Smckusick *
236335b3e579Smckusick * Side effects:
236435b3e579Smckusick *	None.
236535b3e579Smckusick *
236635b3e579Smckusick *--------------------------------------------------------------------------
236735b3e579Smckusick */
23684cf6ea80SralphLEAF(MachTLBGetPID)
236935b3e579Smckusick	mfc0	v0, MACH_COP_0_TLB_HI		# get PID
237035b3e579Smckusick	nop
237135b3e579Smckusick	and	v0, v0, VMMACH_TLB_PID		# mask off PID
237235b3e579Smckusick	j	ra
237335b3e579Smckusick	srl	v0, v0, VMMACH_TLB_PID_SHIFT	# put PID in right spot
23744cf6ea80SralphEND(MachTLBGetPID)
23754cf6ea80Sralph
23764cf6ea80Sralph/*
23774cf6ea80Sralph * Return the current value of the cause register.
23784cf6ea80Sralph */
23794cf6ea80SralphLEAF(MachGetCauseReg)
23804cf6ea80Sralph	mfc0	v0, MACH_COP_0_CAUSE_REG
23814cf6ea80Sralph	j	ra
23824cf6ea80Sralph	nop
23834cf6ea80SralphEND(MachGetCauseReg)
238435b3e579Smckusick#endif /* DEBUG */
238535b3e579Smckusick
238635b3e579Smckusick/*----------------------------------------------------------------------------
238735b3e579Smckusick *
238835b3e579Smckusick * MachSwitchFPState --
238935b3e579Smckusick *
239035b3e579Smckusick *	Save the current state into 'from' and restore it from 'to'.
239135b3e579Smckusick *
239235b3e579Smckusick *	MachSwitchFPState(from, to)
239335b3e579Smckusick *		struct proc *from;
239435b3e579Smckusick *		struct user *to;
239535b3e579Smckusick *
239635b3e579Smckusick * Results:
239735b3e579Smckusick *	None.
239835b3e579Smckusick *
239935b3e579Smckusick * Side effects:
240035b3e579Smckusick *	None.
240135b3e579Smckusick *
240235b3e579Smckusick *----------------------------------------------------------------------------
240335b3e579Smckusick */
240435b3e579SmckusickLEAF(MachSwitchFPState)
240535b3e579Smckusick	mfc0	t1, MACH_COP_0_STATUS_REG	# Save old SR
2406d85b31faSralph	li	t0, MACH_SR_COP_1_BIT		# enable the coprocessor
2407d85b31faSralph	mtc0	t0, MACH_COP_0_STATUS_REG
240835b3e579Smckusick
240935b3e579Smckusick	beq	a0, zero, 1f			# skip save if NULL pointer
241035b3e579Smckusick	nop
241135b3e579Smckusick/*
241235b3e579Smckusick * First read out the status register to make sure that all FP operations
241335b3e579Smckusick * have completed.
241435b3e579Smckusick */
241535b3e579Smckusick	lw	a0, P_ADDR(a0)			# get pointer to pcb for proc
24164cf6ea80Sralph	cfc1	t0, MACH_FPC_CSR		# stall til FP done
24174cf6ea80Sralph	cfc1	t0, MACH_FPC_CSR		# now get status
241835b3e579Smckusick	li	t3, ~MACH_SR_COP_1_BIT
241935b3e579Smckusick	lw	t2, U_PCB_REGS+(PS * 4)(a0)	# get CPU status register
242035b3e579Smckusick	sw	t0, U_PCB_FPREGS+(32 * 4)(a0)	# save FP status
242135b3e579Smckusick	and	t2, t2, t3			# clear COP_1 enable bit
242235b3e579Smckusick	sw	t2, U_PCB_REGS+(PS * 4)(a0)	# save new status register
242335b3e579Smckusick/*
242435b3e579Smckusick * Save the floating point registers.
242535b3e579Smckusick */
242635b3e579Smckusick	swc1	$f0, U_PCB_FPREGS+(0 * 4)(a0)
242735b3e579Smckusick	swc1	$f1, U_PCB_FPREGS+(1 * 4)(a0)
242835b3e579Smckusick	swc1	$f2, U_PCB_FPREGS+(2 * 4)(a0)
242935b3e579Smckusick	swc1	$f3, U_PCB_FPREGS+(3 * 4)(a0)
243035b3e579Smckusick	swc1	$f4, U_PCB_FPREGS+(4 * 4)(a0)
243135b3e579Smckusick	swc1	$f5, U_PCB_FPREGS+(5 * 4)(a0)
243235b3e579Smckusick	swc1	$f6, U_PCB_FPREGS+(6 * 4)(a0)
243335b3e579Smckusick	swc1	$f7, U_PCB_FPREGS+(7 * 4)(a0)
243435b3e579Smckusick	swc1	$f8, U_PCB_FPREGS+(8 * 4)(a0)
243535b3e579Smckusick	swc1	$f9, U_PCB_FPREGS+(9 * 4)(a0)
243635b3e579Smckusick	swc1	$f10, U_PCB_FPREGS+(10 * 4)(a0)
243735b3e579Smckusick	swc1	$f11, U_PCB_FPREGS+(11 * 4)(a0)
243835b3e579Smckusick	swc1	$f12, U_PCB_FPREGS+(12 * 4)(a0)
243935b3e579Smckusick	swc1	$f13, U_PCB_FPREGS+(13 * 4)(a0)
244035b3e579Smckusick	swc1	$f14, U_PCB_FPREGS+(14 * 4)(a0)
244135b3e579Smckusick	swc1	$f15, U_PCB_FPREGS+(15 * 4)(a0)
244235b3e579Smckusick	swc1	$f16, U_PCB_FPREGS+(16 * 4)(a0)
244335b3e579Smckusick	swc1	$f17, U_PCB_FPREGS+(17 * 4)(a0)
244435b3e579Smckusick	swc1	$f18, U_PCB_FPREGS+(18 * 4)(a0)
244535b3e579Smckusick	swc1	$f19, U_PCB_FPREGS+(19 * 4)(a0)
244635b3e579Smckusick	swc1	$f20, U_PCB_FPREGS+(20 * 4)(a0)
244735b3e579Smckusick	swc1	$f21, U_PCB_FPREGS+(21 * 4)(a0)
244835b3e579Smckusick	swc1	$f22, U_PCB_FPREGS+(22 * 4)(a0)
244935b3e579Smckusick	swc1	$f23, U_PCB_FPREGS+(23 * 4)(a0)
245035b3e579Smckusick	swc1	$f24, U_PCB_FPREGS+(24 * 4)(a0)
245135b3e579Smckusick	swc1	$f25, U_PCB_FPREGS+(25 * 4)(a0)
245235b3e579Smckusick	swc1	$f26, U_PCB_FPREGS+(26 * 4)(a0)
245335b3e579Smckusick	swc1	$f27, U_PCB_FPREGS+(27 * 4)(a0)
245435b3e579Smckusick	swc1	$f28, U_PCB_FPREGS+(28 * 4)(a0)
245535b3e579Smckusick	swc1	$f29, U_PCB_FPREGS+(29 * 4)(a0)
245635b3e579Smckusick	swc1	$f30, U_PCB_FPREGS+(30 * 4)(a0)
245735b3e579Smckusick	swc1	$f31, U_PCB_FPREGS+(31 * 4)(a0)
245835b3e579Smckusick
245935b3e579Smckusick1:
246035b3e579Smckusick/*
246135b3e579Smckusick *  Restore the floating point registers.
246235b3e579Smckusick */
246335b3e579Smckusick	lw	t0, U_PCB_FPREGS+(32 * 4)(a1)	# get status register
246435b3e579Smckusick	lwc1	$f0, U_PCB_FPREGS+(0 * 4)(a1)
246535b3e579Smckusick	lwc1	$f1, U_PCB_FPREGS+(1 * 4)(a1)
246635b3e579Smckusick	lwc1	$f2, U_PCB_FPREGS+(2 * 4)(a1)
246735b3e579Smckusick	lwc1	$f3, U_PCB_FPREGS+(3 * 4)(a1)
246835b3e579Smckusick	lwc1	$f4, U_PCB_FPREGS+(4 * 4)(a1)
246935b3e579Smckusick	lwc1	$f5, U_PCB_FPREGS+(5 * 4)(a1)
247035b3e579Smckusick	lwc1	$f6, U_PCB_FPREGS+(6 * 4)(a1)
247135b3e579Smckusick	lwc1	$f7, U_PCB_FPREGS+(7 * 4)(a1)
247235b3e579Smckusick	lwc1	$f8, U_PCB_FPREGS+(8 * 4)(a1)
247335b3e579Smckusick	lwc1	$f9, U_PCB_FPREGS+(9 * 4)(a1)
247435b3e579Smckusick	lwc1	$f10, U_PCB_FPREGS+(10 * 4)(a1)
247535b3e579Smckusick	lwc1	$f11, U_PCB_FPREGS+(11 * 4)(a1)
247635b3e579Smckusick	lwc1	$f12, U_PCB_FPREGS+(12 * 4)(a1)
247735b3e579Smckusick	lwc1	$f13, U_PCB_FPREGS+(13 * 4)(a1)
247835b3e579Smckusick	lwc1	$f14, U_PCB_FPREGS+(14 * 4)(a1)
247935b3e579Smckusick	lwc1	$f15, U_PCB_FPREGS+(15 * 4)(a1)
248035b3e579Smckusick	lwc1	$f16, U_PCB_FPREGS+(16 * 4)(a1)
248135b3e579Smckusick	lwc1	$f17, U_PCB_FPREGS+(17 * 4)(a1)
248235b3e579Smckusick	lwc1	$f18, U_PCB_FPREGS+(18 * 4)(a1)
248335b3e579Smckusick	lwc1	$f19, U_PCB_FPREGS+(19 * 4)(a1)
248435b3e579Smckusick	lwc1	$f20, U_PCB_FPREGS+(20 * 4)(a1)
248535b3e579Smckusick	lwc1	$f21, U_PCB_FPREGS+(21 * 4)(a1)
248635b3e579Smckusick	lwc1	$f22, U_PCB_FPREGS+(22 * 4)(a1)
248735b3e579Smckusick	lwc1	$f23, U_PCB_FPREGS+(23 * 4)(a1)
248835b3e579Smckusick	lwc1	$f24, U_PCB_FPREGS+(24 * 4)(a1)
248935b3e579Smckusick	lwc1	$f25, U_PCB_FPREGS+(25 * 4)(a1)
249035b3e579Smckusick	lwc1	$f26, U_PCB_FPREGS+(26 * 4)(a1)
249135b3e579Smckusick	lwc1	$f27, U_PCB_FPREGS+(27 * 4)(a1)
249235b3e579Smckusick	lwc1	$f28, U_PCB_FPREGS+(28 * 4)(a1)
249335b3e579Smckusick	lwc1	$f29, U_PCB_FPREGS+(29 * 4)(a1)
249435b3e579Smckusick	lwc1	$f30, U_PCB_FPREGS+(30 * 4)(a1)
249535b3e579Smckusick	lwc1	$f31, U_PCB_FPREGS+(31 * 4)(a1)
249635b3e579Smckusick
249735b3e579Smckusick	and	t0, t0, ~MACH_FPC_EXCEPTION_BITS
249835b3e579Smckusick	ctc1	t0, MACH_FPC_CSR
249935b3e579Smckusick	nop
250035b3e579Smckusick
250135b3e579Smckusick	mtc0	t1, MACH_COP_0_STATUS_REG	# Restore the status register.
250235b3e579Smckusick	j	ra
250335b3e579Smckusick	nop
250435b3e579SmckusickEND(MachSwitchFPState)
250535b3e579Smckusick
250635b3e579Smckusick/*----------------------------------------------------------------------------
250735b3e579Smckusick *
250835b3e579Smckusick * MachSaveCurFPState --
250935b3e579Smckusick *
251035b3e579Smckusick *	Save the current floating point coprocessor state.
251135b3e579Smckusick *
251235b3e579Smckusick *	MachSaveCurFPState(p)
251335b3e579Smckusick *		struct proc *p;
251435b3e579Smckusick *
251535b3e579Smckusick * Results:
251635b3e579Smckusick *	None.
251735b3e579Smckusick *
251835b3e579Smckusick * Side effects:
2519c57e7bd3Sralph *	machFPCurProcPtr is cleared.
252035b3e579Smckusick *
252135b3e579Smckusick *----------------------------------------------------------------------------
252235b3e579Smckusick */
252335b3e579SmckusickLEAF(MachSaveCurFPState)
252435b3e579Smckusick	lw	a0, P_ADDR(a0)			# get pointer to pcb for proc
252535b3e579Smckusick	mfc0	t1, MACH_COP_0_STATUS_REG	# Disable interrupts and
252635b3e579Smckusick	li	t0, MACH_SR_COP_1_BIT		#  enable the coprocessor
252735b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG
2528c57e7bd3Sralph	sw	zero, machFPCurProcPtr		# indicate state has been saved
252935b3e579Smckusick/*
253035b3e579Smckusick * First read out the status register to make sure that all FP operations
253135b3e579Smckusick * have completed.
253235b3e579Smckusick */
253335b3e579Smckusick	lw	t2, U_PCB_REGS+(PS * 4)(a0)	# get CPU status register
253435b3e579Smckusick	li	t3, ~MACH_SR_COP_1_BIT
253535b3e579Smckusick	and	t2, t2, t3			# clear COP_1 enable bit
25364cf6ea80Sralph	cfc1	t0, MACH_FPC_CSR		# stall til FP done
25374cf6ea80Sralph	cfc1	t0, MACH_FPC_CSR		# now get status
253835b3e579Smckusick	sw	t2, U_PCB_REGS+(PS * 4)(a0)	# save new status register
253935b3e579Smckusick	sw	t0, U_PCB_FPREGS+(32 * 4)(a0)	# save FP status
254035b3e579Smckusick/*
254135b3e579Smckusick * Save the floating point registers.
254235b3e579Smckusick */
254335b3e579Smckusick	swc1	$f0, U_PCB_FPREGS+(0 * 4)(a0)
254435b3e579Smckusick	swc1	$f1, U_PCB_FPREGS+(1 * 4)(a0)
254535b3e579Smckusick	swc1	$f2, U_PCB_FPREGS+(2 * 4)(a0)
254635b3e579Smckusick	swc1	$f3, U_PCB_FPREGS+(3 * 4)(a0)
254735b3e579Smckusick	swc1	$f4, U_PCB_FPREGS+(4 * 4)(a0)
254835b3e579Smckusick	swc1	$f5, U_PCB_FPREGS+(5 * 4)(a0)
254935b3e579Smckusick	swc1	$f6, U_PCB_FPREGS+(6 * 4)(a0)
255035b3e579Smckusick	swc1	$f7, U_PCB_FPREGS+(7 * 4)(a0)
255135b3e579Smckusick	swc1	$f8, U_PCB_FPREGS+(8 * 4)(a0)
255235b3e579Smckusick	swc1	$f9, U_PCB_FPREGS+(9 * 4)(a0)
255335b3e579Smckusick	swc1	$f10, U_PCB_FPREGS+(10 * 4)(a0)
255435b3e579Smckusick	swc1	$f11, U_PCB_FPREGS+(11 * 4)(a0)
255535b3e579Smckusick	swc1	$f12, U_PCB_FPREGS+(12 * 4)(a0)
255635b3e579Smckusick	swc1	$f13, U_PCB_FPREGS+(13 * 4)(a0)
255735b3e579Smckusick	swc1	$f14, U_PCB_FPREGS+(14 * 4)(a0)
255835b3e579Smckusick	swc1	$f15, U_PCB_FPREGS+(15 * 4)(a0)
255935b3e579Smckusick	swc1	$f16, U_PCB_FPREGS+(16 * 4)(a0)
256035b3e579Smckusick	swc1	$f17, U_PCB_FPREGS+(17 * 4)(a0)
256135b3e579Smckusick	swc1	$f18, U_PCB_FPREGS+(18 * 4)(a0)
256235b3e579Smckusick	swc1	$f19, U_PCB_FPREGS+(19 * 4)(a0)
256335b3e579Smckusick	swc1	$f20, U_PCB_FPREGS+(20 * 4)(a0)
256435b3e579Smckusick	swc1	$f21, U_PCB_FPREGS+(21 * 4)(a0)
256535b3e579Smckusick	swc1	$f22, U_PCB_FPREGS+(22 * 4)(a0)
256635b3e579Smckusick	swc1	$f23, U_PCB_FPREGS+(23 * 4)(a0)
256735b3e579Smckusick	swc1	$f24, U_PCB_FPREGS+(24 * 4)(a0)
256835b3e579Smckusick	swc1	$f25, U_PCB_FPREGS+(25 * 4)(a0)
256935b3e579Smckusick	swc1	$f26, U_PCB_FPREGS+(26 * 4)(a0)
257035b3e579Smckusick	swc1	$f27, U_PCB_FPREGS+(27 * 4)(a0)
257135b3e579Smckusick	swc1	$f28, U_PCB_FPREGS+(28 * 4)(a0)
257235b3e579Smckusick	swc1	$f29, U_PCB_FPREGS+(29 * 4)(a0)
257335b3e579Smckusick	swc1	$f30, U_PCB_FPREGS+(30 * 4)(a0)
257435b3e579Smckusick	swc1	$f31, U_PCB_FPREGS+(31 * 4)(a0)
257535b3e579Smckusick
257635b3e579Smckusick	mtc0	t1, MACH_COP_0_STATUS_REG	# Restore the status register.
257735b3e579Smckusick	j	ra
257835b3e579Smckusick	nop
257935b3e579SmckusickEND(MachSaveCurFPState)
258035b3e579Smckusick
258135b3e579Smckusick/*----------------------------------------------------------------------------
258235b3e579Smckusick *
258335b3e579Smckusick * MachFPInterrupt --
258435b3e579Smckusick *
258535b3e579Smckusick *	Handle a floating point interrupt.
258635b3e579Smckusick *
258735b3e579Smckusick *	MachFPInterrupt(statusReg, causeReg, pc)
258835b3e579Smckusick *		unsigned statusReg;
258935b3e579Smckusick *		unsigned causeReg;
259035b3e579Smckusick *		unsigned pc;
259135b3e579Smckusick *
259235b3e579Smckusick * Results:
259335b3e579Smckusick *	None.
259435b3e579Smckusick *
259535b3e579Smckusick * Side effects:
259635b3e579Smckusick *	None.
259735b3e579Smckusick *
259835b3e579Smckusick *----------------------------------------------------------------------------
259935b3e579Smckusick */
260035b3e579SmckusickNON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra)
260135b3e579Smckusick	subu	sp, sp, STAND_FRAME_SIZE
260235b3e579Smckusick	mfc0	t0, MACH_COP_0_STATUS_REG
260335b3e579Smckusick	sw	ra, STAND_RA_OFFSET(sp)
260435b3e579Smckusick	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
260535b3e579Smckusick
260635b3e579Smckusick	or	t1, t0, MACH_SR_COP_1_BIT
260735b3e579Smckusick	mtc0	t1, MACH_COP_0_STATUS_REG
260835b3e579Smckusick	nop
260935b3e579Smckusick	nop
26104cf6ea80Sralph	cfc1	t1, MACH_FPC_CSR	# stall til FP done
26114cf6ea80Sralph	cfc1	t1, MACH_FPC_CSR	# now get status
261235b3e579Smckusick	nop
261335b3e579Smckusick	sll	t2, t1, (31 - 17)	# unimplemented operation?
261435b3e579Smckusick	bgez	t2, 3f			# no, normal trap
26154854f40cSralph	nop
261635b3e579Smckusick/*
261735b3e579Smckusick * We got an unimplemented operation trap so
261835b3e579Smckusick * fetch the instruction, compute the next PC and emulate the instruction.
261935b3e579Smckusick */
262035b3e579Smckusick	bgez	a1, 1f			# Check the branch delay bit.
26214854f40cSralph	nop
262235b3e579Smckusick/*
262335b3e579Smckusick * The instruction is in the branch delay slot so the branch will have to
262435b3e579Smckusick * be emulated to get the resulting PC.
262535b3e579Smckusick */
262635b3e579Smckusick	sw	a2, STAND_FRAME_SIZE + 8(sp)
262735b3e579Smckusick	li	a0, UADDR+U_PCB_REGS	# first arg is ptr to CPU registers
262835b3e579Smckusick	move	a1, a2			# second arg is instruction PC
262935b3e579Smckusick	move	a2, t1			# third arg is floating point CSR
263035b3e579Smckusick	jal	MachEmulateBranch	# compute PC after branch
26314854f40cSralph	move	a3, zero		# fourth arg is FALSE
263235b3e579Smckusick/*
263335b3e579Smckusick * Now load the floating-point instruction in the branch delay slot
263435b3e579Smckusick * to be emulated.
263535b3e579Smckusick */
263635b3e579Smckusick	lw	a2, STAND_FRAME_SIZE + 8(sp)	# restore EXC pc
263735b3e579Smckusick	b	2f
26384854f40cSralph	lw	a0, 4(a2)			# a0 = coproc instruction
263935b3e579Smckusick/*
264035b3e579Smckusick * This is not in the branch delay slot so calculate the resulting
264135b3e579Smckusick * PC (epc + 4) into v0 and continue to MachEmulateFP().
264235b3e579Smckusick */
264335b3e579Smckusick1:
264435b3e579Smckusick	lw	a0, 0(a2)			# a0 = coproc instruction
264535b3e579Smckusick	addu	v0, a2, 4			# v0 = next pc
264635b3e579Smckusick2:
264735b3e579Smckusick	sw	v0, UADDR+U_PCB_REGS+(PC * 4)	# save new pc
264835b3e579Smckusick/*
264935b3e579Smckusick * Check to see if the instruction to be emulated is a floating-point
265035b3e579Smckusick * instruction.
265135b3e579Smckusick */
265235b3e579Smckusick	srl	a3, a0, MACH_OPCODE_SHIFT
265335b3e579Smckusick	beq	a3, MACH_OPCODE_C1, 4f		# this should never fail
265435b3e579Smckusick/*
265535b3e579Smckusick * Send a floating point exception signal to the current process.
265635b3e579Smckusick */
265735b3e579Smckusick3:
265835b3e579Smckusick	lw	a0, curproc			# get current process
265935b3e579Smckusick	cfc1	a2, MACH_FPC_CSR		# code = FP execptions
266035b3e579Smckusick	ctc1	zero, MACH_FPC_CSR		# Clear exceptions
266135b3e579Smckusick	jal	trapsignal
26624854f40cSralph	li	a1, SIGFPE
266335b3e579Smckusick	b	FPReturn
26644854f40cSralph	nop
266535b3e579Smckusick
266635b3e579Smckusick/*
266735b3e579Smckusick * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate.
266835b3e579Smckusick */
266935b3e579Smckusick4:
267035b3e579Smckusick	jal	MachEmulateFP
26714854f40cSralph	nop
267235b3e579Smckusick
267335b3e579Smckusick/*
267435b3e579Smckusick * Turn off the floating point coprocessor and return.
267535b3e579Smckusick */
267635b3e579SmckusickFPReturn:
267735b3e579Smckusick	mfc0	t0, MACH_COP_0_STATUS_REG
267835b3e579Smckusick	lw	ra, STAND_RA_OFFSET(sp)
267935b3e579Smckusick	and	t0, t0, ~MACH_SR_COP_1_BIT
268035b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG
268135b3e579Smckusick	j	ra
268235b3e579Smckusick	addu	sp, sp, STAND_FRAME_SIZE
268335b3e579SmckusickEND(MachFPInterrupt)
268435b3e579Smckusick
268535b3e579Smckusick/*----------------------------------------------------------------------------
268635b3e579Smckusick *
268735b3e579Smckusick * MachConfigCache --
268835b3e579Smckusick *
268935b3e579Smckusick *	Size the caches.
269035b3e579Smckusick *	NOTE: should only be called from mach_init().
269135b3e579Smckusick *
269235b3e579Smckusick * Results:
269335b3e579Smckusick *     	None.
269435b3e579Smckusick *
269535b3e579Smckusick * Side effects:
269635b3e579Smckusick *	The size of the data cache is stored into machDataCacheSize and the
269735b3e579Smckusick *	size of instruction cache is stored into machInstCacheSize.
269835b3e579Smckusick *
269935b3e579Smckusick *----------------------------------------------------------------------------
270035b3e579Smckusick */
270135b3e579SmckusickNON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra)
270235b3e579Smckusick	subu	sp, sp, STAND_FRAME_SIZE
270335b3e579Smckusick	sw	ra, STAND_RA_OFFSET(sp)		# Save return address.
270435b3e579Smckusick	.mask	0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
270535b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
270635b3e579Smckusick	la	v0, 1f
270735b3e579Smckusick	or	v0, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
270835b3e579Smckusick	j	v0
270935b3e579Smckusick	nop
271035b3e579Smckusick1:
271135b3e579Smckusick/*
271235b3e579Smckusick * This works because jal doesn't change pc[31..28] and the
271335b3e579Smckusick * linker still thinks SizeCache is in the cached region so it computes
271435b3e579Smckusick * the correct address without complaining.
271535b3e579Smckusick */
271635b3e579Smckusick	jal	SizeCache			# Get the size of the d-cache.
271735b3e579Smckusick	nop
271835b3e579Smckusick	sw	v0, machDataCacheSize
271935b3e579Smckusick	nop					# Make sure sw out of pipe
272035b3e579Smckusick	nop
272135b3e579Smckusick	nop
272235b3e579Smckusick	nop
272335b3e579Smckusick	li	v0, MACH_SR_SWAP_CACHES		# Swap caches
272435b3e579Smckusick	mtc0	v0, MACH_COP_0_STATUS_REG
272535b3e579Smckusick	nop					# Insure caches stable
272635b3e579Smckusick	nop
272735b3e579Smckusick	nop
272835b3e579Smckusick	nop
272935b3e579Smckusick	jal	SizeCache			# Get the size of the i-cache.
273035b3e579Smckusick	nop
2731193a1c3eSralph	mtc0	zero, MACH_COP_0_STATUS_REG	# Swap back caches and enable.
2732193a1c3eSralph	nop
2733193a1c3eSralph	nop
2734193a1c3eSralph	nop
2735193a1c3eSralph	nop
273635b3e579Smckusick	sw	v0, machInstCacheSize
273735b3e579Smckusick	la	t0, 1f
273835b3e579Smckusick	j	t0				# Back to cached mode
273935b3e579Smckusick	nop
274035b3e579Smckusick1:
274135b3e579Smckusick	lw	ra, STAND_RA_OFFSET(sp)		# Restore return addr
274235b3e579Smckusick	addu	sp, sp, STAND_FRAME_SIZE	# Restore sp.
274335b3e579Smckusick	j	ra
274435b3e579Smckusick	nop
274535b3e579SmckusickEND(MachConfigCache)
274635b3e579Smckusick
274735b3e579Smckusick/*----------------------------------------------------------------------------
274835b3e579Smckusick *
274935b3e579Smckusick * SizeCache --
275035b3e579Smckusick *
275135b3e579Smckusick *	Get the size of the cache.
275235b3e579Smckusick *
275335b3e579Smckusick * Results:
275435b3e579Smckusick *	The size of the cache.
275535b3e579Smckusick *
275635b3e579Smckusick * Side effects:
275735b3e579Smckusick *	None.
275835b3e579Smckusick *
275935b3e579Smckusick *----------------------------------------------------------------------------
276035b3e579Smckusick */
276135b3e579SmckusickLEAF(SizeCache)
276235b3e579Smckusick	mfc0	t0, MACH_COP_0_STATUS_REG	# Save the current status reg.
276335b3e579Smckusick	nop
276435b3e579Smckusick	or	v0, t0, MACH_SR_ISOL_CACHES	# Isolate the caches.
276535b3e579Smckusick	nop					# Make sure no stores in pipe
276635b3e579Smckusick	mtc0	v0, MACH_COP_0_STATUS_REG
276735b3e579Smckusick	nop					# Make sure isolated
276835b3e579Smckusick	nop
276935b3e579Smckusick	nop
277035b3e579Smckusick/*
277135b3e579Smckusick * Clear cache size boundaries.
277235b3e579Smckusick */
277335b3e579Smckusick	li	v0, MACH_MIN_CACHE_SIZE
2774193a1c3eSralph	li	v1, MACH_CACHED_MEMORY_ADDR
2775193a1c3eSralph	li	t2, MACH_MAX_CACHE_SIZE
277635b3e579Smckusick1:
2777193a1c3eSralph	addu	t1, v0, v1			# Compute address to clear
2778193a1c3eSralph	sw	zero, 0(t1)			# Clear cache memory
2779193a1c3eSralph	bne	v0, t2, 1b
278035b3e579Smckusick	sll	v0, v0, 1
2781193a1c3eSralph
278235b3e579Smckusick	li	v0, -1
2783193a1c3eSralph	sw	v0, 0(v1)			# Store marker in cache
278435b3e579Smckusick	li	v0, MACH_MIN_CACHE_SIZE
278535b3e579Smckusick2:
2786193a1c3eSralph	addu	t1, v0, v1			# Compute address
2787193a1c3eSralph	lw	t3, 0(t1)			# Look for marker
278835b3e579Smckusick	nop
2789193a1c3eSralph	bne	t3, zero, 3f			# Found marker.
279035b3e579Smckusick	nop
2791193a1c3eSralph	bne	v0, t2, 2b			# keep looking
279235b3e579Smckusick	sll	v0, v0, 1			# cache size * 2
2793193a1c3eSralph
279435b3e579Smckusick	move	v0, zero			# must be no cache
279535b3e579Smckusick3:
279635b3e579Smckusick	mtc0	t0, MACH_COP_0_STATUS_REG
279735b3e579Smckusick	nop					# Make sure unisolated
279835b3e579Smckusick	nop
279935b3e579Smckusick	nop
280035b3e579Smckusick	nop
280135b3e579Smckusick	j	ra
280235b3e579Smckusick	nop
280335b3e579SmckusickEND(SizeCache)
280435b3e579Smckusick
280535b3e579Smckusick/*----------------------------------------------------------------------------
280635b3e579Smckusick *
280735b3e579Smckusick * MachFlushCache --
280835b3e579Smckusick *
280935b3e579Smckusick *	Flush the caches.
281035b3e579Smckusick *
281135b3e579Smckusick * Results:
281235b3e579Smckusick *	None.
281335b3e579Smckusick *
281435b3e579Smckusick * Side effects:
281535b3e579Smckusick *	The contents of the caches is flushed.
281635b3e579Smckusick *
281735b3e579Smckusick *----------------------------------------------------------------------------
281835b3e579Smckusick */
281935b3e579SmckusickLEAF(MachFlushCache)
282035b3e579Smckusick	lw	t1, machInstCacheSize		# Must load before isolating
282135b3e579Smckusick	lw	t2, machDataCacheSize		# Must load before isolating
282235b3e579Smckusick	mfc0	t3, MACH_COP_0_STATUS_REG 	# Save the status register.
282335b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
282435b3e579Smckusick	la	v0, 1f
282535b3e579Smckusick	or	v0, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
282635b3e579Smckusick	j	v0
282735b3e579Smckusick	nop
282835b3e579Smckusick/*
282935b3e579Smckusick * Flush the instruction cache.
283035b3e579Smckusick */
283135b3e579Smckusick1:
283235b3e579Smckusick	li	v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
283335b3e579Smckusick	mtc0	v0, MACH_COP_0_STATUS_REG	# Isolate and swap caches.
283435b3e579Smckusick	li	t0, MACH_UNCACHED_MEMORY_ADDR
283535b3e579Smckusick	subu	t0, t0, t1
283635b3e579Smckusick	li	t1, MACH_UNCACHED_MEMORY_ADDR
283735b3e579Smckusick	la	v0, 1f				# Run cached
283835b3e579Smckusick	j	v0
283935b3e579Smckusick	nop
284035b3e579Smckusick1:
28414cf6ea80Sralph	addu	t0, t0, 4
284235b3e579Smckusick	bne	t0, t1, 1b
284335b3e579Smckusick	sb	zero, -4(t0)
284435b3e579Smckusick
284535b3e579Smckusick	la	v0, 1f
284635b3e579Smckusick	or	v0, MACH_UNCACHED_MEMORY_ADDR
284735b3e579Smckusick	j	v0				# Run uncached
284835b3e579Smckusick	nop
284935b3e579Smckusick/*
285035b3e579Smckusick * Flush the data cache.
285135b3e579Smckusick */
285235b3e579Smckusick1:
285335b3e579Smckusick	li	v0, MACH_SR_ISOL_CACHES
285435b3e579Smckusick	mtc0	v0, MACH_COP_0_STATUS_REG	# Isolate and swap back caches
285535b3e579Smckusick	li	t0, MACH_UNCACHED_MEMORY_ADDR
285635b3e579Smckusick	subu	t0, t0, t2
285735b3e579Smckusick	la	v0, 1f
285835b3e579Smckusick	j	v0				# Back to cached mode
285935b3e579Smckusick	nop
286035b3e579Smckusick1:
28614cf6ea80Sralph	addu	t0, t0, 4
286235b3e579Smckusick	bne	t0, t1, 1b
286335b3e579Smckusick	sb	zero, -4(t0)
286435b3e579Smckusick
286535b3e579Smckusick	nop					# Insure isolated stores
286635b3e579Smckusick	nop					#   out of pipe.
286735b3e579Smckusick	nop
286835b3e579Smckusick	nop
286935b3e579Smckusick	mtc0	t3, MACH_COP_0_STATUS_REG	# Restore status reg.
287035b3e579Smckusick	nop					# Insure cache unisolated.
287135b3e579Smckusick	nop
287235b3e579Smckusick	nop
287335b3e579Smckusick	nop
287435b3e579Smckusick	j	ra
287535b3e579Smckusick	nop
287635b3e579SmckusickEND(MachFlushCache)
287735b3e579Smckusick
287835b3e579Smckusick/*----------------------------------------------------------------------------
287935b3e579Smckusick *
288035b3e579Smckusick * MachFlushICache --
288135b3e579Smckusick *
28824cf6ea80Sralph *	void MachFlushICache(addr, len)
28834cf6ea80Sralph *		vm_offset_t addr, len;
288435b3e579Smckusick *
288535b3e579Smckusick *	Flush instruction cache for range of addr to addr + len - 1.
28864cf6ea80Sralph *	The address can be any valid address so long as no TLB misses occur.
288735b3e579Smckusick *
288835b3e579Smckusick * Results:
288935b3e579Smckusick *	None.
289035b3e579Smckusick *
289135b3e579Smckusick * Side effects:
289235b3e579Smckusick *	The contents of the cache is flushed.
289335b3e579Smckusick *
289435b3e579Smckusick *----------------------------------------------------------------------------
289535b3e579Smckusick */
289635b3e579SmckusickLEAF(MachFlushICache)
28974cf6ea80Sralph	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
289835b3e579Smckusick	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
289935b3e579Smckusick
29004cf6ea80Sralph	la	v1, 1f
29014cf6ea80Sralph	or	v1, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
29024cf6ea80Sralph	j	v1
290335b3e579Smckusick	nop
290435b3e579Smckusick1:
29054cf6ea80Sralph	bc0f	1b				# make sure stores are complete
29064cf6ea80Sralph	li	v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
29074cf6ea80Sralph	mtc0	v1, MACH_COP_0_STATUS_REG
290835b3e579Smckusick	nop
29094cf6ea80Sralph	addu	a1, a1, a0			# compute ending address
291035b3e579Smckusick1:
29114cf6ea80Sralph	addu	a0, a0, 4
29124cf6ea80Sralph	bne	a0, a1, 1b
29134cf6ea80Sralph	sb	zero, -4(a0)
291435b3e579Smckusick
29154cf6ea80Sralph	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts
291635b3e579Smckusick	j	ra				# return and run cached
291735b3e579Smckusick	nop
291835b3e579SmckusickEND(MachFlushICache)
29194cf6ea80Sralph
2920a2916846Sralph/*----------------------------------------------------------------------------
2921a2916846Sralph *
2922a2916846Sralph * MachFlushDCache --
2923a2916846Sralph *
2924a2916846Sralph *	void MachFlushDCache(addr, len)
2925a2916846Sralph *		vm_offset_t addr, len;
2926a2916846Sralph *
2927a2916846Sralph *	Flush data cache for range of addr to addr + len - 1.
2928a2916846Sralph *	The address can be any valid address so long as no TLB misses occur.
2929a2916846Sralph *	(Be sure to use cached K0SEG kernel addresses)
2930a2916846Sralph * Results:
2931a2916846Sralph *	None.
2932a2916846Sralph *
2933a2916846Sralph * Side effects:
2934a2916846Sralph *	The contents of the cache is flushed.
2935a2916846Sralph *
2936a2916846Sralph *----------------------------------------------------------------------------
2937a2916846Sralph */
2938a2916846SralphLEAF(MachFlushDCache)
2939a2916846Sralph	mfc0	t0, MACH_COP_0_STATUS_REG	# Save SR
2940a2916846Sralph	mtc0	zero, MACH_COP_0_STATUS_REG	# Disable interrupts.
2941a2916846Sralph
2942a2916846Sralph	la	v1, 1f
2943a2916846Sralph	or	v1, MACH_UNCACHED_MEMORY_ADDR	# Run uncached.
2944a2916846Sralph	j	v1
2945a2916846Sralph	nop
2946a2916846Sralph1:
2947a2916846Sralph	bc0f	1b				# make sure stores are complete
2948a2916846Sralph	li	v1, MACH_SR_ISOL_CACHES
2949a2916846Sralph	mtc0	v1, MACH_COP_0_STATUS_REG
2950a2916846Sralph	nop
2951a2916846Sralph	addu	a1, a1, a0			# compute ending address
2952a2916846Sralph1:
2953a2916846Sralph	addu	a0, a0, 4
2954a2916846Sralph	bne	a0, a1, 1b
2955a2916846Sralph	sb	zero, -4(a0)
2956a2916846Sralph
2957a2916846Sralph	mtc0	t0, MACH_COP_0_STATUS_REG	# enable interrupts
2958a2916846Sralph	j	ra				# return and run cached
2959a2916846Sralph	nop
2960a2916846SralphEND(MachFlushDCache)
2961a2916846Sralph
29624cf6ea80Sralph#ifdef KADB
29634cf6ea80Sralph/*
29644cf6ea80Sralph * Read a long and return it.
29654cf6ea80Sralph * Note: addresses can be unaligned!
29664cf6ea80Sralph *
29674cf6ea80Sralph * long
29684cf6ea80SralphL* kdbpeek(addr)
29694cf6ea80SralphL*	caddt_t addr;
29704cf6ea80SralphL* {
29714cf6ea80SralphL*	return (*(long *)addr);
29724cf6ea80SralphL* }
29734cf6ea80Sralph */
29744cf6ea80SralphLEAF(kdbpeek)
29754cf6ea80Sralph	li	v0, KADBERR
29764cf6ea80Sralph	sw	v0, UADDR+U_PCB_ONFAULT
29774cf6ea80Sralph	and	v0, a0, 3		# unaligned address?
29784cf6ea80Sralph	bne	v0, zero, 1f
29794854f40cSralph	nop
29804cf6ea80Sralph	b	2f
29814854f40cSralph	lw	v0, (a0)		# aligned access
29824cf6ea80Sralph1:
29834cf6ea80Sralph	lwr	v0, 0(a0)		# get next 4 bytes (unaligned)
29844cf6ea80Sralph	lwl	v0, 3(a0)
29854cf6ea80Sralph2:
29864cf6ea80Sralph	j	ra			# made it w/o errors
29874854f40cSralph	sw	zero, UADDR+U_PCB_ONFAULT
29884cf6ea80Sralphkadberr:
29894cf6ea80Sralph	li	v0, 1			# trap sends us here
29904cf6ea80Sralph	sw	v0, kdbmkfault
29914cf6ea80Sralph	j	ra
29924854f40cSralph	nop
29934cf6ea80SralphEND(kdbpeek)
29944cf6ea80Sralph
29954cf6ea80Sralph/*
29964cf6ea80Sralph * Write a long to 'addr'.
29974cf6ea80Sralph * Note: addresses can be unaligned!
29984cf6ea80Sralph *
29994cf6ea80SralphL* void
30004cf6ea80SralphL* kdbpoke(addr, value)
30014cf6ea80SralphL*	caddt_t addr;
30024cf6ea80SralphL*	long value;
30034cf6ea80SralphL* {
30044cf6ea80SralphL*	*(long *)addr = value;
30054cf6ea80SralphL* }
30064cf6ea80Sralph */
30074cf6ea80SralphLEAF(kdbpoke)
30084cf6ea80Sralph	li	v0, KADBERR
30094cf6ea80Sralph	sw	v0, UADDR+U_PCB_ONFAULT
30104cf6ea80Sralph	and	v0, a0, 3		# unaligned address?
30114cf6ea80Sralph	bne	v0, zero, 1f
30124854f40cSralph	nop
30134cf6ea80Sralph	b	2f
30144854f40cSralph	sw	a1, (a0)		# aligned access
30154cf6ea80Sralph1:
30164cf6ea80Sralph	swr	a1, 0(a0)		# store next 4 bytes (unaligned)
30174cf6ea80Sralph	swl	a1, 3(a0)
30184cf6ea80Sralph	and	a0, a0, ~3		# align address for cache flush
30194cf6ea80Sralph2:
30204cf6ea80Sralph	sw	zero, UADDR+U_PCB_ONFAULT
30214cf6ea80Sralph	b	MachFlushICache		# flush instruction cache
30224854f40cSralph	li	a1, 8
30234cf6ea80SralphEND(kdbpoke)
30244cf6ea80Sralph
30254cf6ea80Sralph/*
30264cf6ea80Sralph * Save registers and state so we can do a 'kdbreset' (like longjmp) later.
30274cf6ea80Sralph * Always returns zero.
30284cf6ea80Sralph *
30294cf6ea80SralphL* int kdb_savearea[11];
30304cf6ea80SralphL*
30314cf6ea80SralphL* int
30324cf6ea80SralphL* kdbsetexit()
30334cf6ea80SralphL* {
30344cf6ea80SralphL*	kdb_savearea[0] = 0;
30354cf6ea80SralphL*	return (0);
30364cf6ea80SralphL* }
30374cf6ea80Sralph */
30384cf6ea80Sralph	.comm	kdb_savearea, (11 * 4)
30394cf6ea80Sralph
30404cf6ea80SralphLEAF(kdbsetexit)
30414cf6ea80Sralph	la	a0, kdb_savearea
30424cf6ea80Sralph	sw	s0, 0(a0)
30434cf6ea80Sralph	sw	s1, 4(a0)
30444cf6ea80Sralph	sw	s2, 8(a0)
30454cf6ea80Sralph	sw	s3, 12(a0)
30464cf6ea80Sralph	sw	s4, 16(a0)
30474cf6ea80Sralph	sw	s5, 20(a0)
30484cf6ea80Sralph	sw	s6, 24(a0)
30494cf6ea80Sralph	sw	s7, 28(a0)
30504cf6ea80Sralph	sw	sp, 32(a0)
30514cf6ea80Sralph	sw	s8, 36(a0)
30524cf6ea80Sralph	sw	ra, 40(a0)
30534cf6ea80Sralph	j	ra
30544cf6ea80Sralph	move	v0, zero
30554cf6ea80SralphEND(kdbsetexit)
30564cf6ea80Sralph
30574cf6ea80Sralph/*
30584cf6ea80Sralph * Restore registers and state (like longjmp) and return x.
30594cf6ea80Sralph *
30604cf6ea80SralphL* int
30614cf6ea80SralphL* kdbreset(x)
30624cf6ea80SralphL* {
30634cf6ea80SralphL*	return (x);
30644cf6ea80SralphL* }
30654cf6ea80Sralph */
30664cf6ea80SralphLEAF(kdbreset)
30674cf6ea80Sralph	la	v0, kdb_savearea
30684cf6ea80Sralph	lw	ra, 40(v0)
30694cf6ea80Sralph	lw	s0, 0(v0)
30704cf6ea80Sralph	lw	s1, 4(v0)
30714cf6ea80Sralph	lw	s2, 8(v0)
30724cf6ea80Sralph	lw	s3, 12(v0)
30734cf6ea80Sralph	lw	s4, 16(v0)
30744cf6ea80Sralph	lw	s5, 20(v0)
30754cf6ea80Sralph	lw	s6, 24(v0)
30764cf6ea80Sralph	lw	s7, 28(v0)
30774cf6ea80Sralph	lw	sp, 32(v0)
30784cf6ea80Sralph	lw	s8, 36(v0)
30794cf6ea80Sralph	j	ra
30804cf6ea80Sralph	move	v0, a0
30814cf6ea80SralphEND(kdbreset)
30824cf6ea80Sralph
30834cf6ea80Sralph/*
30844cf6ea80Sralph * Trap into the debugger.
30854cf6ea80Sralph *
30864cf6ea80SralphL* void
30874cf6ea80SralphL* kdbpanic()
30884cf6ea80SralphL* {
30894cf6ea80SralphL* }
30904cf6ea80Sralph */
30914cf6ea80SralphLEAF(kdbpanic)
30924cf6ea80Sralph	break	MACH_BREAK_KDB_VAL
30934cf6ea80Sralph	j	ra
30944854f40cSralph	nop
30954cf6ea80SralphEND(kdbpanic)
30964cf6ea80Sralph#endif /* KADB */
30974854f40cSralph
30984854f40cSralph#ifdef DEBUG
309992e9186eSralphLEAF(cpu_getregs)
31004854f40cSralph	sw	sp, 0(a0)
310192e9186eSralph	sw	ra, 4(a0)
31024854f40cSralph	j	ra
310392e9186eSralph	sw	s8, 8(a0)
31044854f40cSralphEND(cpu_getregs)
31054854f40cSralph#endif /* DEBUG */
31064cec8633Sralph
31074cec8633Sralph/*
310892e9186eSralph * Interrupt counters for vmstat.
310992e9186eSralph * XXX These aren't used yet.
31104cec8633Sralph */
31114cec8633Sralph	.data
31124cec8633Sralph	.globl	intrcnt, eintrcnt, intrnames, eintrnames
31134cec8633Sralphintrnames:
3114*759b7897Sralph	.asciiz	"softclock"
3115*759b7897Sralph	.asciiz	"softnet"
3116*759b7897Sralph	.asciiz	"dc"
3117*759b7897Sralph	.asciiz	"ether"
3118*759b7897Sralph	.asciiz	"disk"
3119*759b7897Sralph	.asciiz	"memory"
312092e9186eSralph	.asciiz	"clock"
3121*759b7897Sralph	.asciiz	"fp"
31224cec8633Sralpheintrnames:
31234cec8633Sralph	.align	2
31244cec8633Sralphintrcnt:
3125*759b7897Sralph	.word	0,0,0,0,0,0,0,0
31264cec8633Sralpheintrcnt:
3127*759b7897Sralph	.word	0	# This shouldn't be needed but the eintrcnt label
3128*759b7897Sralph			# ends up in a different section otherwise.
3129