jsos

college code for operating system fundamentals in js

git clone https://9o.is/git/jsos.git

kernel.js

(8033B)


      1 /* ------------
      2    Kernel.js
      3    
      4    Requires globals.js
      5    
      6    Routines for the Operataing System, NOT the host.
      7    
      8    This code references page numbers in the text book: 
      9    Operating System Concepts 8th editiion by Silberschatz, Galvin, and Gagne.  ISBN 978-0-470-12872-5   
     10    ------------ */
     11 
     12 
     13 //
     14 // OS Startup and Shutdown Routines   
     15 //
     16 function krnBootstrap()      // Page 8.
     17 {
     18     simLog("bootstrap", "host");  // Use simLog because we ALWAYS want this, even if _Trace is off.
     19 
     20     // Initialize the Console.
     21     _Console = new Console();             // The console output device.
     22     _Console.init();
     23 
     24     // Initialize our global queues.
     25     _KernelInterruptQueue = new Queue();  // A (currently) non-priority queue for interrupt requests (IRQs).
     26     _KernelBuffers = new Array();         // Buffers... for the kernel.
     27     _KernelInputQueue = new Queue();      // Where device input lands before being processed out somewhere.
     28     _KernelMemoryManager = new MemoryManager();
     29     _KernelReadyQueue = PriorityQueue({low: true});   // the ready queue for waiting processes to execute.
     30     _KernelCPUScheduler = new scheduler();
     31     
     32     // Initialize standard input and output to the _Console.
     33     _StdIn  = _Console;
     34     _StdOut = _Console;
     35 
     36     // Load the Keyboard Device Driver
     37     krnTrace("Loading the keyboard device driver.");
     38     krnKeyboardDriver = new DeviceDriverKeyboard();     // Construct it.
     39     krnKeyboardDriver.driverEntry();                    // Call the driverEntry() initialization routine.
     40     krnTrace(krnKeyboardDriver.status);
     41 
     42     // Load the Filesystem Device Driver
     43     krnTrace("Loading the filesystem device driver.");
     44     krnFilesystemDriver = new DeviceDriverFilesystem();
     45     krnFilesystemDriver.driverEntry();
     46     krnTrace(krnFilesystemDriver.status);
     47 
     48     // 
     49     // ... more?
     50     //
     51 
     52     // Enable the OS Interrupts.  (Not the CPU clock interrupt, as that is done in the hardware sim.)
     53     krnTrace("Enabling the interrupts.");
     54     krnEnableInterrupts();
     55     // Launch the shell.
     56     krnTrace("Creating and Launching the shell.")
     57     _OsShell = new Shell();
     58     _OsShell.init();
     59 }
     60 
     61 function krnShutdown()
     62 {
     63     krnTrace("begin shutdown OS");
     64     // TODO: Check for running processes.  Alert if there are some, alert and stop.  Else...    
     65     // ... Disable the Interruupts.
     66     krnTrace("Disabling the interrupts.");
     67     krnDisableInterrupts();
     68     // 
     69     // Unload the Device Drivers?
     70     // More?
     71     //
     72     krnTrace("end shutdown OS");
     73 }
     74 
     75 
     76 function krnOnCPUClockPulse() 
     77 {
     78     _Console.taskbarRefresh(); 
     79     /* This gets called from the host hardware every time there is a hardware clock pulse. 
     80        This is NOT the same as a TIMER, which causes an interrupt and is handled like other interrupts.
     81        This, on the other hand, is the clock pulse from the hardware (or host) that tells the kernel 
     82        that it has to look for interrupts and process them if it finds any.                           */
     83 
     84     // Check for an interrupt, are any. Page 560
     85     if (_KernelInterruptQueue.getSize() > 0)    
     86     {
     87         // Process the first interrupt on the interrupt queue.
     88         // TODO: Implement a priority queye based on the IRQ number/id to enforce interrupt priority.
     89         var interrput = _KernelInterruptQueue.dequeue();
     90         krnInterruptHandler(interrput.irq, interrput.params);        
     91     }
     92     // If there are no interrupts then run a CPU cycle if there is anything scheduled.
     93     else if (_KernelCPUScheduler.ready()) 
     94     {
     95         MODE = 1;
     96         _KernelCPUScheduler.run();
     97         MODE = 0;
     98     }    
     99     else                       // If there are no interrupts and there is nothing being executed then just be idle.
    100     {
    101        krnTrace("Idle");
    102     }
    103 }
    104 
    105 
    106 // 
    107 // Interrupt Handling
    108 // 
    109 function krnEnableInterrupts()
    110 {
    111     // Keyboard
    112     simEnableKeyboardInterrupt();
    113     // Put more here.
    114 }
    115 
    116 function krnDisableInterrupts()
    117 {
    118     // Keyboard
    119     simDisableKeyboardInterrupt();
    120     // Put more here.
    121 }
    122 
    123 // Queue an interrupt
    124 function krnInterrupt(irq, params) {
    125     _KernelInterruptQueue.enqueue(new Interrupt(irq, params));
    126 }
    127 
    128 function krnInterruptHandler(irq, params)    // This is the Interrupt Handler Routine.  Page 8.
    129 {
    130     // Trace our entrance here so we can compute Interrupt Latency by analyzing the log file later on.  Page 766.
    131     krnTrace("Handling IRQ~" + irq);
    132 
    133     // Save CPU state. (I think we do this elsewhere.)
    134 
    135     // Invoke the requested Interrupt Service Routine via Switch/Case rather than an Interrupt Vector.
    136     // TODO: Use Interrupt Vector in the future.
    137     // Note: There is no need to "dismiss" or acknowledge the interrupts in our design here.  
    138     //       Maybe the hardware simulation will grow to support/require that in the future.
    139     switch (irq)
    140     {
    141         case TIMER_IRQ: 
    142             krnTimerISR();                   // Kernel built-in routine for timers (not the clock).
    143             break;
    144         case KEYBOARD_IRQ: 
    145             krnKeyboardDriver.isr(params);   // Kernel mode device driver
    146             _StdIn.handleInput();
    147             break;
    148         case SYSCALL_IRQ:                    // System Call interrupt
    149             krnSystemCall(params);
    150             break;
    151         default: 
    152             krnTrapError("Invalid Interrupt Request. irq=" + irq + " params=[" + params + "]");
    153     }
    154 
    155     // 3. Restore the saved state.  TODO: Question: Should we restore the state via IRET in the ISR instead of here? p560.
    156 }
    157 
    158 function krnTimerISR()  // The built-in TIMER (not clock) Interrupt Service Routine (as opposed to an ISR coming from a device driver).
    159 {
    160     // Check multiprogramming parameters and enfore quanta here. Call the scheduler / context switch here if necessary.
    161 }   
    162 
    163 //
    164 // System Calls... that generate software interrupts via tha Application Programming Interface library routines.
    165 //
    166 // Some ideas:
    167 // - ReadConsole
    168 // - WriteConsole
    169 // - CreateProcess
    170 // - ExitProcess
    171 // - WaitForProcessToExit
    172 // - CreateFile
    173 // - OpenFile
    174 // - ReadFile
    175 // - WriteFile
    176 // - CloseFile
    177 function krnSystemCall(operator) {
    178 
    179   switch(operator) {
    180 
    181     // a process has been terminated
    182     case 0x00: 
    183       krnTrace("Process "+_KernelCPUScheduler.running.pid+
    184           " terminated successfully.");
    185       _KernelCPUScheduler.
    186           running.setState(PCB_STATE_TERMINATED);
    187       _KernelCPUScheduler.completedProcesses++;
    188       break;
    189 
    190     // normal system call
    191     case 0xFF: 
    192       if(_CPU.X == 1)
    193         _StdOut.putText(_CPU.Y.toString()); 
    194 
    195       // print the 00-terminated string stored at 
    196       // the address in the Y register.
    197       else if(_CPU.X == 2) {
    198         var ascii = hex2ASCII(_Memory.getByte(_CPU.Y + _KernelCPUScheduler.running.base));
    199         do {
    200           _StdOut.putText(ascii);
    201           ascii = hex2ASCII(_Memory.getByte(++_CPU.Y + _KernelCPUScheduler.running.base));
    202         } while (ascii != null)
    203       }
    204       break;
    205 
    206     // Context Switch
    207     case 0xFFFF:
    208       MODE = 1;
    209       var old = _KernelCPUScheduler.running;
    210       krnTrace("Removing PID "+old.PID+" by context switch.");
    211       old.setState(PCB_STATE_READY);
    212       _KernelReadyQueue.push(old, old.priority);
    213       _KernelCPUScheduler.running = undefined;
    214       MODE = 0;
    215       break;
    216 
    217     // Invalid system call
    218     default: 
    219       krnTrapError(_ERROR_INVALID_SYSTEM_CALL);
    220       break;
    221   }
    222 }
    223 
    224 //
    225 // OS Utility Routines
    226 //
    227 function krnTrace(msg)
    228 {
    229    // Check globals to see if trace is set ON.  If so, then (maybe) log the message. 
    230    if (_Trace)
    231    {
    232       if (msg === "Idle")
    233       {
    234          // We can't log every idle clock pulse because it would lag the browser very quickly.
    235          if (_OSclock % 10 == 0)  // Check the CPU_CLOCK_INTERVAL in globals.js for an 
    236          {                        // idea of the tick rate and adjust this line accordingly.
    237             simLog(msg, "OS");          
    238          }         
    239       }
    240       else
    241       {
    242        simLog(msg, "OS");
    243       }
    244    }
    245 }
    246    
    247 function krnTrapError(msg)
    248 {
    249     simLog("OS ERROR - TRAP: " + msg);    
    250     krnShutdown();
    251     _Console.bsod(msg);
    252 }