Initial Spring 2016 commit.
This commit is contained in:
34
kern/arch/sys161/conf/conf.arch
Normal file
34
kern/arch/sys161/conf/conf.arch
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
#
|
||||
# Platform-dependent sources for System/161.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# locore
|
||||
#
|
||||
|
||||
# Cache handling for the kind of MIPS we have
|
||||
platform sys161 file arch/mips/locore/cache-mips161.S
|
||||
|
||||
# Exception handling (assembler entry points) for the kind of MIPS we have
|
||||
platform sys161 file arch/mips/locore/exception-mips1.S
|
||||
|
||||
#
|
||||
# VM
|
||||
#
|
||||
|
||||
# TLB handling for the kind of MIPS we have
|
||||
platform sys161 file arch/mips/vm/tlb-mips161.S
|
||||
|
||||
#
|
||||
# Devices. We have LAMEbus.
|
||||
#
|
||||
|
||||
platform sys161 file arch/sys161/dev/lamebus_machdep.c
|
||||
include dev/lamebus/conf.lamebus
|
||||
|
||||
#
|
||||
# Startup and initialization.
|
||||
#
|
||||
platform sys161 file arch/sys161/main/start.S
|
334
kern/arch/sys161/dev/lamebus_machdep.c
Normal file
334
kern/arch/sys161/dev/lamebus_machdep.c
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* 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 <types.h>
|
||||
#include <kern/unistd.h>
|
||||
#include <lib.h>
|
||||
#include <mips/specialreg.h>
|
||||
#include <mips/trapframe.h>
|
||||
#include <cpu.h>
|
||||
#include <spl.h>
|
||||
#include <clock.h>
|
||||
#include <thread.h>
|
||||
#include <current.h>
|
||||
#include <membar.h>
|
||||
#include <synch.h>
|
||||
#include <mainbus.h>
|
||||
#include <sys161/bus.h>
|
||||
#include <lamebus/lamebus.h>
|
||||
#include "autoconf.h"
|
||||
|
||||
/*
|
||||
* CPU frequency used by the on-chip timer.
|
||||
*
|
||||
* Note that we really ought to measure the CPU frequency against the
|
||||
* real-time clock instead of compiling it in like this.
|
||||
*/
|
||||
#define CPU_FREQUENCY 25000000 /* 25 MHz */
|
||||
|
||||
/*
|
||||
* Access to the on-chip timer.
|
||||
*
|
||||
* The c0_count register increments on every cycle; when the value
|
||||
* matches the c0_compare register, the timer interrupt line is
|
||||
* asserted. Writing to c0_compare again clears the interrupt.
|
||||
*/
|
||||
static
|
||||
void
|
||||
mips_timer_set(uint32_t count)
|
||||
{
|
||||
/*
|
||||
* $11 == c0_compare; we can't use the symbolic name inside
|
||||
* the asm string.
|
||||
*/
|
||||
__asm volatile(
|
||||
".set push;" /* save assembler mode */
|
||||
".set mips32;" /* allow MIPS32 registers */
|
||||
"mtc0 %0, $11;" /* do it */
|
||||
".set pop" /* restore assembler mode */
|
||||
:: "r" (count));
|
||||
}
|
||||
|
||||
/*
|
||||
* LAMEbus data for the system. (We have only one LAMEbus per system.)
|
||||
* This does not need to be locked, because it's constant once
|
||||
* initialized, and initialized before we start other threads or CPUs.
|
||||
*/
|
||||
static struct lamebus_softc *lamebus;
|
||||
|
||||
void
|
||||
mainbus_bootstrap(void)
|
||||
{
|
||||
/* Interrupts should be off (and have been off since startup) */
|
||||
KASSERT(curthread->t_curspl > 0);
|
||||
|
||||
/* Initialize the system LAMEbus data */
|
||||
lamebus = lamebus_init();
|
||||
|
||||
/* Probe CPUs (should these be done as device attachments instead?) */
|
||||
lamebus_find_cpus(lamebus);
|
||||
|
||||
/*
|
||||
* Print the device name for the main bus.
|
||||
*/
|
||||
kprintf("lamebus0 (system main bus)\n");
|
||||
|
||||
/*
|
||||
* Now we can take interrupts without croaking, so turn them on.
|
||||
* Some device probes might require being able to get interrupts.
|
||||
*/
|
||||
|
||||
spl0();
|
||||
|
||||
/*
|
||||
* Now probe all the devices attached to the bus.
|
||||
* (This amounts to all devices.)
|
||||
*/
|
||||
autoconf_lamebus(lamebus, 0);
|
||||
|
||||
/*
|
||||
* Configure the MIPS on-chip timer to interrupt HZ times a second.
|
||||
*/
|
||||
mips_timer_set(CPU_FREQUENCY / HZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start all secondary CPUs.
|
||||
*/
|
||||
void
|
||||
mainbus_start_cpus(void)
|
||||
{
|
||||
lamebus_start_cpus(lamebus);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to generate the memory address (in the uncached segment)
|
||||
* for the specified offset into the specified slot's region of the
|
||||
* LAMEbus.
|
||||
*/
|
||||
void *
|
||||
lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset)
|
||||
{
|
||||
uint32_t address;
|
||||
|
||||
(void)bus; // not needed
|
||||
|
||||
KASSERT(slot >= 0 && slot < LB_NSLOTS);
|
||||
|
||||
address = LB_BASEADDR + slot*LB_SLOT_SIZE + offset;
|
||||
return (void *)address;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a 32-bit register from a LAMEbus device.
|
||||
*/
|
||||
uint32_t
|
||||
lamebus_read_register(struct lamebus_softc *bus, int slot, uint32_t offset)
|
||||
{
|
||||
uint32_t *ptr;
|
||||
|
||||
ptr = lamebus_map_area(bus, slot, offset);
|
||||
|
||||
/*
|
||||
* Make sure the load happens after anything the device has
|
||||
* been doing.
|
||||
*/
|
||||
membar_load_load();
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a 32-bit register of a LAMEbus device.
|
||||
*/
|
||||
void
|
||||
lamebus_write_register(struct lamebus_softc *bus, int slot,
|
||||
uint32_t offset, uint32_t val)
|
||||
{
|
||||
uint32_t *ptr;
|
||||
|
||||
ptr = lamebus_map_area(bus, slot, offset);
|
||||
*ptr = val;
|
||||
|
||||
/*
|
||||
* Make sure the store happens before we do anything else to
|
||||
* the device.
|
||||
*/
|
||||
membar_store_store();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Power off the system.
|
||||
*/
|
||||
void
|
||||
mainbus_poweroff(void)
|
||||
{
|
||||
/*
|
||||
*
|
||||
* Note that lamebus_write_register() doesn't actually access
|
||||
* the bus argument, so this will still work if we get here
|
||||
* before the bus is initialized.
|
||||
*/
|
||||
lamebus_poweroff(lamebus);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reboot the system.
|
||||
*/
|
||||
void
|
||||
mainbus_reboot(void)
|
||||
{
|
||||
/*
|
||||
* The MIPS doesn't appear to have any on-chip reset.
|
||||
* LAMEbus doesn't have a reset control, so we just
|
||||
* power off instead of rebooting. This would not be
|
||||
* so great in a real system, but it's fine for what
|
||||
* we're doing.
|
||||
*/
|
||||
kprintf("Cannot reboot - powering off instead, sorry.\n");
|
||||
mainbus_poweroff();
|
||||
}
|
||||
|
||||
/*
|
||||
* Halt the system.
|
||||
* On some systems, this would return to the boot monitor. But we don't
|
||||
* have one.
|
||||
*/
|
||||
void
|
||||
mainbus_halt(void)
|
||||
{
|
||||
cpu_halt();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to reset the system from panic().
|
||||
*
|
||||
* By the time we get here, the system may well be sufficiently hosed
|
||||
* as to panic recursively if we do much of anything. So just power off.
|
||||
* (We'd reboot, but System/161 doesn't do that.)
|
||||
*/
|
||||
void
|
||||
mainbus_panic(void)
|
||||
{
|
||||
mainbus_poweroff();
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to get the size of installed physical RAM from the LAMEbus
|
||||
* controller.
|
||||
*/
|
||||
uint32_t
|
||||
mainbus_ramsize(void)
|
||||
{
|
||||
uint32_t ramsize;
|
||||
|
||||
ramsize = lamebus_ramsize();
|
||||
|
||||
/*
|
||||
* This is the same as the last physical address, as long as
|
||||
* we have less than 508 megabytes of memory. The LAMEbus I/O
|
||||
* area occupies the space between 508 megabytes and 512
|
||||
* megabytes, so if we had more RAM than this it would have to
|
||||
* be discontiguous. This is not a case we are going to worry
|
||||
* about.
|
||||
*/
|
||||
if (ramsize > 508*1024*1024) {
|
||||
ramsize = 508*1024*1024;
|
||||
}
|
||||
|
||||
return ramsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send IPI.
|
||||
*/
|
||||
void
|
||||
mainbus_send_ipi(struct cpu *target)
|
||||
{
|
||||
lamebus_assert_ipi(lamebus, target);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt dispatcher.
|
||||
*/
|
||||
|
||||
/* Wiring of LAMEbus interrupts to bits in the cause register */
|
||||
#define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */
|
||||
#define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */
|
||||
#define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */
|
||||
|
||||
void
|
||||
mainbus_interrupt(struct trapframe *tf)
|
||||
{
|
||||
uint32_t cause;
|
||||
bool seen = false;
|
||||
|
||||
/* interrupts should be off */
|
||||
KASSERT(curthread->t_curspl > 0);
|
||||
|
||||
cause = tf->tf_cause;
|
||||
if (cause & LAMEBUS_IRQ_BIT) {
|
||||
lamebus_interrupt(lamebus);
|
||||
seen = true;
|
||||
}
|
||||
if (cause & LAMEBUS_IPI_BIT) {
|
||||
interprocessor_interrupt();
|
||||
lamebus_clear_ipi(lamebus, curcpu);
|
||||
seen = true;
|
||||
}
|
||||
if (cause & MIPS_TIMER_BIT) {
|
||||
/* Reset the timer (this clears the interrupt) */
|
||||
mips_timer_set(CPU_FREQUENCY / HZ);
|
||||
/* and call hardclock */
|
||||
hardclock();
|
||||
seen = true;
|
||||
}
|
||||
|
||||
if (!seen) {
|
||||
if ((cause & CCA_IRQS) == 0) {
|
||||
/*
|
||||
* Don't panic here; this can happen if an
|
||||
* interrupt line asserts (very) briefly and
|
||||
* turns off again before we get as far as
|
||||
* reading the cause register. This was
|
||||
* actually seen... once.
|
||||
*/
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* But if we get an interrupt on an interrupt
|
||||
* line that's not supposed to be wired up,
|
||||
* complain.
|
||||
*/
|
||||
panic("Unknown interrupt; cause register is %08x\n",
|
||||
cause);
|
||||
}
|
||||
}
|
||||
}
|
60
kern/arch/sys161/include/bus.h
Normal file
60
kern/arch/sys161/include/bus.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS161_BUS_H_
|
||||
#define _SYS161_BUS_H_
|
||||
|
||||
/*
|
||||
* Generic bus interface file.
|
||||
*
|
||||
* The only bus on System/161 is LAMEbus.
|
||||
* This would need to be a bit more complicated if that weren't the case.
|
||||
*/
|
||||
|
||||
#include <machine/vm.h> /* for MIPS_KSEG1 */
|
||||
#include <lamebus/lamebus.h> /* for LAMEbus definitions */
|
||||
|
||||
#define bus_write_register(bus, slot, offset, val) \
|
||||
lamebus_write_register(bus, slot, offset, val)
|
||||
|
||||
#define bus_read_register(bus, slot, offset) \
|
||||
lamebus_read_register(bus, slot, offset)
|
||||
|
||||
#define bus_map_area(bus, slot, offset) \
|
||||
lamebus_map_area(bus, slot, offset)
|
||||
|
||||
/*
|
||||
* Machine-dependent LAMEbus definitions
|
||||
*/
|
||||
|
||||
/* Base address of the LAMEbus mapping area */
|
||||
#define LB_BASEADDR (MIPS_KSEG1 + 0x1fe00000)
|
||||
|
||||
|
||||
#endif /* _SYS161_BUS_H_ */
|
44
kern/arch/sys161/include/maxcpus.h
Normal file
44
kern/arch/sys161/include/maxcpus.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS161_MAXCPUS_H_
|
||||
#define _SYS161_MAXCPUS_H_
|
||||
|
||||
/*
|
||||
* For various reasons (see mips/cpu.c) it's desirable to have a
|
||||
* fixed-size per-cpu array in the data segment. This is
|
||||
* platform-dependent rather than processor-dependent because there's
|
||||
* nothing about the processor that determines how many CPUs can
|
||||
* exist; however, any real platform has *some* limit. For System/161,
|
||||
* the limit is 32.
|
||||
*/
|
||||
|
||||
#define MAXCPUS 32
|
||||
|
||||
#endif /* _SYS161_MAXCPUS_H_ */
|
335
kern/arch/sys161/main/start.S
Normal file
335
kern/arch/sys161/main/start.S
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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
|
Reference in New Issue
Block a user