/* See COPYRIGHT for copyright information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void boot_aps(void); void sysenter_handler(); 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); cprintf("\33[31m" "C" "\33[33m" "o" "\33[32m" "l" "\33[36m" "o" "\33[34m" "r" "\33[0m" " Works!" "\n"); write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) sysenter_handler, 0); write_msr(MSR_IA32_SYSENTER_ESP, KSTACKTOP, 0); write_msr(MSR_IA32_SYSENTER_CS, GD_KT, 0); // 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: lock_kernel(); // Starting non-boot CPUs boot_aps(); #if defined(TEST) // Don't touch -- used by grading script! ENV_CREATE(TEST, ENV_TYPE_USER); #else // Touch all you want. ENV_CREATE(user_yield, ENV_TYPE_USER); ENV_CREATE(user_yield, ENV_TYPE_USER); ENV_CREATE(user_yield, ENV_TYPE_USER); ENV_CREATE(user_yield, ENV_TYPE_USER); #endif // TEST* // 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: lock_kernel(); sched_yield(); // 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); }