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 }