1 using System;
2 using System.Threading;
3
4 namespace cmsx.machine
5 {
6 public const byte irqMax = 64u;
7
8 public const byte irqSoftware = 0u;
9 public const ulong SOFTWARE_INTERRUPT_BIT = cast<ulong>(1u) << irqSoftware;
10 public const byte irqClock = 1u;
11 public const ulong CLOCK_BIT = cast<ulong>(1u) << irqClock;
12 public const byte irqDisk = 2u;
13 public const ulong DISK_BIT = cast<ulong>(1u) << irqDisk;
14 public const byte irqKeyboard = 3u;
15 public const ulong KEYBOARD_BIT = cast<ulong>(1u) << irqKeyboard;
16
17 public const int irqFirstSetBegin = 0;
18 public const int irqFirstSetEnd = 4;
19
20 public const byte irqR = 32u;
21 public const ulong R_BIT = cast<ulong>(1u) << irqR;
22 public const byte irqW = 33u;
23 public const ulong W_BIT = cast<ulong>(1u) << irqW;
24 public const byte irqX = 34u;
25 public const ulong X_BIT = cast<ulong>(1u) << irqX;
26 public const byte irqN = 35u;
27 public const ulong N_BIT = cast<ulong>(1u) << irqN;
28 public const byte irqK = 36u;
29 public const ulong K_BIT = cast<ulong>(1u) << irqK;
30 public const byte irqCOW = 37u;
31 public const ulong COW_BIT = cast<ulong>(1u) << irqCOW;
32 public const byte irqS = 38u;
33 public const ulong S_BIT = cast<ulong>(1u) << irqS;
34 public const byte irqP = 39u;
35 public const ulong P_BIT = cast<ulong>(1u) << irqP;
36
37 public const ulong MACHINE_INTERRUPT_BITS = R_BIT | W_BIT | X_BIT | N_BIT | K_BIT | COW_BIT | S_BIT | P_BIT;
38
39 public const int irqSecondSetBegin = 32;
40 public const int irqSecondSetEnd = 40;
41
42 public const ulong ALL_INTERRUPT_BITS = 0xFFFFFFFFFFFFFFFFu;
43
44 public delegate void InterruptHandler(Machine& machine, byte irq);
45
46 public inline nothrow ulong MakeInterruptHandlerPtrAddress(byte irq)
47 {
48 return interruptVectorBaseAddress + cast<ulong>(8u) * irq;
49 }
50
51 public nothrow void SetProcessorToKernelMode(Registers& regs)
52 {
53 LockGuard<Mutex> lock(regs.GetInterruptMutex());
54 regs.SetSpecial(Registers.rK, regs.GetSpecial(Registers.rK) & ~N_BIT);
55 }
56
57 public nothrow void SetProcessorToUserMode(Registers& regs)
58 {
59 LockGuard<Mutex> lock(regs.GetInterruptMutex());
60 regs.SetSpecial(Registers.rK, regs.GetSpecial(Registers.rK) | MACHINE_INTERRUPT_BITS);
61 }
62
63 public nothrow bool IsProcessorInKernelMode(Registers& regs)
64 {
65 LockGuard<Mutex> lock(regs.GetInterruptMutex());
66 return (regs.GetSpecial(Registers.rK) & N_BIT) == 0u;
67 }
68
69 public nothrow void DisableAllInterrupts(Registers& regs)
70 {
71 LockGuard<Mutex> lock(regs.GetInterruptMutex());
72 regs.SetSpecial(Registers.rK, 0u);
73 }
74
75 public nothrow void EnableAllInterrupts(Registers& regs)
76 {
77 LockGuard<Mutex> lock(regs.GetInterruptMutex());
78 regs.SetSpecial(Registers.rK, ALL_INTERRUPT_BITS);
79 }
80
81 public nothrow void SetSecurityViolation(Registers& regs, ulong virtualAddress)
82 {
83 LockGuard<Mutex> lock(regs.GetInterruptMutex());
84 regs.SetSpecial(Registers.rZZ, virtualAddress);
85 regs.SetSpecial(Registers.rK, regs.GetSpecial(Registers.rK) | S_BIT);
86 regs.SetInterrupt(S_BIT);
87 }
88
89 private bool issuePageFault = true;
90
91 public nothrow bool IssuePageFault()
92 {
93 return issuePageFault;
94 }
95
96 public nothrow void InvokePageFault(Registers& regs, ulong virtualAddress, Protection pageProtection, Protection access)
97 {
98 if (!IssuePageFault())
99 {
100 Console.Error() << regs.GetPC() << endl();
101 return;
102 }
103 regs.SetSpecial(Registers.rYY, PackProtection(pageProtection, access));
104 regs.SetSpecial(Registers.rZZ, virtualAddress);
105 LockGuard<Mutex> lock(regs.GetInterruptMutex());
106 ulong rq = regs.GetSpecial(Registers.rQ);
107 if (pageProtection == Protection.copyOnWrite)
108 {
109 rq = rq | COW_BIT;
110 }
111 else
112 {
113 if ((access & Protection.execute) != 0u)
114 {
115 rq = rq | X_BIT;
116 }
117 else if ((access & Protection.write) != 0u)
118 {
119 rq = rq | W_BIT;
120 }
121 else if ((access & Protection.read) != 0u)
122 {
123 rq = rq | R_BIT;
124 }
125 else
126 {
127 SetSecurityViolation(regs, virtualAddress);
128 return;
129 }
130 }
131 regs.SetSpecial(Registers.rQ, rq);
132 }
133
134 public nothrow string GetInterruptName(int irq)
135 {
136 switch (irq)
137 {
138 case irqSoftware: return "software";
139 case irqClock: return "clock";
140 case irqKeyboard: return "keyboard";
141 case irqR: return "read page fault";
142 case irqW: return "write page fault";
143 case irqX: return "execute page fault";
144 case irqCOW: return "copy-on-write page fault";
145 case irqN: return "kernel address page fault";
146 case irqK: return "kernel instruction";
147 case irqS: return "security violation";
148 case irqP: return "negative address";
149 }
150 return "unknown";
151 }
152 }