/*1* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 20092* The President and Fellows of Harvard College.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. Neither the name of the University nor the names of its contributors13* may be used to endorse or promote products derived from this software14* without specific prior written permission.15*16* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* CPU control functions.31*/3233#include <types.h>34#include <lib.h>35#include <mips/specialreg.h>36#include <mips/trapframe.h>37#include <platform/maxcpus.h>38#include <cpu.h>39#include <thread.h>4041////////////////////////////////////////////////////////////4243/*44* Startup and exception-time stack hook.45*46* The MIPS lacks a good way to find the current CPU, current thread,47* or current thread stack upon trap entry from user mode. To deal48* with this, we store the CPU number (our number, not the hardware49* number) in a nonessential field in the MMU, which is about the only50* place possible, and then use that to index cpustacks[]. This gets51* us the value to load as the stack pointer. We can then also load52* curthread from cputhreads[] by parallel indexing.53*54* These arrays are also used to start up new CPUs, for roughly the55* same reasons.56*/5758vaddr_t cpustacks[MAXCPUS];59vaddr_t cputhreads[MAXCPUS];6061/*62* Do machine-dependent initialization of the cpu structure or things63* associated with a new cpu. Note that we're not running on the new64* cpu when this is called.65*/66void67cpu_machdep_init(struct cpu *c)68{69vaddr_t stackpointer;7071KASSERT(c->c_number < MAXCPUS);7273if (c->c_curthread->t_stack == NULL) {74/* boot cpu; don't need to do anything here */75}76else {77/*78* Stick the stack in cpustacks[], and thread pointer79* in cputhreads[].80*/8182/* stack base address */83stackpointer = (vaddr_t) c->c_curthread->t_stack;84/* since stacks grow down, get the top */85stackpointer += STACK_SIZE;8687cpustacks[c->c_number] = stackpointer;88cputhreads[c->c_number] = (vaddr_t)c->c_curthread;89}90}9192////////////////////////////////////////////////////////////9394/*95* Return the type name of the currently running CPU.96*/9798const char *99cpu_identify(void)100{101/* XXX Ought to be more sophisticated. */102return "MIPS r3000";103}104105////////////////////////////////////////////////////////////106107/*108* Interrupt control.109*110* While the mips actually has on-chip interrupt priority masking, in111* the interests of simplicity, we don't use it. Instead we use112* coprocessor 0 register 12 (the system coprocessor "status"113* register) bit 0, IEc, which is the global interrupt enable flag.114* (IEc stands for interrupt-enable-current.)115*/116117/*118* gcc inline assembly to get at the status register.119*120* Pipeline hazards:121* - there must be at least one cycle between GET_STATUS122* and SET_STATUS;123* - it may take up to three cycles after SET_STATUS for the124* interrupt state to really change.125*126* These considerations do not (currently) apply to System/161,127* however.128*/129#define GET_STATUS(x) __asm volatile("mfc0 %0,$12" : "=r" (x))130#define SET_STATUS(x) __asm volatile("mtc0 %0,$12" :: "r" (x))131132/*133* Interrupts on.134*/135void136cpu_irqon(void)137{138uint32_t x;139140GET_STATUS(x);141x |= CST_IEc;142SET_STATUS(x);143}144145/*146* Interrupts off.147*/148void149cpu_irqoff(void)150{151uint32_t x;152153GET_STATUS(x);154x &= ~(uint32_t)CST_IEc;155SET_STATUS(x);156}157158/*159* Used below.160*/161static162void163cpu_irqonoff(void)164{165uint32_t x, xon, xoff;166167GET_STATUS(x);168xon = x | CST_IEc;169xoff = x & ~(uint32_t)CST_IEc;170SET_STATUS(xon);171__asm volatile("nop; nop; nop; nop");172SET_STATUS(xoff);173}174175////////////////////////////////////////////////////////////176177/*178* Idling.179*/180181/*182* gcc inline assembly for the WAIT instruction.183*184* mips r2k/r3k has no idle instruction at all.185*186* However, to avoid completely overloading the computing cluster, we187* appropriate the mips32 WAIT instruction.188*/189190static191inline192void193wait(void)194{195/*196* The WAIT instruction goes into powersave mode until an197* interrupt is trying to occur.198*199* Then switch interrupts on and off again, so we actually200* take the interrupt.201*202* Note that the precise behavior of this instruction in the203* System/161 simulator is partly guesswork. This code may not204* work on a real mips.205*/206__asm volatile(207".set push;" /* save assembler mode */208".set mips32;" /* allow MIPS32 instructions */209".set volatile;" /* avoid unwanted optimization */210"wait;" /* suspend until interrupted */211".set pop" /* restore assembler mode */212);213}214215/*216* Idle the processor until something happens.217*/218void219cpu_idle(void)220{221wait();222cpu_irqonoff();223}224225/*226* Halt the CPU permanently.227*/228void229cpu_halt(void)230{231cpu_irqoff();232while (1) {233wait();234}235}236237238