169 lines
3.7 KiB
C
169 lines
3.7 KiB
C
/* See COPYRIGHT for copyright information. */
|
|
|
|
#include <inc/stdio.h>
|
|
#include <inc/string.h>
|
|
#include <inc/assert.h>
|
|
|
|
#include <kern/monitor.h>
|
|
#include <kern/console.h>
|
|
#include <kern/pmap.h>
|
|
#include <kern/kclock.h>
|
|
#include <kern/env.h>
|
|
#include <kern/trap.h>
|
|
#include <kern/sched.h>
|
|
#include <kern/picirq.h>
|
|
#include <kern/cpu.h>
|
|
#include <kern/spinlock.h>
|
|
|
|
static void boot_aps(void);
|
|
|
|
|
|
void
|
|
i386_init(void)
|
|
{
|
|
// Initialize the console.
|
|
// Can't call cprintf until after we do this!
|
|
cons_init();
|
|
|
|
cprintf("444544 decimal is %o octal!\n", 444544);
|
|
|
|
// Lab 2 memory management initialization functions
|
|
mem_init();
|
|
|
|
// Lab 3 user environment initialization functions
|
|
env_init();
|
|
trap_init();
|
|
|
|
// Lab 4 multiprocessor initialization functions
|
|
mp_init();
|
|
lapic_init();
|
|
|
|
// Lab 4 multitasking initialization functions
|
|
pic_init();
|
|
|
|
// Acquire the big kernel lock before waking up APs
|
|
// Your code here:
|
|
|
|
// Starting non-boot CPUs
|
|
boot_aps();
|
|
|
|
// Start fs.
|
|
ENV_CREATE(fs_fs, ENV_TYPE_FS);
|
|
|
|
#if defined(TEST)
|
|
// Don't touch -- used by grading script!
|
|
ENV_CREATE(TEST, ENV_TYPE_USER);
|
|
#else
|
|
// Touch all you want.
|
|
ENV_CREATE(user_icode, ENV_TYPE_USER);
|
|
#endif // TEST*
|
|
|
|
// Should not be necessary - drains keyboard because interrupt has given up.
|
|
kbd_intr();
|
|
|
|
// Schedule and run the first user environment!
|
|
sched_yield();
|
|
}
|
|
|
|
// While boot_aps is booting a given CPU, it communicates the per-core
|
|
// stack pointer that should be loaded by mpentry.S to that CPU in
|
|
// this variable.
|
|
void *mpentry_kstack;
|
|
|
|
// Start the non-boot (AP) processors.
|
|
static void
|
|
boot_aps(void)
|
|
{
|
|
extern unsigned char mpentry_start[], mpentry_end[];
|
|
void *code;
|
|
struct CpuInfo *c;
|
|
|
|
// Write entry code to unused memory at MPENTRY_PADDR
|
|
code = KADDR(MPENTRY_PADDR);
|
|
memmove(code, mpentry_start, mpentry_end - mpentry_start);
|
|
|
|
// Boot each AP one at a time
|
|
for (c = cpus; c < cpus + ncpu; c++) {
|
|
if (c == cpus + cpunum()) // We've started already.
|
|
continue;
|
|
|
|
// Tell mpentry.S what stack to use
|
|
mpentry_kstack = percpu_kstacks[c - cpus] + KSTKSIZE;
|
|
// Start the CPU at mpentry_start
|
|
lapic_startap(c->cpu_id, PADDR(code));
|
|
// Wait for the CPU to finish some basic setup in mp_main()
|
|
while(c->cpu_status != CPU_STARTED)
|
|
;
|
|
}
|
|
}
|
|
|
|
// Setup code for APs
|
|
void
|
|
mp_main(void)
|
|
{
|
|
// We are in high EIP now, safe to switch to kern_pgdir
|
|
lcr3(PADDR(kern_pgdir));
|
|
cprintf("SMP: CPU %d starting\n", cpunum());
|
|
|
|
lapic_init();
|
|
env_init_percpu();
|
|
trap_init_percpu();
|
|
xchg(&thiscpu->cpu_status, CPU_STARTED); // tell boot_aps() we're up
|
|
|
|
// Now that we have finished some basic setup, call sched_yield()
|
|
// to start running processes on this CPU. But make sure that
|
|
// only one CPU can enter the scheduler at a time!
|
|
//
|
|
// Your code here:
|
|
|
|
// Remove this after you finish Exercise 6
|
|
for (;;);
|
|
}
|
|
|
|
/*
|
|
* Variable panicstr contains argument to first call to panic; used as flag
|
|
* to indicate that the kernel has already called panic.
|
|
*/
|
|
const char *panicstr;
|
|
|
|
/*
|
|
* Panic is called on unresolvable fatal errors.
|
|
* It prints "panic: mesg", and then enters the kernel monitor.
|
|
*/
|
|
void
|
|
_panic(const char *file, int line, const char *fmt,...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (panicstr)
|
|
goto dead;
|
|
panicstr = fmt;
|
|
|
|
// Be extra sure that the machine is in as reasonable state
|
|
asm volatile("cli; cld");
|
|
|
|
va_start(ap, fmt);
|
|
cprintf("kernel panic on CPU %d at %s:%d: ", cpunum(), file, line);
|
|
vcprintf(fmt, ap);
|
|
cprintf("\n");
|
|
va_end(ap);
|
|
|
|
dead:
|
|
/* break into the kernel monitor */
|
|
while (1)
|
|
monitor(NULL);
|
|
}
|
|
|
|
/* like panic, but don't */
|
|
void
|
|
_warn(const char *file, int line, const char *fmt,...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
cprintf("kernel warning at %s:%d: ", file, line);
|
|
vcprintf(fmt, ap);
|
|
cprintf("\n");
|
|
va_end(ap);
|
|
}
|