/** ** @file kernel.c ** ** @author CSCI-452 class of 20245 ** ** @brief Kernel support routines */ #define KERNEL_SRC #include <common.h> #include <cio.h> #include <clock.h> #include <kmem.h> #include <procs.h> #include <sio.h> #include <syscalls.h> #include <user.h> #include <userids.h> #include <vm.h> /* ** PRIVATE DEFINITIONS */ /* ** PRIVATE DATA TYPES */ /* ** PRIVATE GLOBAL VARIABLES */ /* ** PUBLIC GLOBAL VARIABLES */ // character buffers, usable throughout the OS // nto guaranteed to retain their contents across an exception return char b256[256]; // primarily used for message creation char b512[512]; // used by PANIC macro /* ** PRIVATE FUNCTIONS */ /* ** PRIVATE FUNCTIONS */ /** ** report - report the system configuration ** ** Prints configuration information about the OS on the console monitor. ** ** @param dtrace Decode the TRACE options */ static void kreport(bool_t dtrace) { cio_puts("\n-------------------------------\n"); cio_printf("Config: N_PROCS = %d", N_PROCS); cio_printf(" N_PRIOS = %d", N_PRIOS); cio_printf(" N_STATES = %d", N_STATES); cio_printf(" CLOCK = %dHz\n", CLOCK_FREQ); // This code is ugly, but it's the simplest way to // print out the values of compile-time options // without spending a lot of execution time at it. cio_puts("Options: " #ifdef RPT_INT_UNEXP " R-uint" #endif #ifdef RPT_INT_MYSTERY " R-mint" #endif #ifdef TRACE_CX " CX" #endif #ifdef CONSOLE_STATS " Cstats" #endif ); // end of cio_puts() call #ifdef SANITY cio_printf(" SANITY = %d", SANITY); #endif #ifdef STATUS cio_printf(" STATUS = %d", STATUS); #endif #if TRACE > 0 cio_printf(" TRACE = 0x%04x\n", TRACE); // decode the trace settings if that was requested if (TRACING_SOMETHING && dtrace) { // this one is simpler - we rely on string literal // concatenation in the C compiler to create one // long string to print out cio_puts("Tracing:" #if TRACING_PCB " PCB" #endif #if TRACING_VM " VM" #endif #if TRACING_QUEUE " QUE" #endif #if TRACING_SCHED " SCHED" #endif #if TRACING_DISPATCH " DISPATCH" #endif #if TRACING_SYSCALLS " SCALL" #endif #if TRACING_SYSRETS " SRET" #endif #if TRACING_EXIT " EXIT" #endif #if TRACING_INIT " INIT" #endif #if TRACING_KMEM " KM" #endif #if TRACING_KMEM_FREELIST " KMFL" #endif #if TRACING_KMEM_INIT " KMIN" #endif #if TRACING_FORK " FORK" #endif #if TRACING_EXEC " EXEC" #endif #if TRACING_SIO_STAT " S_STAT" #endif #if TRACING_SIO_ISR " S_ISR" #endif #if TRACING_SIO_RD " S_RD" #endif #if TRACING_SIO_WR " S_WR" #endif #if TRACING_USER " USER" #endif #if TRACING_ELF " ELF" #endif ); // end of cio_puts() call } #endif /* TRACE > 0 */ cio_puts("\n-------------------------------\n"); } #if defined(CONSOLE_STATS) /** ** stats - callback routine for console statistics ** ** Called by the CIO module when a key is pressed on the ** console keyboard. Depending on the key, it will print ** statistics on the console display, or will cause the ** user shell process to be dispatched. ** ** This code runs as part of the CIO ISR. */ static void stats(int code) { switch (code) { case 'a': // dump the active table ptable_dump("\nActive processes", false); break; case 'c': // dump context info for all active PCBs ctx_dump_all("\nContext dump"); break; case 'p': // dump the active table and all PCBs ptable_dump("\nActive processes", true); break; case 'q': // dump the queues // code to dump out any/all queues pcb_queue_dump("R", ready, true); pcb_queue_dump("W", waiting, true); pcb_queue_dump("S", sleeping, true); pcb_queue_dump("Z", zombie, true); pcb_queue_dump("I", sioread, true); break; case 'r': // print system configuration information report(true); break; // ignore CR and LF case '\r': // FALL THROUGH case '\n': break; default: cio_printf("console: unknown request '0x%02x'\n", code); // FALL THROUGH case 'h': // help message cio_puts("\nCommands:\n" " a -- dump the active table\n" " c -- dump contexts for active processes\n" " h -- this message\n" " p -- dump the active table and all PCBs\n" " q -- dump the queues\n" " r -- print system configuration\n"); break; } } #endif /* ** PUBLIC FUNCTIONS */ /** ** main - system initialization routine ** ** Called by the startup code immediately before returning into the ** first user process. ** ** Making this type 'int' keeps the compiler happy. */ int main(void) { /* ** BOILERPLATE CODE - taken from basic framework ** ** Initialize interrupt stuff. */ init_interrupts(); // IDT and PIC initialization /* ** Console I/O system. ** ** Does not depend on the other kernel modules, so we can ** initialize it before we initialize the kernel memory ** and queue modules. */ #if defined(CONSOLE_STATS) cio_init(stats); #else cio_init(NULL); // no console callback routine #endif cio_clearscreen(); // wipe out whatever is there /* ** TERM-SPECIFIC CODE STARTS HERE */ /* ** Initialize various OS modules ** ** Other modules (clock, SIO, syscall, etc.) are expected to ** install their own ISRs in their initialization routines. */ cio_puts("System initialization starting.\n"); cio_puts("-------------------------------\n"); cio_puts("Modules:"); // call the module initialization functions, being // careful to follow any module precedence requirements km_init(); // MUST BE FIRST #if TRACING_KMEM || TRACING_KMEM_FREE delay(DELAY_2_SEC); // approximately #endif // other module initialization calls here clk_init(); // clock pcb_init(); // process (PCBs, queues, scheduler) #if TRACING_PCB delay(DELAY_2_SEC); #endif sio_init(); // serial i/o sys_init(); // system call #if TRACING_SYSCALLS || TRACING_SYSRETS delay(DELAY_2_SEC); #endif vm_init(); // virtual memory user_init(); // user code handling cio_puts("\nModule initialization complete.\n"); cio_puts("-------------------------------\n"); // report our configuration options kreport(true); delay(DELAY_2_SEC); /* ** Other tasks typically performed here: ** ** Enabling any I/O devices (e.g., SIO xmit/rcv) */ /* ** Create the initial user process ** ** This code is largely stolen from the fork() and exec() ** implementations in syscalls.c; if those change, this must ** also change. */ // if we can't get a PCB, there's no use continuing! assert(pcb_alloc(&init_pcb) == SUCCESS); // fill in the necessary details init_pcb->pid = PID_INIT; init_pcb->state = STATE_NEW; init_pcb->priority = PRIO_HIGH; // find the 'init' program prog_t *prog = user_locate(Init); assert(prog != NULL); // command-line arguments for 'init' const char *args[2] = { "init", NULL }; // load it assert(user_load(prog, init_pcb, args, true) == SUCCESS); // send it on its merry way schedule(init_pcb); dispatch(); #ifdef TRACE_CX // if we're using a scrolling region, wait a bit more and then set it up delay(DELAY_7_SEC); // define a scrolling region in the top 7 lines of the screen cio_setscroll(0, 7, 99, 99); // clear it cio_clearscroll(); // clear the top line cio_puts_at( 0, 0, "* "); // separator cio_puts_at( 0, 6, "================================================================================"); #endif /* ** END OF TERM-SPECIFIC CODE ** ** Finally, report that we're all done. */ cio_puts("System initialization complete.\n"); cio_puts("-------------------------------\n"); sio_enable(SIO_RX); // produce a "system state" report cio_puts("System status: Queues "); pcb_queue_dump("R", ready, true); pcb_queue_dump("W", waiting, true); pcb_queue_dump("S", sleeping, true); pcb_queue_dump("Z", zombie, true); pcb_queue_dump("I", sioread, true); ptable_dump_counts(); pcb_dump("Current: ", current, true); delay(DELAY_3_SEC); vm_print(current->pdir, true, TwoLevel); delay(DELAY_3_SEC); return 0; }