freebsd-nq/sys/mips/mips/tlb.S
Warner Losh 45d426a34e FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors.  There
presently is support for ADMtek ADM5120, A mips 4Kc in a malta board,
the RB533 routerboard (based on IDT RC32434) and some preliminary
support for sibtye/broadcom designs.  Other hardware support will be
forthcomcing.

This port boots multiuser under gxemul emulating the malta board and
also bootstraps on the hardware whose support is forthcoming...

Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard,
Randall Stewert and others that have contributed to the mips2 and/or
mips2-jnpr perforce branches.  Juniper contirbuted a generic mips port
late in the life cycle of the misp2 branch.  Warner Losh merged the
mips2 and Juniper code bases, and others list above have worked for
the past several months to get to multiuser.

In addition, the mips2 work owe a debt to the trail blazing efforts of
the original mips branch in perforce done by Juli Mallett.
2008-04-13 07:27:37 +00:00

510 lines
14 KiB
ArmAsm

/* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Digital Equipment Corporation and Ralph Campbell.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Copyright (C) 1989 Digital Equipment Corporation.
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies.
* Digital Equipment Corporation makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
* v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL)
* from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
* v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL)
* from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
* v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL)
*
* from: @(#)locore.s 8.5 (Berkeley) 1/4/94
* JNPR: tlb.S,v 1.1.4.2 2007/09/10 09:02:05 girish
* $FreeBSD$
*/
/*
* Contains code that is the first executed at boot time plus
* assembly language support routines.
*/
#include "opt_cputype.h"
#include <machine/asm.h>
#include <machine/cpu.h>
#include <machine/cpuregs.h>
#include <machine/regnum.h>
#include <machine/pte.h>
#include "assym.s"
#if defined(ISA_MIPS32)
#undef WITH_64BIT_CP0
#elif defined(ISA_MIPS64)
#define WITH_64BIT_CP0
#elif defined(ISA_MIPS3)
#define WITH_64BIT_CP0
#else
#error "Please write the code for this ISA"
#endif
#ifdef WITH_64BIT_CP0
#define _SLL dsll
#define _SRL dsrl
#define _MFC0 dmfc0
#define _MTC0 dmtc0
#define WIRED_SHIFT 34
#define PAGE_SHIFT 34
#else
#define _SLL sll
#define _SRL srl
#define _MFC0 mfc0
#define _MTC0 mtc0
#define WIRED_SHIFT 2
#define PAGE_SHIFT 2
#endif
.set noreorder # Noreorder is default style!
#if defined(ISA_MIPS32)
.set mips32
#elif defined(ISA_MIPS64)
.set mips64
#elif defined(ISA_MIPS3)
.set mips3
#endif
#define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
/*
* FREEBSD_DEVELOPERS_FIXME
* Some MIPS CPU may need delays using nops between executing CP0 Instructions
*/
#define MIPS_CPU_NOP_DELAY nop;nop;nop;nop;
/*--------------------------------------------------------------------------
*
* Mips_TLBWriteIndexed(unsigned index, tlb *tlb);
*
* Write the given entry into the TLB at the given index.
*
* Results:
* None.
*
* Side effects:
* TLB entry set.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_TLBWriteIndexed)
mfc0 v1, COP_0_STATUS_REG # Save the status register.
mtc0 zero, COP_0_STATUS_REG # Disable interrupts
ITLBNOPFIX
lw a2, 8(a1)
lw a3, 12(a1)
_MFC0 t0, COP_0_TLB_HI # Save the current PID.
_MTC0 a2, COP_0_TLB_LO0 # Set up entry low0.
_MTC0 a3, COP_0_TLB_LO1 # Set up entry low1.
lw a2, 0(a1)
lw a3, 4(a1)
mtc0 a0, COP_0_TLB_INDEX # Set the index.
_MTC0 a2, COP_0_TLB_PG_MASK # Set up entry mask.
_MTC0 a3, COP_0_TLB_HI # Set up entry high.
MIPS_CPU_NOP_DELAY
tlbwi # Write the TLB
MIPS_CPU_NOP_DELAY
_MTC0 t0, COP_0_TLB_HI # Restore the PID.
nop
_MTC0 zero, COP_0_TLB_PG_MASK # Default mask value.
mtc0 v1, COP_0_STATUS_REG # Restore the status register
ITLBNOPFIX
j ra
nop
END(Mips_TLBWriteIndexed)
/*--------------------------------------------------------------------------
*
* Mips_SetPID(int pid);
*
* Write the given pid into the TLB pid reg.
*
* Results:
* None.
*
* Side effects:
* PID set in the entry hi register.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_SetPID)
_MTC0 a0, COP_0_TLB_HI # Write the hi reg value
nop # required for QED5230
nop # required for QED5230
j ra
nop
END(Mips_SetPID)
/*--------------------------------------------------------------------------
*
* Mips_SetWIRED(int wired);
*
* Write the given value into the TLB wired reg.
*
* Results:
* None.
*
* Side effects:
* WIRED set in the wired register.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_SetWIRED)
mtc0 a0, COP_0_TLB_WIRED
j ra
nop
END(Mips_SetWIRED)
/*--------------------------------------------------------------------------
*
* Mips_GetWIRED(void);
*
* Get the value from the TLB wired reg.
*
* Results:
* Value of wired reg.
*
* Side effects:
* None.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_GetWIRED)
mfc0 v0, COP_0_TLB_WIRED
j ra
nop
END(Mips_GetWIRED)
/*--------------------------------------------------------------------------
*
* Mips_TLBFlush(tlbsize);
*
* Flush the "random" entries from the TLB.
* Uses "wired" register to determine what register to start with.
* Arg "tlbsize" is the number of entries to flush.
*
* Results:
* None.
*
* Side effects:
* The TLB is flushed.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_TLBFlush)
mfc0 v1, COP_0_STATUS_REG # Save the status register.
mtc0 zero, COP_0_STATUS_REG # Disable interrupts
ITLBNOPFIX
mfc0 t1, COP_0_TLB_WIRED
li v0, MIPS_KSEG3_START + 0x0fff0000 # invalid address
_MFC0 t0, COP_0_TLB_HI # Save the PID
_MTC0 v0, COP_0_TLB_HI # Mark entry high as invalid
_MTC0 zero, COP_0_TLB_LO0 # Zero out low entry0.
_MTC0 zero, COP_0_TLB_LO1 # Zero out low entry1.
mtc0 zero, COP_0_TLB_PG_MASK # Zero out mask entry.
/*
* Align the starting value (t1) and the upper bound (a0).
*/
1:
mtc0 t1, COP_0_TLB_INDEX # Set the index register.
ITLBNOPFIX
_MTC0 t0, COP_0_TLB_HI # Restore the PID
addu t1, t1, 1 # Increment index.
addu t0, t0, 8 * 1024
MIPS_CPU_NOP_DELAY
tlbwi # Write the TLB entry.
MIPS_CPU_NOP_DELAY
bne t1, a0, 1b
nop
_MTC0 t0, COP_0_TLB_HI # Restore the PID
mtc0 v1, COP_0_STATUS_REG # Restore the status register
ITLBNOPFIX
j ra
nop
END(Mips_TLBFlush)
/*--------------------------------------------------------------------------
*
* Mips_TLBFlushAddr(unsigned TLBhi);
*
* Flush any TLB entries for the given address and TLB PID.
*
* Results:
* None.
*
* Side effects:
* The process's page is flushed from the TLB.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_TLBFlushAddr)
mfc0 v1, COP_0_STATUS_REG # Save the status register.
mtc0 zero, COP_0_STATUS_REG # Disable interrupts
ITLBNOPFIX
li v0, (PTE_HVPN | PTE_ASID)
and a0, a0, v0 # Make shure valid hi value.
_MFC0 t0, COP_0_TLB_HI # Get current PID
mfc0 t3, COP_0_TLB_PG_MASK # Save current pgMask
_MTC0 a0, COP_0_TLB_HI # look for addr & PID
MIPS_CPU_NOP_DELAY
tlbp # Probe for the entry.
MIPS_CPU_NOP_DELAY
mfc0 v0, COP_0_TLB_INDEX # See what we got
li t1, MIPS_KSEG0_START + 0x0fff0000
bltz v0, 1f # index < 0 => !found
nop
# Load invalid entry, each TLB entry should have it's own bogus
# address calculated by following expression:
# MIPS_KSEG0_START + 0x0fff0000 + 2 * i * PAGE_SIZE;
# One bogus value for every TLB entry might cause MCHECK exception
sll v0, PAGE_SHIFT + 1
addu t1, v0
_MTC0 t1, COP_0_TLB_HI # Mark entry high as invalid
_MTC0 zero, COP_0_TLB_LO0 # Zero out low entry.
_MTC0 zero, COP_0_TLB_LO1 # Zero out low entry.
MIPS_CPU_NOP_DELAY
tlbwi
MIPS_CPU_NOP_DELAY
1:
_MTC0 t0, COP_0_TLB_HI # restore PID
mtc0 t3, COP_0_TLB_PG_MASK # Restore pgMask
mtc0 v1, COP_0_STATUS_REG # Restore the status register
ITLBNOPFIX
j ra
nop
END(Mips_TLBFlushAddr)
/*--------------------------------------------------------------------------
*
* Mips_TLBUpdate(unsigned virpageadr, lowregx);
*
* Update the TLB if highreg is found; otherwise, enter the data.
*
* Results:
* < 0 if loaded >= 0 if updated.
*
* Side effects:
* None.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_TLBUpdate)
mfc0 v1, COP_0_STATUS_REG # Save the status register.
mtc0 zero, COP_0_STATUS_REG # Disable interrupts
ITLBNOPFIX
and t1, a0, 0x1000 # t1 = Even/Odd flag
li v0, (PTE_HVPN | PTE_ASID)
and a0, a0, v0
_MFC0 t0, COP_0_TLB_HI # Save current PID
_MTC0 a0, COP_0_TLB_HI # Init high reg
and a2, a1, PTE_G # Copy global bit
MIPS_CPU_NOP_DELAY
tlbp # Probe for the entry.
_SLL a1, a1, WIRED_SHIFT
_SRL a1, a1, WIRED_SHIFT
nop
mfc0 v0, COP_0_TLB_INDEX # See what we got
bne t1, zero, 2f # Decide even odd
# EVEN
nop
bltz v0, 1f # index < 0 => !found
MIPS_CPU_NOP_DELAY
tlbr # update, read entry first
MIPS_CPU_NOP_DELAY
_MTC0 a1, COP_0_TLB_LO0 # init low reg0.
MIPS_CPU_NOP_DELAY
tlbwi # update slot found
b 4f
nop
1:
mtc0 zero, COP_0_TLB_PG_MASK # init mask.
_MTC0 a0, COP_0_TLB_HI # init high reg.
_MTC0 a1, COP_0_TLB_LO0 # init low reg0.
_MTC0 a2, COP_0_TLB_LO1 # init low reg1.
MIPS_CPU_NOP_DELAY
tlbwr # enter into a random slot
MIPS_CPU_NOP_DELAY
b 4f
nop
# ODD
2:
nop
bltz v0, 3f # index < 0 => !found
MIPS_CPU_NOP_DELAY
tlbr # read the entry first
MIPS_CPU_NOP_DELAY
_MTC0 a1, COP_0_TLB_LO1 # init low reg1.
MIPS_CPU_NOP_DELAY
tlbwi # update slot found
MIPS_CPU_NOP_DELAY
b 4f
nop
3:
mtc0 zero, COP_0_TLB_PG_MASK # init mask.
_MTC0 a0, COP_0_TLB_HI # init high reg.
_MTC0 a2, COP_0_TLB_LO0 # init low reg0.
_MTC0 a1, COP_0_TLB_LO1 # init low reg1.
MIPS_CPU_NOP_DELAY
tlbwr # enter into a random slot
4: # Make shure pipeline
MIPS_CPU_NOP_DELAY
_MTC0 t0, COP_0_TLB_HI # restore PID
mtc0 v1, COP_0_STATUS_REG # Restore the status register
ITLBNOPFIX
j ra
nop
END(Mips_TLBUpdate)
/*--------------------------------------------------------------------------
*
* Mips_TLBRead(unsigned entry, struct tlb *tlb);
*
* Read the TLB entry.
*
* Results:
* None.
*
* Side effects:
* tlb will contain the TLB entry found.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_TLBRead)
mfc0 v1, COP_0_STATUS_REG # Save the status register.
mtc0 zero, COP_0_STATUS_REG # Disable interrupts
ITLBNOPFIX
_MFC0 t0, COP_0_TLB_HI # Get current PID
mtc0 a0, COP_0_TLB_INDEX # Set the index register
MIPS_CPU_NOP_DELAY
tlbr # Read from the TLB
MIPS_CPU_NOP_DELAY
mfc0 t2, COP_0_TLB_PG_MASK # fetch the hi entry
_MFC0 t3, COP_0_TLB_HI # fetch the hi entry
_MFC0 t4, COP_0_TLB_LO0 # See what we got
_MFC0 t5, COP_0_TLB_LO1 # See what we got
_MTC0 t0, COP_0_TLB_HI # restore PID
MIPS_CPU_NOP_DELAY
mtc0 v1, COP_0_STATUS_REG # Restore the status register
ITLBNOPFIX
sw t2, 0(a1)
sw t3, 4(a1)
sw t4, 8(a1)
j ra
sw t5, 12(a1)
END(Mips_TLBRead)
/*--------------------------------------------------------------------------
*
* Mips_TLBGetPID(void);
*
* Results:
* Returns the current TLB pid reg.
*
* Side effects:
* None.
*
*--------------------------------------------------------------------------
*/
LEAF(Mips_TLBGetPID)
_MFC0 v0, COP_0_TLB_HI # get PID
j ra
and v0, v0, VMTLB_PID # mask off PID
END(Mips_TLBGetPID)
/*--------------------------------------------------------------------------
*
* void mips_TBIAP(int sizeofTLB);
*
* Invalidate TLB entries belong to per process user spaces while
* leaving entries for kernel space marked global intact.
*
*--------------------------------------------------------------------------
*/
LEAF(mips_TBIAP)
mfc0 v1, COP_0_STATUS_REG # save status register
mtc0 zero, COP_0_STATUS_REG # disable interrupts
_MFC0 t4, COP_0_TLB_HI # Get current PID
move t2, a0
mfc0 t1, COP_0_TLB_WIRED
li v0, MIPS_KSEG0_START + 0x0fff0000 # invalid address
mfc0 t3, COP_0_TLB_PG_MASK # save current pgMask
# do {} while (t1 < t2)
1:
mtc0 t1, COP_0_TLB_INDEX # set index
MIPS_CPU_NOP_DELAY
tlbr # obtain an entry
MIPS_CPU_NOP_DELAY
_MFC0 a0, COP_0_TLB_LO1
and a0, a0, PTE_G # check to see it has G bit
bnez a0, 2f
nop
_MTC0 v0, COP_0_TLB_HI # make entryHi invalid
_MTC0 zero, COP_0_TLB_LO0 # zero out entryLo0
_MTC0 zero, COP_0_TLB_LO1 # zero out entryLo1
mtc0 zero, COP_0_TLB_PG_MASK # zero out mask entry
MIPS_CPU_NOP_DELAY
tlbwi # invalidate the TLB entry
2:
addu t1, t1, 1
addu v0, 1 << (PAGE_SHIFT + 1)
bne t1, t2, 1b
nop
_MTC0 t4, COP_0_TLB_HI # restore PID
mtc0 t3, COP_0_TLB_PG_MASK # restore pgMask
MIPS_CPU_NOP_DELAY
mtc0 v1, COP_0_STATUS_REG # restore status register
j ra # new ASID will be set soon
nop
.set mips2
END(mips_TBIAP)