00001 /* 00002 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 00003 * The President and Fellows of Harvard College. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the University nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 */ 00029 00030 /* 00031 * CPU control functions. 00032 */ 00033 00034 #include <types.h> 00035 #include <lib.h> 00036 #include <mips/specialreg.h> 00037 #include <mips/trapframe.h> 00038 #include <platform/maxcpus.h> 00039 #include <cpu.h> 00040 #include <thread.h> 00041 00042 //////////////////////////////////////////////////////////// 00043 00044 /* 00045 * Startup and exception-time stack hook. 00046 * 00047 * The MIPS lacks a good way to find the current CPU, current thread, 00048 * or current thread stack upon trap entry from user mode. To deal 00049 * with this, we store the CPU number (our number, not the hardware 00050 * number) in a nonessential field in the MMU, which is about the only 00051 * place possible, and then use that to index cpustacks[]. This gets 00052 * us the value to load as the stack pointer. We can then also load 00053 * curthread from cputhreads[] by parallel indexing. 00054 * 00055 * These arrays are also used to start up new CPUs, for roughly the 00056 * same reasons. 00057 */ 00058 00059 vaddr_t cpustacks[MAXCPUS]; 00060 vaddr_t cputhreads[MAXCPUS]; 00061 00062 /* 00063 * Do machine-dependent initialization of the cpu structure or things 00064 * associated with a new cpu. Note that we're not running on the new 00065 * cpu when this is called. 00066 */ 00067 void 00068 cpu_machdep_init(struct cpu *c) 00069 { 00070 vaddr_t stackpointer; 00071 00072 KASSERT(c->c_number < MAXCPUS); 00073 00074 if (c->c_curthread->t_stack == NULL) { 00075 /* boot cpu; don't need to do anything here */ 00076 } 00077 else { 00078 /* 00079 * Stick the stack in cpustacks[], and thread pointer 00080 * in cputhreads[]. 00081 */ 00082 00083 /* stack base address */ 00084 stackpointer = (vaddr_t) c->c_curthread->t_stack; 00085 /* since stacks grow down, get the top */ 00086 stackpointer += STACK_SIZE; 00087 00088 cpustacks[c->c_number] = stackpointer; 00089 cputhreads[c->c_number] = (vaddr_t)c->c_curthread; 00090 } 00091 } 00092 00093 //////////////////////////////////////////////////////////// 00094 00095 /* 00096 * Return the type name of the currently running CPU. 00097 */ 00098 00099 const char * 00100 cpu_identify(void) 00101 { 00102 /* XXX Ought to be more sophisticated. */ 00103 return "MIPS r3000"; 00104 } 00105 00106 //////////////////////////////////////////////////////////// 00107 00108 /* 00109 * Interrupt control. 00110 * 00111 * While the mips actually has on-chip interrupt priority masking, in 00112 * the interests of simplicity, we don't use it. Instead we use 00113 * coprocessor 0 register 12 (the system coprocessor "status" 00114 * register) bit 0, IEc, which is the global interrupt enable flag. 00115 * (IEc stands for interrupt-enable-current.) 00116 */ 00117 00118 /* 00119 * gcc inline assembly to get at the status register. 00120 * 00121 * Pipeline hazards: 00122 * - there must be at least one cycle between GET_STATUS 00123 * and SET_STATUS; 00124 * - it may take up to three cycles after SET_STATUS for the 00125 * interrupt state to really change. 00126 * 00127 * These considerations do not (currently) apply to System/161, 00128 * however. 00129 */ 00130 #define GET_STATUS(x) __asm volatile("mfc0 %0,$12" : "=r" (x)) 00131 #define SET_STATUS(x) __asm volatile("mtc0 %0,$12" :: "r" (x)) 00132 00133 /* 00134 * Interrupts on. 00135 */ 00136 void 00137 cpu_irqon(void) 00138 { 00139 uint32_t x; 00140 00141 GET_STATUS(x); 00142 x |= CST_IEc; 00143 SET_STATUS(x); 00144 } 00145 00146 /* 00147 * Interrupts off. 00148 */ 00149 void 00150 cpu_irqoff(void) 00151 { 00152 uint32_t x; 00153 00154 GET_STATUS(x); 00155 x &= ~(uint32_t)CST_IEc; 00156 SET_STATUS(x); 00157 } 00158 00159 /* 00160 * Used below. 00161 */ 00162 static 00163 void 00164 cpu_irqonoff(void) 00165 { 00166 uint32_t x, xon, xoff; 00167 00168 GET_STATUS(x); 00169 xon = x | CST_IEc; 00170 xoff = x & ~(uint32_t)CST_IEc; 00171 SET_STATUS(xon); 00172 __asm volatile("nop; nop; nop; nop"); 00173 SET_STATUS(xoff); 00174 } 00175 00176 //////////////////////////////////////////////////////////// 00177 00178 /* 00179 * Idling. 00180 */ 00181 00182 /* 00183 * gcc inline assembly for the WAIT instruction. 00184 * 00185 * mips r2k/r3k has no idle instruction at all. 00186 * 00187 * However, to avoid completely overloading the computing cluster, we 00188 * appropriate the mips32 WAIT instruction. 00189 */ 00190 00191 static 00192 inline 00193 void 00194 wait(void) 00195 { 00196 /* 00197 * The WAIT instruction goes into powersave mode until an 00198 * interrupt is trying to occur. 00199 * 00200 * Then switch interrupts on and off again, so we actually 00201 * take the interrupt. 00202 * 00203 * Note that the precise behavior of this instruction in the 00204 * System/161 simulator is partly guesswork. This code may not 00205 * work on a real mips. 00206 */ 00207 __asm volatile( 00208 ".set push;" /* save assembler mode */ 00209 ".set mips32;" /* allow MIPS32 instructions */ 00210 ".set volatile;" /* avoid unwanted optimization */ 00211 "wait;" /* suspend until interrupted */ 00212 ".set pop" /* restore assembler mode */ 00213 ); 00214 } 00215 00216 /* 00217 * Idle the processor until something happens. 00218 */ 00219 void 00220 cpu_idle(void) 00221 { 00222 wait(); 00223 cpu_irqonoff(); 00224 } 00225 00226 /* 00227 * Halt the CPU permanently. 00228 */ 00229 void 00230 cpu_halt(void) 00231 { 00232 cpu_irqoff(); 00233 while (1) { 00234 wait(); 00235 } 00236 }