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