123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- /*
- * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
- * The President and Fellows of Harvard College.
- *
- * 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.
- * 3. 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 UNIVERSITY 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 UNIVERSITY 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.
- */
- #include <kern/mips/regdefs.h>
- #include <mips/specialreg.h>
- .set noreorder
- .text
- .globl __start
- .type __start,@function
- .ent __start
- __start:
- /*
- * Stack frame. We save the return address register, even though
- * it contains nothing useful. This is for gdb's benefit when it
- * comes disassembling. We also need 16 bytes for making a call,
- * and we have to align to an 8-byte (64-bit) boundary, so the
- * total frame size is 24.
- *
- * Note that the frame here must match the frame we set up below
- * when we switch off the bootup stack. Otherwise, gdb gets very
- * confused.
- */
- .frame sp, 24, $0 /* 24-byte sp-relative frame; return addr on stack */
- .mask 0x80000000, -4 /* register 31 (ra) saved at (sp+24)-4 */
- addiu sp, sp, -24
- sw ra, 20(sp)
-
- /*
- * The System/161 loader sets up a boot stack for the first
- * processor at the top of physical memory, and passes us a single
- * string argument. The string lives on the very top of the stack.
- * We get its address in a0.
- *
- * The kernel loads at virtual address 0x80000200, which is
- * physical address 0x00000200. The space immediately below this
- * is reserved for the exception vector code.
- *
- * The symbol _end is generated by the linker. It's the address of
- * the end of the kernel. It's not a variable; the *value* of the
- * _end symbol itself is this address. In C you'd use "&_end".
- *
- * We set up the memory map like this:
- *
- * top of memory
- * free memory
- * P + 0x1000
- * first thread's stack (1 page)
- * P
- * wasted space (< 1 page)
- * copy of the boot string
- * _end
- * kernel
- * 0x80000200
- * exception handlers
- * 0x80000000
- *
- * where P is the next whole page after copying the argument string.
- */
- la s0, _end /* stash _end in a saved register */
-
- move a1, a0 /* move bootstring to the second argument */
- move a0, s0 /* make _end the first argument */
- jal strcpy /* call strcpy(_end, bootstring) */
- nop /* delay slot */
- move a0, s0 /* make _end the first argument again */
- jal strlen /* call strlen(_end) */
- nop
- add t0, s0, v0 /* add in the length of the string */
- addi t0, t0, 1 /* and the null terminator */
-
-
- addi t0, t0, 4095 /* round up to next page boundary */
- li t1, 0xfffff000
- and t0, t0, t1
- addi t0, t0, 4096 /* add one page to hold the stack */
- move sp, t0 /* start the kernel stack for the first thread here */
- sw t0, firstfree /* remember the first free page for later */
- /*
- * At this point, s0 contains the boot argument string, and no other
- * registers contain anything interesting (except the stack pointer).
- */
- /*
- * Now set up a stack frame on the real kernel stack: a dummy saved
- * return address and four argument slots for making function calls,
- * plus a wasted slot for alignment.
- *
- * (This needs to match the stack frame set up at the top of the
- * function, or the debugger gets confused.)
- */
- addiu sp, sp, -24
- sw $0, 20(sp)
- /*
- * Now, copy the exception handler code onto the first page of memory.
- */
- li a0, EXADDR_UTLB
- la a1, mips_utlb_handler
- la a2, mips_utlb_end
- sub a2, a2, a1
- jal memmove
- nop
- li a0, EXADDR_GENERAL
- la a1, mips_general_handler
- la a2, mips_general_end
- sub a2, a2, a1
- jal memmove
- nop
- /*
- * Flush the instruction cache to make sure the above changes show
- * through to instruction fetch.
- */
- jal mips_flushicache
- nop
- /*
- * Initialize the TLB.
- */
- jal tlb_reset
- nop
- /*
- * Load NULL into the register we use for curthread.
- */
- li s7, 0
- /*
- * Set up the status register.
- *
- * The MIPS has six hardware interrupt lines and two software interrupts.
- * These are individually maskable in the status register. However, we
- * don't use this feature (for simplicity) - we only use the master
- * interrupt enable/disable flag in bit 0. So enable all of those bits
- * now and forget about them.
- *
- * The BEV bit in the status register, if set, causes the processor to
- * jump to a different set of hardwired exception handling addresses.
- * This is so that the kernel's exception handling code can be loaded
- * into RAM and that the boot ROM's exception handling code can be ROM.
- * This flag is normally set at boot time, and we need to be sure to
- * clear it.
- *
- * The KUo/IEo/KUp/IEp/KUc/IEc bits should all start at zero.
- *
- * We also want all the other random control bits (mostly for cache
- * stuff) set to zero.
- *
- * Thus, the actual value we write is CST_IRQMASK.
- */
-
- li t0, CST_IRQMASK /* get value */
- mtc0 t0, c0_status /* set status register */
- /*
- * Load the CPU number into the PTBASE field of the CONTEXT
- * register. This is necessary to read from cpustacks[] and
- * cputhreads[] on trap entry from user mode. See further
- * discussions elsewhere.
- *
- * Because the boot CPU is CPU 0, we can just send 0.
- */
- mtc0 $0, c0_context
- /*
- * Load the GP register. This is a MIPS ABI feature; the GP
- * register points to an address in the middle of the data segment,
- * so data can be accessed relative to GP using one instruction
- * instead of the two it takes to set up a full 32-bit address.
- */
- la gp, _gp
-
- /*
- * We're all set up!
- * Fetch the copy of the bootstring as the argument, and call main.
- */
- jal kmain
- move a0, s0 /* in delay slot */
- /*
- * kmain shouldn't return. panic.
- * Loop back just in case panic returns too.
- */
- 1:
- la a0, panicstr
- jal panic
- nop /* delay slot */
- j 1b
- nop /* delay slot */
- .end __start
- .rdata
- panicstr:
- .asciz "kmain returned\n"
- /*
- * CPUs started after the boot CPU come here.
- */
- .text
- .globl cpu_start_secondary
- .type cpu_start_secondary,@function
- .ent cpu_start_secondary
- cpu_start_secondary:
-
- /*
- * When we get here our stack points to the CRAM area of the bus
- * controller per-CPU space. This means we can, with a bit of
- * caution, call C functions, but nothing very deeply nesting.
- * However, we don't need to.
- *
- * The a0 register contains the value that was put in the second
- * word of the CRAM area, which is the (software) cpu number for
- * indexing cpustacks[]. None of the other registers contain
- * anything useful.
- */
- /*
- * Stack frame. We save the return address register, even though
- * it contains nothing useful. This is for gdb's benefit when it
- * comes disassembling. We also need 16 bytes for making a call,
- * and 4 bytes for alignment, so the total frame size is 24.
- *
- * Note that the frame here must match the frame we set up below
- * when we switch stacks. Otherwise, gdb gets very confused.
- */
- .frame sp, 24, $0 /* 24-byte sp-relative frame; return addr on stack */
- .mask 0x80000000, -4 /* register 31 (ra) saved at (sp+24)-4 */
- addiu sp, sp, -24
- sw ra, 20(sp)
- /*
- * Fetch the stack out of cpustacks[].
- */
- lui t0, %hi(cpustacks) /* load upper half of cpustacks base addr */
- sll v0, a0, 2 /* get byte index for array (multiply by 4) */
- addu t0, t0, v0 /* add it in */
- lw sp, %lo(cpustacks)(t0) /* get the stack pointer */
- /*
- * Now fetch curthread out of cputhreads[].
- */
- lui t0, %hi(cputhreads) /* load upper half of cpustacks base addr */
- sll v0, a0, 2 /* get byte index for array (multiply by 4) */
- addu t0, t0, v0 /* add it in */
- lw s7, %lo(cputhreads)(t0) /* load curthread register */
- /*
- * Initialize the TLB.
- */
- jal tlb_reset
- nop
- /*
- * Set up the status register, as described above.
- */
- li t0, CST_IRQMASK /* get value */
- mtc0 t0, c0_status /* set status register */
-
- /*
- * Load the CPU number into the PTBASE field of the CONTEXT
- * register, as described above.
- */
- sll v0, a0, CTX_PTBASESHIFT
- mtc0 v0, c0_context
- /*
- * Initialize the on-chip timer interrupt.
- *
- * This should be set to CPU_FREQUENCY/HZ, but we don't have either
- * of those values here, so we'll arbitrarily set it to 100,000. It
- * will get reset to the right thing after it first fires.
- */
- li v0, 100000
- mtc0 v0, c0_compare
- /*
- * Load the GP register.
- */
- la gp, _gp
- /*
- * Set up a stack frame. Store zero into the return address slot so
- * we show as the top of the stack.
- */
- addiu sp, sp, -24
- sw z0, 20(sp)
- /*
- * Off to MI code. Pass the cpu number as the argument; it's already
- * in the a0 register.
- */
- j cpu_hatch
- nop /* delay slot for jump */
- .end cpu_start_secondary
|