os161-1.99
 All Data Structures
cpu.c
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 }
 All Data Structures