1 using System;
  2 using System.Collections;
  3 using cmsx.machine;
  4 
  5 namespace cmsx.kernel
  6 {
  7     public ulong kernelFiberStackSize = 64u * 1024u;
  8 
  9     public delegate void SystemCallFiberDelegate(void* processParam);
 10 
 11     public class ProcessDueTimeLess : Rel<Process*>
 12     {
 13         public nothrow bool operator()(Process* leftProcess* right) const
 14         {
 15             #assert(left->state == Process.State.asleep);
 16             #assert(left->event == wakeupEvent);
 17             #assert(right->state == Process.State.asleep);
 18             #assert(right->event == wakeupEvent);
 19             long leftDueTime = cast<long>(left->eventData1);
 20             long rightDueTime = cast<long>(right->eventData1);
 21             return leftDueTime < rightDueTime;
 22         }
 23     }
 24 
 25     public class SleepingProcessQueue
 26     {
 27         static SleepingProcessQueue() : instance(new SleepingProcessQueue())
 28         {
 29         }
 30         public static SleepingProcessQueue& Instance()
 31         {
 32             return *instance;
 33         }
 34         public void AddProcess(Process* process)
 35         {
 36             sleepingProcesses.Insert(process);
 37         }
 38         public List<Process*> GetProcessesToWakeUp(long dueTime)
 39         {
 40             List<Process*> processesToWakeUp;
 41             while (!sleepingProcesses.IsEmpty())
 42             {
 43                 Process* process = *sleepingProcesses.Begin();
 44                 #assert(process->state == Process.State.asleep);
 45                 #assert(process->event == wakeupEvent);
 46                 long processDueTime = cast<long>(process->eventData1);
 47                 if (processDueTime <= dueTime)
 48                 {
 49                     sleepingProcesses.Remove(sleepingProcesses.Begin());
 50                     processesToWakeUp.Add(process);
 51                 }
 52                 else
 53                 {
 54                     break;
 55                 }
 56             }
 57             return processesToWakeUp;
 58         }
 59         private static UniquePtr<SleepingProcessQueue> instance;
 60         private Set<Process*ProcessDueTimeLess> sleepingProcesses;
 61     }
 62 
 63     public nothrow void ClockInterruptHandler(Machine& machinebyte irq)
 64     {
 65         if (Log())
 66         {
 67             LogMessage("intr""clock");
 68         }
 69         Kernel& kernel = Kernel.Instance();
 70         ProcessTable& processTable = kernel.GetProcessTable();
 71         List<Process*> processesToWakeUp = SleepingProcessQueue.Instance().GetProcessesToWakeUp(Now().Rep());
 72         for (Process* process : processesToWakeUp)
 73         {
 74             WakeUpProcess(processTableprocess);
 75         }
 76         Schedule(machineprocessTable);
 77     }
 78 
 79     public void PageFaultHandler(Machine& machinebyte irq)
 80     {
 81         if (Log())
 82         {
 83             LogMessage("intr""pagefault");
 84         }
 85         Registers& regs = machine.GetRegisters();
 86         ulong yy = regs.GetSpecial(Registers.rYY);
 87         Protection pageProtection = Protection.notPresent;
 88         Protection protection = Protection.notPresent;
 89         UnpackProtection(yypageProtectionprotection);
 90         ulong virtualAddress = machine.GetRegisters().GetSpecial(Registers.rZZ);
 91         string registers = regs.ToString();
 92         Kernel& kernel = Kernel.Instance();
 93         ProcessTable& processTable = kernel.GetProcessTable();
 94         Process* process = processTable.GetRunning();
 95         string runningProcessName = "?";
 96         string stackTrace;
 97         string error = "page fault";
 98         if (process != null)
 99         {
100             runningProcessName = ProcessName(process);
101             if ((virtualAddress >= stackSegmentBaseAddress && virtualAddress < kernelBaseAddress))
102             {
103                 Console.Error() << "stack overflow." << endl();
104                 error = "stack overflow";
105             }
106             else
107             {
108                 Console.Error() << "page fault." << endl();
109                 stackTrace = GetProcessStackTrace(machineprocessmachine.GetRegisters().Get(cmsx.machine.regFP));
110             }
111         }
112         Debugger* debugger = kernel.GetDebugger();
113         string errorlf = error + "\n";
114         debugger->WriteOutput(cast<byte*>(cast<void*>(errorlf.Chars()))errorlf.Length());
115         debugger->Run(process);
116         Panic(error + ", virtual address = " + ToHexString(virtualAddress) + ", page protection = " + GetProtectionStr(pageProtection) + ", " + GetProtectionStr(protection) + " needed (running process=" + 
117             runningProcessName + ")\n" + stackTrace + "\nRegisters:\n" + registers);
118     }
119 
120     public void SecurityViolationHandler(Machine& machinebyte irq)
121     {
122         if (Log())
123         {
124             LogMessage("intr""security");
125         }
126         ulong virtualAddress = machine.GetRegisters().GetSpecial(Registers.rZZ);
127         Kernel& kernel = Kernel.Instance();
128         ProcessTable& processTable = kernel.GetProcessTable();
129         Process* process = processTable.GetRunning();
130         string runningProcessName = "?";
131         string stackTrace;
132         Console.Error() << "security violation: virtual address = " << ToHexString(virtualAddress) << endl();
133         if (process != null)
134         {
135             runningProcessName = ProcessName(process);
136             stackTrace = GetProcessStackTrace(machineprocessmachine.GetRegisters().Get(cmsx.machine.regFP));
137         }
138         Panic("security violation, virtual address = " + ToHexString(virtualAddress) + ", processor not in kernel mode (running process=" + runningProcessName + ")\n" + stackTrace);
139     }
140 
141     public void SoftwareInterruptHandler(Machine& machinebyte irq)
142     {
143         if (Log())
144         {
145             LogMessage("intr""software");
146         }
147         Registers& regs = machine.GetRegisters();
148         ulong prevRV = regs.GetSpecial(Registers.rV);
149         ulong kernelRV = MakeVirtualTranslationRegisterValue(machine.GetKernelRootPageAddress()kernelAddressSpaceNumber);
150         regs.SetSpecial(Registers.rVkernelRV);
151         ulong trapValue = regs.GetSpecial(Registers.rX);
152         byte trapX = cast<byte>((trapValue & trapXMask) >> trapXShift);
153         byte trapY = cast<byte>((trapValue & trapYMask) >> trapYShift);
154         byte trapZ = cast<byte>((trapValue & trapZMask) >> trapZShift);
155         ulong trapAX = regs.Get(regAX);
156         ulong trapBX = regs.Get(regBX);
157         ulong trapCX = regs.Get(regCX);
158         ulong trapDX = regs.Get(regDX);
159         ulong trapEX = regs.Get(regEX);
160         ulong trapOffset = cast<ulong>(trapY) << 3u;
161         ulong systemCallTableBaseAddress = regs.GetSpecial(Registers.rT);
162         ulong systemCallHandlerPtrAddress = systemCallTableBaseAddress + trapOffset;
163         ulong systemCallHandlerAddress = machine.GetMemory().ReadULong(systemCallHandlerPtrAddressProtection.read);
164         regs.SetSpecial(Registers.rVprevRV);
165         if (systemCallHandlerAddress == 0u)
166         {
167             Panic("handler for trap " + ToString(trapY) + " is null");
168         }
169         SystemCallHandler handler = cast<SystemCallHandler>(cast<void*>(systemCallHandlerAddress));
170         Kernel& kernel = Kernel.Instance();
171         ProcessTable& processTable = kernel.GetProcessTable();
172         Process* process = processTable.GetRunning();
173         if (process == null)
174         {
175             Panic("system call called for a process that is not running");
176         }
177         if (process->fiber == null)
178         {
179             SystemCallFiberDelegate systemCallFiber = SystemCallFiber;
180             void* systemCallFiberStartAddress = cast<void*>(systemCallFiber);
181             process->fiber = OsCreateFiber(kernelFiberStackSizesystemCallFiberStartAddressprocess);
182         }
183         process->mode = Process.Mode.runningKernel;
184         process->systemCall = SystemCall(&machine&kernel&processTableprocesshandlertrapXtrapYtrapZtrapAXtrapBXtrapCXtrapDXtrapEX);
185         OsSwitchToFiber(process->fiber);
186     }
187 
188     public nothrow void IntervalInterruptHandler(Machine& machinebyte irq)
189     {
190         // todo
191     }
192 
193     public nothrow void DiskInterruptHandler(Machine& machinebyte irq)
194     {
195         if (Log())
196         {
197             LogMessage("intr""disk");
198         }
199         DiskDriver& diskDriver = GetDiskDriver();
200         diskDriver.InterruptService();
201     }
202 
203     public nothrow void KeyboardInterruptHandler(Machine& machinebyte irq)
204     {
205         if (Log())
206         {
207             LogMessage("intr""kb");
208         }
209         Kernel& kernel = Kernel.Instance();
210         ConsoleDriver* consoleDriver = kernel.GetConsoleDriver();
211         if (consoleDriver != null)
212         {
213             consoleDriver->InterruptService();
214         }
215     }
216 
217     public void KernelInterruptReturn()
218     {
219         if (Log())
220         {
221             LogMessage("intr.return""begin");
222         }
223         Machine& machine = GetMachine();
224         Kernel& kernel = Kernel.Instance();
225         ProcessTable& processTable = kernel.GetProcessTable();
226         Process* process = processTable.GetRunning();
227         if (process == null)
228         {
229             Panic("no process is running");
230         }
231         while (process->state == Process.State.zombie || process->state == Process.State.asleep || process->mode == Process.Mode.runningKernel && process->state == Process.State.running)
232         {
233             if (process->state == Process.State.zombie)
234             {
235                 if (process->fiber != null)
236                 {
237                     OsDeleteFiber(process->fiber);
238                     process->fiber = null;
239                 }
240                 Schedule(machineprocessTable);
241                 process = processTable.GetRunning();
242             }
243             else if (process->state == Process.State.asleep)
244             {
245                 Schedule(machineprocessTable);
246                 process = processTable.GetRunning();
247             }
248             else if (process->mode == Process.Mode.runningKernel && process->state == Process.State.running)
249             {
250                 if (Log())
251                 {
252                     LogMessage("intr.return"ProcessName(process) + ".runkernel");
253                 }
254                 OsSwitchToFiber(process->fiber);
255             }
256         }
257         if (process->systemCallReady && !process->systemCall.IsDebugBreak())
258         {
259             process->systemCallReady = false;
260             long result = process->systemCall.result;
261             ulong returnValue = cast<ulong>(result);
262             if (Log())
263             {
264                 LogMessage("intr.return"ProcessName(process) + ".return=" + ToString(returnValue));
265             }
266             Registers& regs = machine.GetRegisters();
267             regs.Set(regAXreturnValue);
268         }
269         if (Log())
270         {
271             LogMessage("intr.return""end");
272         }
273     }
274 }