root/kern/arch/sys161/startup/start.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 #include <kern/mips/regdefs.h>
  31 #include <mips/specialreg.h>
  32 
  33    .set noreorder
  34 
  35    .text
  36    .globl __start
  37    .type __start,@function
  38    .ent __start
  39 __start:
  40 
  41    /*
  42     * Stack frame. We save the return address register, even though
  43     * it contains nothing useful. This is for gdb's benefit when it
  44     * comes disassembling. We also need 16 bytes for making a call,
  45     * and we have to align to an 8-byte (64-bit) boundary, so the
  46     * total frame size is 24.
  47     *
  48     * Note that the frame here must match the frame we set up below
  49     * when we switch off the bootup stack. Otherwise, gdb gets very
  50     * confused.
  51     */
  52    .frame sp, 24, $0    /* 24-byte sp-relative frame; return addr on stack */
  53    .mask 0x80000000, -4 /* register 31 (ra) saved at (sp+24)-4 */
  54    addiu sp, sp, -24
  55    sw ra, 20(sp)
  56    
  57    /*
  58     * The System/161 loader sets up a boot stack for the first
  59     * processor at the top of physical memory, and passes us a single
  60     * string argument. The string lives on the very top of the stack.
  61     * We get its address in a0.
  62     *
  63     * The kernel loads at virtual address 0x80000200, which is
  64     * physical address 0x00000200. The space immediately below this
  65     * is reserved for the exception vector code.
  66     *
  67     * The symbol _end is generated by the linker. It's the address of
  68     * the end of the kernel. It's not a variable; the *value* of the
  69     * _end symbol itself is this address. In C you'd use "&_end".
  70     *
  71     * We set up the memory map like this:
  72     *
  73     *         top of memory
  74     *                         free memory
  75     *         P + 0x1000
  76     *                         first thread's stack (1 page)
  77     *         P
  78     *                         wasted space (< 1 page)
  79     *                         copy of the boot string
  80     *         _end          
  81     *                         kernel
  82     *         0x80000200
  83     *                         exception handlers
  84     *         0x80000000
  85     *
  86     * where P is the next whole page after copying the argument string.
  87     */
  88 
  89    la s0, _end          /* stash _end in a saved register */
  90    
  91    move a1, a0          /* move bootstring to the second argument */
  92    move a0, s0          /* make _end the first argument */
  93    jal strcpy           /* call strcpy(_end, bootstring) */
  94    nop                  /* delay slot */
  95 
  96    move a0, s0          /* make _end the first argument again */
  97    jal strlen           /* call strlen(_end) */
  98    nop
  99 
 100    add t0, s0, v0       /* add in the length of the string */
 101    addi t0, t0, 1       /* and the null terminator */
 102    
 103    
 104    addi t0, t0, 4095    /* round up to next page boundary */
 105    li   t1, 0xfffff000
 106    and  t0, t0, t1
 107 
 108    addi t0, t0, 4096    /* add one page to hold the stack */
 109 
 110    move sp, t0          /* start the kernel stack for the first thread here */
 111 
 112    sw t0, firstfree     /* remember the first free page for later */
 113 
 114    /*
 115     * At this point, s0 contains the boot argument string, and no other
 116     * registers contain anything interesting (except the stack pointer).
 117     */
 118 
 119    /*
 120     * Now set up a stack frame on the real kernel stack: a dummy saved
 121     * return address and four argument slots for making function calls,
 122     * plus a wasted slot for alignment.
 123     *
 124     * (This needs to match the stack frame set up at the top of the
 125     * function, or the debugger gets confused.)
 126     */
 127    addiu sp, sp, -24
 128    sw $0, 20(sp)
 129 
 130    /*
 131     * Now, copy the exception handler code onto the first page of memory.
 132     */
 133 
 134    li a0, EXADDR_UTLB
 135    la a1, mips_utlb_handler
 136    la a2, mips_utlb_end
 137    sub a2, a2, a1
 138    jal memmove
 139    nop
 140 
 141    li a0, EXADDR_GENERAL
 142    la a1, mips_general_handler
 143    la a2, mips_general_end
 144    sub a2, a2, a1
 145    jal memmove
 146    nop
 147 
 148    /*
 149     * Flush the instruction cache to make sure the above changes show
 150     * through to instruction fetch.
 151     */
 152    jal mips_flushicache
 153    nop
 154 
 155    /*
 156     * Initialize the TLB.
 157     */
 158    jal tlb_reset
 159    nop
 160 
 161    /*
 162     * Load NULL into the register we use for curthread.
 163     */
 164    li s7, 0
 165 
 166    /*
 167     * Set up the status register.
 168     *
 169     * The MIPS has six hardware interrupt lines and two software interrupts.
 170     * These are individually maskable in the status register. However, we
 171     * don't use this feature (for simplicity) - we only use the master 
 172     * interrupt enable/disable flag in bit 0. So enable all of those bits
 173     * now and forget about them.
 174     *
 175     * The BEV bit in the status register, if set, causes the processor to
 176     * jump to a different set of hardwired exception handling addresses.
 177     * This is so that the kernel's exception handling code can be loaded
 178     * into RAM and that the boot ROM's exception handling code can be ROM.
 179     * This flag is normally set at boot time, and we need to be sure to
 180     * clear it.
 181     *
 182     * The KUo/IEo/KUp/IEp/KUc/IEc bits should all start at zero.
 183     *
 184     * We also want all the other random control bits (mostly for cache
 185     * stuff) set to zero.
 186     *
 187     * Thus, the actual value we write is CST_IRQMASK.
 188     */
 189    
 190    li  t0, CST_IRQMASK          /* get value */
 191    mtc0 t0, c0_status           /* set status register */
 192 
 193    /*
 194     * Load the CPU number into the PTBASE field of the CONTEXT
 195     * register. This is necessary to read from cpustacks[] and
 196     * cputhreads[] on trap entry from user mode. See further
 197     * discussions elsewhere.
 198     *
 199     * Because the boot CPU is CPU 0, we can just send 0.
 200     */
 201    mtc0 $0, c0_context
 202 
 203    /*
 204     * Load the GP register. This is a MIPS ABI feature; the GP
 205     * register points to an address in the middle of the data segment,
 206     * so data can be accessed relative to GP using one instruction
 207     * instead of the two it takes to set up a full 32-bit address.
 208     */
 209    la gp, _gp
 210    
 211    /*
 212     * We're all set up!
 213     * Fetch the copy of the bootstring as the argument, and call main.
 214     */
 215    jal kmain
 216    move a0, s0                  /* in delay slot */
 217 
 218 
 219    /*
 220     * kmain shouldn't return. panic.
 221     * Loop back just in case panic returns too.
 222     */
 223 1:
 224    la  a0, panicstr
 225    jal panic
 226    nop                          /* delay slot */
 227    j 1b
 228    nop                          /* delay slot */
 229    .end __start
 230 
 231    .rdata
 232 panicstr:
 233    .asciz "kmain returned\n"
 234 
 235    /*
 236     * CPUs started after the boot CPU come here.
 237     */
 238    .text
 239    .globl cpu_start_secondary
 240    .type cpu_start_secondary,@function
 241    .ent cpu_start_secondary
 242 cpu_start_secondary:
 243    
 244    /*
 245     * When we get here our stack points to the CRAM area of the bus
 246     * controller per-CPU space. This means we can, with a bit of
 247     * caution, call C functions, but nothing very deeply nesting.
 248     * However, we don't need to.
 249     *
 250     * The a0 register contains the value that was put in the second
 251     * word of the CRAM area, which is the (software) cpu number for
 252     * indexing cpustacks[]. None of the other registers contain
 253     * anything useful.
 254     */
 255 
 256 
 257    /*
 258     * Stack frame. We save the return address register, even though
 259     * it contains nothing useful. This is for gdb's benefit when it
 260     * comes disassembling. We also need 16 bytes for making a call,
 261     * and 4 bytes for alignment, so the total frame size is 24.
 262     *
 263     * Note that the frame here must match the frame we set up below
 264     * when we switch stacks. Otherwise, gdb gets very confused.
 265     */
 266    .frame sp, 24, $0    /* 24-byte sp-relative frame; return addr on stack */
 267    .mask 0x80000000, -4 /* register 31 (ra) saved at (sp+24)-4 */
 268    addiu sp, sp, -24
 269    sw ra, 20(sp)
 270 
 271    /*
 272     * Fetch the stack out of cpustacks[].
 273     */
 274    lui t0, %hi(cpustacks)       /* load upper half of cpustacks base addr */
 275    sll v0, a0, 2                /* get byte index for array (multiply by 4) */
 276    addu t0, t0, v0              /* add it in */
 277    lw sp, %lo(cpustacks)(t0)    /* get the stack pointer */
 278 
 279    /*
 280     * Now fetch curthread out of cputhreads[].
 281     */
 282    lui t0, %hi(cputhreads)      /* load upper half of cpustacks base addr */
 283    sll v0, a0, 2                /* get byte index for array (multiply by 4) */
 284    addu t0, t0, v0              /* add it in */
 285    lw s7, %lo(cputhreads)(t0)   /* load curthread register */
 286 
 287    /*
 288     * Initialize the TLB.
 289     */
 290    jal tlb_reset
 291    nop
 292 
 293    /*
 294     * Set up the status register, as described above.
 295     */
 296    li  t0, CST_IRQMASK          /* get value */
 297    mtc0 t0, c0_status           /* set status register */
 298    
 299    /*
 300     * Load the CPU number into the PTBASE field of the CONTEXT
 301     * register, as described above.
 302     */
 303    sll v0, a0, CTX_PTBASESHIFT
 304    mtc0 v0, c0_context
 305 
 306    /*
 307     * Initialize the on-chip timer interrupt.
 308     *
 309     * This should be set to CPU_FREQUENCY/HZ, but we don't have either
 310     * of those values here, so we'll arbitrarily set it to 100,000. It
 311     * will get reset to the right thing after it first fires.
 312     */
 313    li v0, 100000
 314    mtc0 v0, c0_compare
 315 
 316 
 317    /*
 318     * Load the GP register.
 319     */
 320    la gp, _gp
 321 
 322    /*
 323     * Set up a stack frame. Store zero into the return address slot so
 324     * we show as the top of the stack.
 325     */
 326    addiu sp, sp, -24
 327    sw z0, 20(sp)
 328 
 329    /*
 330     * Off to MI code. Pass the cpu number as the argument; it's already
 331     * in the a0 register.
 332     */
 333    j cpu_hatch
 334    nop                          /* delay slot for jump */
 335    .end cpu_start_secondary

/* [<][>][^][v][top][bottom][index][help] */